{"model_name":"gpt-5.3-codex-xhigh","codes":{"1":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int BOARD = 10000;\nenum Side { LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3 };\n\nstruct Company {\n    int x, y, r;\n};\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n};\n\nstruct State {\n    vector<Rect> rects;\n    vector<long long> area;\n    vector<double> p;\n    double total = 0.0;\n};\n\nint n;\nvector<Company> C;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) {\n        x = seed ? seed : 88172645463325252ull;\n    }\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int l, int r) {\n        if (l == r) return l;\n        uint64_t span = (uint64_t)((long long)r - l + 1);\n        return l + (int)(nextU64() % span);\n    }\n};\n\ninline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\ninline long long rectArea(const Rect& rc) {\n    return 1LL * (rc.r - rc.l) * (rc.t - rc.b);\n}\n\ninline double satisfaction(long long s, long long target) {\n    if (s <= 0) return 0.0;\n    double ratio = (s < target) ? (double)s / (double)target : (double)target / (double)s;\n    double d = 1.0 - ratio;\n    return 1.0 - d * d;\n}\n\ninline int getCoord(const Rect& rc, int side) {\n    if (side == LEFT) return rc.l;\n    if (side == RIGHT) return rc.r;\n    if (side == BOTTOM) return rc.b;\n    return rc.t;\n}\n\ninline void setCoord(Rect& rc, int side, int v) {\n    if (side == LEFT) rc.l = v;\n    else if (side == RIGHT) rc.r = v;\n    else if (side == BOTTOM) rc.b = v;\n    else rc.t = v;\n}\n\ninline long long areaWithSide(const Rect& rc, int side, int v) {\n    if (side == LEFT) return 1LL * (rc.r - v) * (rc.t - rc.b);\n    if (side == RIGHT) return 1LL * (v - rc.l) * (rc.t - rc.b);\n    if (side == BOTTOM) return 1LL * (rc.r - rc.l) * (rc.t - v);\n    return 1LL * (rc.r - rc.l) * (v - rc.b);\n}\n\npair<int, int> sideRange(const State& st, int i, int side) {\n    const Rect& a = st.rects[i];\n\n    if (side == LEFT) {\n        int L = 0;\n        int U = min(C[i].x, a.r - 1);\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.l < a.r) {\n                L = max(L, b.r);\n            }\n        }\n        return {L, U};\n    }\n\n    if (side == RIGHT) {\n        int L = max(C[i].x + 1, a.l + 1);\n        int U = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.r > a.l) {\n                U = min(U, b.l);\n            }\n        }\n        return {L, U};\n    }\n\n    if (side == BOTTOM) {\n        int L = 0;\n        int U = min(C[i].y, a.t - 1);\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && b.b < a.t) {\n                L = max(L, b.t);\n            }\n        }\n        return {L, U};\n    }\n\n    // TOP\n    int L = max(C[i].y + 1, a.b + 1);\n    int U = BOARD;\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (overlap1D(a.l, a.r, b.l, b.r) && b.t > a.b) {\n            U = min(U, b.b);\n        }\n    }\n    return {L, U};\n}\n\npair<int, int> shiftRangeX(const State& st, int i) {\n    const Rect& a = st.rects[i];\n    int LB = -a.l;\n    int UB = BOARD - a.r;\n\n    // point containment\n    LB = max(LB, C[i].x + 1 - a.r);\n    UB = min(UB, C[i].x - a.l);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.b, a.t, b.b, b.t)) continue;\n        if (b.r <= a.l) {\n            LB = max(LB, b.r - a.l);\n        } else if (b.l >= a.r) {\n            UB = min(UB, b.l - a.r);\n        } else {\n            // Should not happen in valid state\n            return {1, 0};\n        }\n    }\n    return {LB, UB};\n}\n\npair<int, int> shiftRangeY(const State& st, int i) {\n    const Rect& a = st.rects[i];\n    int LB = -a.b;\n    int UB = BOARD - a.t;\n\n    // point containment\n    LB = max(LB, C[i].y + 1 - a.t);\n    UB = min(UB, C[i].y - a.b);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.l, a.r, b.l, b.r)) continue;\n        if (b.t <= a.b) {\n            LB = max(LB, b.t - a.b);\n        } else if (b.b >= a.t) {\n            UB = min(UB, b.b - a.t);\n        } else {\n            // Should not happen in valid state\n            return {1, 0};\n        }\n    }\n    return {LB, UB};\n}\n\nint bestCoordForSide(const State& st, int i, int side, int L, int U) {\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n\n    int cands[20];\n    int m = 0;\n\n    auto pushCand = [&](int v) {\n        if (v < L || v > U) return;\n        for (int k = 0; k < m; ++k) if (cands[k] == v) return;\n        cands[m++] = v;\n    };\n\n    pushCand(cur);\n    pushCand(L);\n    pushCand(U);\n\n    long long target = C[i].r;\n\n    if (side == LEFT || side == RIGHT) {\n        int h = a.t - a.b;\n        if (h > 0) {\n            double wantW = (double)target / (double)h;\n            int wf = (int)floor(wantW);\n            int wc = (int)ceil(wantW);\n            int arr[4] = {wf - 1, wf, wc, wc + 1};\n            for (int ww : arr) {\n                if (ww < 1) continue;\n                int v = (side == LEFT) ? (a.r - ww) : (a.l + ww);\n                pushCand(v);\n            }\n        }\n    } else {\n        int w = a.r - a.l;\n        if (w > 0) {\n            double wantH = (double)target / (double)w;\n            int hf = (int)floor(wantH);\n            int hc = (int)ceil(wantH);\n            int arr[4] = {hf - 1, hf, hc, hc + 1};\n            for (int hh : arr) {\n                if (hh < 1) continue;\n                int v = (side == BOTTOM) ? (a.t - hh) : (a.b + hh);\n                pushCand(v);\n            }\n        }\n    }\n\n    if (m == 0) return min(max(cur, L), U);\n\n    int best = cands[0];\n    double bestP = -1e100;\n\n    for (int k = 0; k < m; ++k) {\n        int v = cands[k];\n        long long ar = areaWithSide(a, side, v);\n        double p = satisfaction(ar, C[i].r);\n        if (p > bestP + 1e-15 || (fabs(p - bestP) <= 1e-15 && abs(v - cur) < abs(best - cur))) {\n            bestP = p;\n            best = v;\n        }\n    }\n    return best;\n}\n\nState makeState(const vector<Rect>& rects) {\n    State st;\n    st.rects = rects;\n    st.area.resize(n);\n    st.p.resize(n);\n    st.total = 0.0;\n    for (int i = 0; i < n; ++i) {\n        st.area[i] = rectArea(st.rects[i]);\n        st.p[i] = satisfaction(st.area[i], C[i].r);\n        st.total += st.p[i];\n    }\n    return st;\n}\n\nvoid shuffleVec(vector<int>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.nextInt(0, i);\n        swap(v[i], v[j]);\n    }\n}\n\nvoid greedyOptimize(State& st, RNG& rng, int maxPass) {\n    vector<int> ord(n);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        shuffleVec(ord, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < n; ++idx) {\n            int i = ord[idx];\n            double oldP = st.p[i];\n\n            int bestSide = -1;\n            int bestV = 0;\n            double bestDelta = 1e-12;\n            double bestBal = -1e100;\n\n            for (int side = 0; side < 4; ++side) {\n                auto [L, U] = sideRange(st, i, side);\n                if (L > U) continue;\n\n                int cur = getCoord(st.rects[i], side);\n                int v = bestCoordForSide(st, i, side, L, U);\n                if (v == cur) continue;\n\n                Rect tmp = st.rects[i];\n                setCoord(tmp, side, v);\n                long long ar = rectArea(tmp);\n                double newP = satisfaction(ar, C[i].r);\n                double delta = newP - oldP;\n                if (delta <= 1e-12) continue;\n\n                double bal = -fabs(log((double)(tmp.r - tmp.l) / (double)(tmp.t - tmp.b)));\n                if (delta > bestDelta + 1e-12 || (fabs(delta - bestDelta) <= 1e-12 && bal > bestBal)) {\n                    bestDelta = delta;\n                    bestBal = bal;\n                    bestSide = side;\n                    bestV = v;\n                }\n            }\n\n            if (bestSide != -1) {\n                st.total -= st.p[i];\n                setCoord(st.rects[i], bestSide, bestV);\n                st.area[i] = rectArea(st.rects[i]);\n                st.p[i] = satisfaction(st.area[i], C[i].r);\n                st.total += st.p[i];\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nbool validateRects(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = rects[i];\n        if (!(0 <= a.l && a.l < a.r && a.r <= BOARD && 0 <= a.b && a.b < a.t && a.t <= BOARD)) return false;\n        if (!(a.l <= C[i].x && C[i].x + 1 <= a.r && a.b <= C[i].y && C[i].y + 1 <= a.t)) return false;\n    }\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect& a = rects[i];\n            const Rect& b = rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && overlap1D(a.b, a.t, b.b, b.t)) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\nstruct SplitCand {\n    int ori; // 0: vertical, 1: horizontal\n    int k;\n    int t;\n    double cost;\n};\n\nint buildCallCount = 0;\nconstexpr int BUILD_CALL_LIMIT = 80000;\n\nbool buildPartitionRec(const vector<int>& ids, int L, int B, int R, int T, vector<Rect>& out, RNG& rng) {\n    if (++buildCallCount > BUILD_CALL_LIMIT) return false;\n\n    int m = (int)ids.size();\n    if (m == 0) return true;\n    if (L >= R || B >= T) return false;\n    if (1LL * (R - L) * (T - B) < m) return false;\n\n    if (m == 1) {\n        int id = ids[0];\n        if (!(L <= C[id].x && C[id].x + 1 <= R && B <= C[id].y && C[id].y + 1 <= T)) return false;\n        out[id] = {L, B, R, T};\n        return true;\n    }\n\n    int W = R - L;\n    int H = T - B;\n    if (W <= 0 || H <= 0) return false;\n\n    vector<int> ox = ids, oy = ids;\n    sort(ox.begin(), ox.end(), [](int a, int b) {\n        if (C[a].x != C[b].x) return C[a].x < C[b].x;\n        return C[a].y < C[b].y;\n    });\n    sort(oy.begin(), oy.end(), [](int a, int b) {\n        if (C[a].y != C[b].y) return C[a].y < C[b].y;\n        return C[a].x < C[b].x;\n    });\n\n    vector<long long> px(m + 1, 0), py(m + 1, 0);\n    for (int i = 0; i < m; ++i) {\n        px[i + 1] = px[i] + C[ox[i]].r;\n        py[i + 1] = py[i] + C[oy[i]].r;\n    }\n    long long totalR = px[m];\n\n    vector<SplitCand> cands;\n    cands.reserve(2 * (m - 1));\n\n    // Vertical split\n    if (W >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int xl = C[ox[k - 1]].x;\n            int xr = C[ox[k]].x;\n            int low = max(L + 1, xl + 1);\n            int high = min(R - 1, xr);\n            if (low > high) continue;\n\n            long long leftR = px[k];\n            long long rightR = totalR - leftR;\n\n            double target = L + (double)leftR / (double)H;\n            int t = (int)llround(target);\n            if (t < low) t = low;\n            if (t > high) t = high;\n\n            long long leftArea = 1LL * (t - L) * H;\n            long long rightArea = 1LL * (R - t) * H;\n\n            double cost = fabs((double)(leftArea - leftR)) + fabs((double)(rightArea - rightR));\n            cost += 0.01 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({0, k, t, cost});\n        }\n    }\n\n    // Horizontal split\n    if (H >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int yb = C[oy[k - 1]].y;\n            int yt = C[oy[k]].y;\n            int low = max(B + 1, yb + 1);\n            int high = min(T - 1, yt);\n            if (low > high) continue;\n\n            long long botR = py[k];\n            long long topR = totalR - botR;\n\n            double target = B + (double)botR / (double)W;\n            int t = (int)llround(target);\n            if (t < low) t = low;\n            if (t > high) t = high;\n\n            long long botArea = 1LL * (t - B) * W;\n            long long topArea = 1LL * (T - t) * W;\n\n            double cost = fabs((double)(botArea - botR)) + fabs((double)(topArea - topR));\n            cost += 0.01 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({1, k, t, cost});\n        }\n    }\n\n    if (cands.empty()) return false;\n\n    sort(cands.begin(), cands.end(), [](const SplitCand& a, const SplitCand& b) {\n        return a.cost < b.cost;\n    });\n\n    int limit = min((int)cands.size(), 14);\n    // small randomization among top candidates\n    for (int i = 0; i < limit; ++i) {\n        int rem = min(3, limit - i);\n        int j = i + rng.nextInt(0, rem - 1);\n        swap(cands[i], cands[j]);\n    }\n\n    for (int idx = 0; idx < limit; ++idx) {\n        const SplitCand& c = cands[idx];\n\n        if (c.ori == 0) {\n            // vertical\n            long long areaL = 1LL * (c.t - L) * (T - B);\n            long long areaR = 1LL * (R - c.t) * (T - B);\n            if (areaL < c.k || areaR < (m - c.k)) continue;\n\n            vector<int> leftIds(ox.begin(), ox.begin() + c.k);\n            vector<int> rightIds(ox.begin() + c.k, ox.end());\n\n            if (buildPartitionRec(leftIds, L, B, c.t, T, out, rng) &&\n                buildPartitionRec(rightIds, c.t, B, R, T, out, rng)) {\n                return true;\n            }\n        } else {\n            // horizontal\n            long long areaB = 1LL * (R - L) * (c.t - B);\n            long long areaT = 1LL * (R - L) * (T - c.t);\n            if (areaB < c.k || areaT < (m - c.k)) continue;\n\n            vector<int> bottomIds(oy.begin(), oy.begin() + c.k);\n            vector<int> topIds(oy.begin() + c.k, oy.end());\n\n            if (buildPartitionRec(bottomIds, L, B, R, c.t, out, rng) &&\n                buildPartitionRec(topIds, L, c.t, R, T, out, rng)) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nint pickRect(const State& st, RNG& rng) {\n    int i = rng.nextInt(0, n - 1);\n    if (rng.nextDouble() < 0.6) {\n        int j = rng.nextInt(0, n - 1);\n        if (st.p[j] < st.p[i]) i = j;\n        int k = rng.nextInt(0, n - 1);\n        if (st.p[k] < st.p[i]) i = k;\n    }\n    return i;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    C.resize(n);\n\n    uint64_t seed = 1469598103934665603ull ^ (uint64_t)n * 1000003ull;\n    for (int i = 0; i < n; ++i) {\n        cin >> C[i].x >> C[i].y >> C[i].r;\n        seed ^= (uint64_t)(C[i].x + 1) * 1000003ull;\n        seed ^= (uint64_t)(C[i].y + 1) * 1009837ull;\n        seed ^= (uint64_t)(C[i].r + 3) * 10000019ull;\n        seed *= 1099511628211ull;\n    }\n    RNG rng(seed);\n\n    auto start = chrono::steady_clock::now();\n    auto nowSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    // Init A: 1x1\n    vector<Rect> initA(n);\n    for (int i = 0; i < n; ++i) {\n        initA[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n    }\n    State stA = makeState(initA);\n    greedyOptimize(stA, rng, 60);\n\n    State bestInit = stA;\n\n    // Init B: recursive partition (guillotine-like)\n    vector<Rect> initB(n);\n    bool okB = false;\n    for (int attempt = 0; attempt < 4 && !okB; ++attempt) {\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        buildCallCount = 0;\n        if (buildPartitionRec(ids, 0, 0, BOARD, BOARD, initB, rng) && validateRects(initB)) {\n            okB = true;\n        }\n    }\n    if (okB) {\n        State stB = makeState(initB);\n        greedyOptimize(stB, rng, 60);\n        if (stB.total > bestInit.total) bestInit = stB;\n    }\n\n    State cur = bestInit;\n    State best = bestInit;\n\n    const double TL = 4.85;\n    const double T0 = 0.01;\n    const double T1 = 1e-5;\n\n    double progress = 0.0;\n    double temp = T0;\n    double nextRefine = 0.6;\n\n    for (long long iter = 0;; ++iter) {\n        if ((iter & 255LL) == 0) {\n            double t = nowSec();\n            if (t >= TL) break;\n            progress = t / TL;\n            temp = T0 * pow(T1 / T0, progress);\n\n            if (t >= nextRefine) {\n                greedyOptimize(cur, rng, 3);\n                if (cur.total > best.total) best = cur;\n                nextRefine += 0.6;\n            }\n        }\n\n        int i = pickRect(cur, rng);\n        double op = rng.nextDouble();\n\n        if (op < 0.85) {\n            // side move\n            int side = rng.nextInt(0, 3);\n            auto [L, U] = sideRange(cur, i, side);\n            if (L > U) continue;\n\n            int curV = getCoord(cur.rects[i], side);\n\n            int v = curV;\n            double sel = rng.nextDouble();\n            if (sel < 0.55) {\n                v = bestCoordForSide(cur, i, side, L, U);\n            } else if (sel < 0.85) {\n                int span = U - L;\n                int step = max(1, (int)(span * (1.0 - progress) * 0.35));\n                int d = rng.nextInt(-step, step);\n                v = curV + d;\n                if (v < L) v = L;\n                if (v > U) v = U;\n            } else {\n                v = rng.nextInt(L, U);\n            }\n\n            if (v == curV) continue;\n\n            long long newA = areaWithSide(cur.rects[i], side, v);\n            double newP = satisfaction(newA, C[i].r);\n            double delta = newP - cur.p[i];\n\n            if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                cur.total += delta;\n                cur.p[i] = newP;\n                cur.area[i] = newA;\n                setCoord(cur.rects[i], side, v);\n\n                if (cur.total > best.total) best = cur;\n            }\n\n        } else if (op < 0.925) {\n            // shift X\n            auto [LB, UB] = shiftRangeX(cur, i);\n            if (LB > UB) continue;\n\n            int dx = 0;\n            if (LB == UB) {\n                dx = LB;\n            } else {\n                double sel = rng.nextDouble();\n                if (sel < 0.5) dx = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dx = rng.nextInt(LB, UB);\n            }\n\n            if (dx == 0) continue;\n            cur.rects[i].l += dx;\n            cur.rects[i].r += dx;\n\n        } else {\n            // shift Y\n            auto [LB, UB] = shiftRangeY(cur, i);\n            if (LB > UB) continue;\n\n            int dy = 0;\n            if (LB == UB) {\n                dy = LB;\n            } else {\n                double sel = rng.nextDouble();\n                if (sel < 0.5) dy = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dy = rng.nextInt(LB, UB);\n            }\n\n            if (dy == 0) continue;\n            cur.rects[i].b += dy;\n            cur.rects[i].t += dy;\n        }\n    }\n\n    greedyOptimize(best, rng, 80);\n    best = makeState(best.rects);\n\n    if (!validateRects(best.rects)) {\n        if (validateRects(bestInit.rects)) {\n            best = bestInit;\n        } else {\n            vector<Rect> safe(n);\n            for (int i = 0; i < n; ++i) {\n                safe[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n            }\n            best = makeState(safe);\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& rc = best.rects[i];\n        cout << rc.l << ' ' << rc.b << ' ' << rc.r << ' ' << rc.t << '\\n';\n    }\n\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 N = H * W;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + int(next_u64() % uint64_t(r - l + 1));\n    }\n};\n\nstruct Params {\n    double wFuture;\n    double wValue;\n    double wMob;\n    double wNoise;\n    double epsRandom; // epsilon random choice when branching\n};\n\nstruct Result {\n    long long score = LLONG_MIN;\n    string path;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    if (!(cin >> si >> sj)) return 0;\n\n    vector<int> tile(N), val(N);\n    int maxTile = -1;\n\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x;\n            cin >> x;\n            tile[i * W + j] = x;\n            maxTile = max(maxTile, x);\n        }\n    }\n    int M = maxTile + 1;\n\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            cin >> val[i * W + j];\n        }\n    }\n\n    vector<int> tileBest(M, 0);\n    for (int v = 0; v < N; v++) {\n        tileBest[tile[v]] = max(tileBest[tile[v]], val[v]);\n    }\n\n    // Directions: U D L R\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    const char dch[4] = {'U', 'D', 'L', 'R'};\n\n    auto inside = [&](int r, int c) {\n        return (0 <= r && r < H && 0 <= c && c < W);\n    };\n\n    // nextAll: all in-bounds neighbors by UDLR (for replay)\n    int nextAll[N][4];\n    for (int v = 0; v < N; v++) for (int d = 0; d < 4; d++) nextAll[v][d] = -1;\n\n    // adjacency excluding same-tile edges\n    int deg[N];\n    int adj[N][4];\n    char adjCh[N][4];\n    memset(deg, 0, sizeof(deg));\n\n    for (int r = 0; r < H; r++) {\n        for (int c = 0; c < W; c++) {\n            int v = r * W + c;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + di[d], nc = c + dj[d];\n                if (!inside(nr, nc)) continue;\n                int to = nr * W + nc;\n                nextAll[v][d] = to;\n\n                if (tile[to] != tile[v]) {\n                    int k = deg[v]++;\n                    adj[v][k] = to;\n                    adjCh[v][k] = dch[d];\n                }\n            }\n        }\n    }\n\n    auto charToDir = [&](char c) -> int {\n        switch (c) {\n            case 'U': return 0;\n            case 'D': return 1;\n            case 'L': return 2;\n            case 'R': return 3;\n            default: return -1;\n        }\n    };\n\n    const int start = si * W + sj;\n\n    vector<int> tileMark(M, 0);\n    int tileToken = 1;\n\n    static int cellSeen[N];\n    memset(cellSeen, 0, sizeof(cellSeen));\n    int cellSeenToken = 1;\n\n    vector<int> tileSeen(M, 0);\n    int tileSeenToken = 1;\n\n    int q[N];\n\n    using Clock = chrono::steady_clock;\n    auto deadline = Clock::now() + chrono::milliseconds(1880);\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    seed ^= uint64_t(start) * 11995408973635179863ULL;\n    XorShift64 rng(seed);\n\n    auto analyzeCandidate = [&](int cand, int token, int &mob, int &future) {\n        // Assume we move into cand => cand's tile becomes blocked for future.\n        int extraTile = tile[cand];\n        mob = 0;\n        future = 0;\n\n        int mark = ++cellSeenToken;\n        if (cellSeenToken == INT_MAX) {\n            memset(cellSeen, 0, sizeof(cellSeen));\n            cellSeenToken = 1;\n            mark = 1;\n        }\n\n        // Components among neighbors of cand in remaining graph.\n        for (int k = 0; k < deg[cand]; k++) {\n            int nb = adj[cand][k];\n            int tnb = tile[nb];\n            if (tileMark[tnb] == token || tnb == extraTile) continue;\n            mob++;\n\n            if (cellSeen[nb] == mark) continue;\n\n            int head = 0, tail = 0;\n            q[tail++] = nb;\n            cellSeen[nb] = mark;\n\n            int compScore = 0;\n            int ttok = ++tileSeenToken;\n            if (tileSeenToken == INT_MAX) {\n                fill(tileSeen.begin(), tileSeen.end(), 0);\n                tileSeenToken = 1;\n                ttok = 1;\n            }\n\n            while (head < tail) {\n                int v = q[head++];\n                int tv = tile[v];\n                if (tileSeen[tv] != ttok) {\n                    tileSeen[tv] = ttok;\n                    compScore += tileBest[tv]; // optimistic per tile\n                }\n\n                for (int kk = 0; kk < deg[v]; kk++) {\n                    int to = adj[v][kk];\n                    int tto = tile[to];\n                    if (tileMark[tto] == token || tto == extraTile) continue;\n                    if (cellSeen[to] == mark) continue;\n                    cellSeen[to] = mark;\n                    q[tail++] = to;\n                }\n            }\n\n            if (compScore > future) future = compScore;\n        }\n    };\n\n    auto simulate = [&](const Params &prm, const string *basePath, int cut) -> Result {\n        Result res;\n\n        ++tileToken;\n        if (tileToken == INT_MAX) {\n            fill(tileMark.begin(), tileMark.end(), 0);\n            tileToken = 1;\n        }\n        int token = tileToken;\n\n        string path;\n        path.reserve(N);\n\n        long long score = 0;\n        int cur = start;\n        tileMark[tile[cur]] = token;\n        score += val[cur];\n\n        // Replay prefix if requested\n        if (basePath && cut > 0) {\n            int L = min<int>(cut, basePath->size());\n            for (int i = 0; i < L; i++) {\n                int d = charToDir((*basePath)[i]);\n                if (d < 0) break;\n                int to = nextAll[cur][d];\n                if (to < 0) break;\n                int tt = tile[to];\n                if (tileMark[tt] == token) break;\n                path.push_back((*basePath)[i]);\n                cur = to;\n                tileMark[tt] = token;\n                score += val[cur];\n            }\n        }\n\n        int stepCounter = 0;\n        while (true) {\n            int cands[4];\n            char cchars[4];\n            int nc = 0;\n\n            for (int k = 0; k < deg[cur]; k++) {\n                int to = adj[cur][k];\n                if (tileMark[tile[to]] != token) {\n                    cands[nc] = to;\n                    cchars[nc] = adjCh[cur][k];\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int pick = 0;\n            if (nc >= 2) {\n                if (rng.next_double() < prm.epsRandom) {\n                    pick = rng.next_int(0, nc - 1);\n                } else {\n                    double bestEv = -1e100;\n                    for (int i = 0; i < nc; i++) {\n                        int cand = cands[i];\n                        int mob, future;\n                        analyzeCandidate(cand, token, mob, future);\n\n                        double ev =\n                            prm.wFuture * double(future) +\n                            prm.wValue  * double(val[cand]) -\n                            prm.wMob    * double(mob) +\n                            prm.wNoise  * rng.next_double();\n\n                        if (ev > bestEv + 1e-12) {\n                            bestEv = ev;\n                            pick = i;\n                        } else if (fabs(ev - bestEv) <= 1e-12) {\n                            if (rng.next_u64() & 1ULL) pick = i;\n                        }\n                    }\n                }\n            }\n\n            int nxt = cands[pick];\n            path.push_back(cchars[pick]);\n            cur = nxt;\n            tileMark[tile[cur]] = token;\n            score += val[cur];\n\n            stepCounter++;\n            if ((stepCounter & 63) == 0) {\n                if (Clock::now() >= deadline) break;\n            }\n        }\n\n        res.score = score;\n        res.path = std::move(path);\n        return res;\n    };\n\n    Result best;\n\n    // Initial deterministic-ish run\n    Params base{1.0, 1.0, 12.0, 0.0, 0.0};\n    best = simulate(base, nullptr, 0);\n\n    // Multi-start until timeout\n    while (Clock::now() < deadline) {\n        Params prm;\n        prm.wFuture   = 0.60 + 0.90 * rng.next_double();\n        prm.wValue    = 0.40 + 1.60 * rng.next_double();\n        prm.wMob      = 0.00 + 40.00 * rng.next_double();\n        prm.wNoise    = 0.00 + 350.00 * rng.next_double();\n        prm.epsRandom = 0.00 + 0.15 * rng.next_double();\n\n        const string *bp = nullptr;\n        int cut = 0;\n\n        // Partial replay from current best (light local search)\n        if (!best.path.empty() && rng.next_double() < 0.35) {\n            bp = &best.path;\n            int L = (int)best.path.size();\n            if (L >= 1) {\n                if (rng.next_double() < 0.5) {\n                    cut = rng.next_int(0, L - 1);\n                } else {\n                    int lo = max(0, L - 700);\n                    cut = rng.next_int(lo, L - 1);\n                }\n            }\n        }\n\n        Result cur = simulate(prm, bp, cut);\n        if (cur.score > best.score ||\n            (cur.score == best.score && cur.path.size() > best.path.size())) {\n            best = std::move(cur);\n        }\n    }\n\n    cout << best.path << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr int Q = 1000;\n\n    static constexpr double COST_MIN = 1000.0;\n    static constexpr double COST_MAX = 9000.0;\n\n    // Confidence prior for local edge residual.\n    static constexpr double PRIOR_CNT = 1.5;\n    static constexpr double DELTA_CLIP = 3500.0;\n\n    static constexpr int RANDOM_PHASE = 60; // early exploration turns\n\n    struct EdgeRef {\n        bool horiz; // true: horizontal h[i][j], false: vertical v[i][j]\n        int i, j;\n    };\n\n    using HCost = array<array<double, N - 1>, N>; // h[i][j] : (i,j)<->(i,j+1)\n    using VCost = array<array<double, N>, N - 1>; // v[i][j] : (i,j)<->(i+1,j)\n\n    // Row / column base estimates\n    array<double, N> rowBase{}, colBase{};\n\n    // Local residual estimates\n    array<array<double, N - 1>, N> deltaH{};\n    array<array<double, N>, N - 1> deltaV{};\n\n    // Traversal counts (confidence)\n    array<array<int, N - 1>, N> cntH{};\n    array<array<int, N>, N - 1> cntV{};\n\n    mt19937 rng;\n    uniform_real_distribution<double> urand;\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 int id(int i, int j) { return i * N + j; }\n\n    double edgeCostH(int i, int j) const {\n        double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n        double c = rowBase[i] + sh * deltaH[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    double edgeCostV(int i, int j) const {\n        double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n        double c = colBase[j] + sh * deltaV[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    void buildBaseCosts(HCost& h, VCost& v) const {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                h[i][j] = edgeCostH(i, j);\n            }\n        }\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                v[i][j] = edgeCostV(i, j);\n            }\n        }\n    }\n\n    string directManhattan(int si, int sj, int ti, int tj) const {\n        string p;\n        if (ti > si) p.append(ti - si, 'D');\n        else p.append(si - ti, 'U');\n        if (tj > sj) p.append(tj - sj, 'R');\n        else p.append(sj - tj, 'L');\n        return p;\n    }\n\n    string dijkstraPath(int si, int sj, int ti, int tj, const HCost& h, const VCost& v) const {\n        constexpr double INF = 1e100;\n        array<double, N * N> dist;\n        array<int, N * N> prv;\n        array<char, N * N> pmv;\n        dist.fill(INF);\n        prv.fill(-1);\n        pmv.fill(0);\n\n        int S = id(si, sj), T = id(ti, tj);\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[S] = 0.0;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == T) break;\n            int i = u / N, j = u % N;\n\n            if (i > 0) {\n                int to = id(i - 1, j);\n                double nd = d + v[i - 1][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'U';\n                    pq.push({nd, to});\n                }\n            }\n            if (i + 1 < N) {\n                int to = id(i + 1, j);\n                double nd = d + v[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'D';\n                    pq.push({nd, to});\n                }\n            }\n            if (j > 0) {\n                int to = id(i, j - 1);\n                double nd = d + h[i][j - 1];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'L';\n                    pq.push({nd, to});\n                }\n            }\n            if (j + 1 < N) {\n                int to = id(i, j + 1);\n                double nd = d + h[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'R';\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        if (prv[T] == -1) return directManhattan(si, sj, ti, tj);\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmv[cur]);\n            cur = prv[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Early-phase monotone exploration path (biased by low estimated cost and low visit count).\n    string biasedMonotonePath(int si, int sj, int ti, int tj, const HCost& h, const VCost& v) {\n        int i = si, j = sj;\n        string path;\n        path.reserve(abs(ti - si) + abs(tj - sj));\n\n        while (i != ti || j != tj) {\n            bool canV = (i != ti);\n            bool canH = (j != tj);\n\n            if (canV && canH) {\n                bool down = (ti > i);\n                bool right = (tj > j);\n\n                double cv;\n                int nv;\n                if (down) {\n                    cv = v[i][j];\n                    nv = cntV[i][j];\n                } else {\n                    cv = v[i - 1][j];\n                    nv = cntV[i - 1][j];\n                }\n\n                double ch;\n                int nh;\n                if (right) {\n                    ch = h[i][j];\n                    nh = cntH[i][j];\n                } else {\n                    ch = h[i][j - 1];\n                    nh = cntH[i][j - 1];\n                }\n\n                double sv = (1.0 / cv) * (1.0 + 1.0 / (nv + 1.0));\n                double sh = (1.0 / ch) * (1.0 + 1.0 / (nh + 1.0));\n                double r = urand(rng) * (sv + sh);\n\n                if (r < sv) {\n                    if (down) {\n                        path.push_back('D');\n                        ++i;\n                    } else {\n                        path.push_back('U');\n                        --i;\n                    }\n                } else {\n                    if (right) {\n                        path.push_back('R');\n                        ++j;\n                    } else {\n                        path.push_back('L');\n                        --j;\n                    }\n                }\n            } else if (canV) {\n                if (ti > i) {\n                    path.push_back('D');\n                    ++i;\n                } else {\n                    path.push_back('U');\n                    --i;\n                }\n            } else {\n                if (tj > j) {\n                    path.push_back('R');\n                    ++j;\n                } else {\n                    path.push_back('L');\n                    --j;\n                }\n            }\n        }\n\n        return path;\n    }\n\n    void pathToEdges(\n        int si, int sj, const string& path,\n        vector<EdgeRef>& edges,\n        array<int, N>& rowCnt, array<int, N>& colCnt\n    ) const {\n        int i = si, j = sj;\n        edges.clear();\n        edges.reserve(path.size());\n        rowCnt.fill(0);\n        colCnt.fill(0);\n\n        for (char c : path) {\n            if (c == 'U') {\n                edges.push_back({false, i - 1, j});\n                colCnt[j]++;\n                --i;\n            } else if (c == 'D') {\n                edges.push_back({false, i, j});\n                colCnt[j]++;\n                ++i;\n            } else if (c == 'L') {\n                edges.push_back({true, i, j - 1});\n                rowCnt[i]++;\n                --j;\n            } else { // 'R'\n                edges.push_back({true, i, j});\n                rowCnt[i]++;\n                ++j;\n            }\n        }\n    }\n\npublic:\n    Solver() : rng(20240309), urand(0.0, 1.0) {\n        rowBase.fill(5000.0);\n        colBase.fill(5000.0);\n\n        for (auto& r : deltaH) r.fill(0.0);\n        for (auto& r : deltaV) r.fill(0.0);\n        for (auto& r : cntH) r.fill(0);\n        for (auto& r : cntV) r.fill(0);\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int q = 0; q < Q; q++) {\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            HCost baseH, searchH;\n            VCost baseV, searchV;\n            buildBaseCosts(baseH, baseV);\n\n            // Early stage: slight bias to shorter-step paths + tiny jitter for exploration.\n            double stepPenalty = (q < 180) ? (100.0 * (180 - q) / 180.0) : 0.0;\n            double jitterEps = (q < 180) ? (0.05 * (180 - q) / 180.0) : 0.0;\n\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N - 1; j++) {\n                    double c = baseH[i][j] + stepPenalty;\n                    if (jitterEps > 0.0) {\n                        double unc = 1.0 / sqrt(cntH[i][j] + 1.0);\n                        double r = urand(rng) * 2.0 - 1.0;\n                        c *= (1.0 + jitterEps * unc * r);\n                    }\n                    searchH[i][j] = max(1.0, c);\n                }\n            }\n            for (int i = 0; i < N - 1; i++) {\n                for (int j = 0; j < N; j++) {\n                    double c = baseV[i][j] + stepPenalty;\n                    if (jitterEps > 0.0) {\n                        double unc = 1.0 / sqrt(cntV[i][j] + 1.0);\n                        double r = urand(rng) * 2.0 - 1.0;\n                        c *= (1.0 + jitterEps * unc * r);\n                    }\n                    searchV[i][j] = max(1.0, c);\n                }\n            }\n\n            string path;\n            if (q < RANDOM_PHASE) path = biasedMonotonePath(si, sj, ti, tj, baseH, baseV);\n            else path = dijkstraPath(si, sj, ti, tj, searchH, searchV);\n\n            cout << path << '\\n' << flush;\n\n            int obsInt;\n            if (!(cin >> obsInt)) return;\n            if (obsInt < 0) return; // judge error guard\n            double obs = static_cast<double>(obsInt);\n\n            vector<EdgeRef> edges;\n            array<int, N> rowCnt, colCnt;\n            pathToEdges(si, sj, path, edges, rowCnt, colCnt);\n\n            int L = static_cast<int>(edges.size());\n            if (L == 0) continue;\n\n            // Prediction before update\n            double pred = 0.0;\n            for (const auto& e : edges) {\n                pred += e.horiz ? baseH[e.i][e.j] : baseV[e.i][e.j];\n            }\n            double err = obs - pred;\n\n            // Update row/column base parameters\n            double norm = 1e-9;\n            for (int i = 0; i < N; i++) norm += 1.0 * rowCnt[i] * rowCnt[i];\n            for (int j = 0; j < N; j++) norm += 1.0 * colCnt[j] * colCnt[j];\n\n            double etaLine = 0.24 * exp(-0.002 * q) + 0.08;\n            for (int i = 0; i < N; i++) {\n                if (rowCnt[i] == 0) continue;\n                rowBase[i] += etaLine * err * rowCnt[i] / norm;\n                rowBase[i] = clampd(rowBase[i], COST_MIN, COST_MAX);\n            }\n            for (int j = 0; j < N; j++) {\n                if (colCnt[j] == 0) continue;\n                colBase[j] += etaLine * err * colCnt[j] / norm;\n                colBase[j] = clampd(colBase[j], COST_MIN, COST_MAX);\n            }\n\n            // Residual after base update (computed exactly on this path)\n            double pred2 = 0.0;\n            for (const auto& e : edges) {\n                if (e.horiz) {\n                    double sh = static_cast<double>(cntH[e.i][e.j]) / (cntH[e.i][e.j] + PRIOR_CNT);\n                    pred2 += clampd(rowBase[e.i] + sh * deltaH[e.i][e.j], COST_MIN, COST_MAX);\n                } else {\n                    double sh = static_cast<double>(cntV[e.i][e.j]) / (cntV[e.i][e.j] + PRIOR_CNT);\n                    pred2 += clampd(colBase[e.j] + sh * deltaV[e.i][e.j], COST_MIN, COST_MAX);\n                }\n            }\n            double residual = obs - pred2;\n\n            // Update local residuals on traversed edges\n            double etaDelta = 0.40 * exp(-0.0015 * q) + 0.15;\n            double perEdge = residual / L;\n            for (const auto& e : edges) {\n                if (e.horiz) {\n                    int c = cntH[e.i][e.j];\n                    double lr = etaDelta / sqrt(c + 1.0);\n                    deltaH[e.i][e.j] += lr * perEdge;\n                    deltaH[e.i][e.j] = clampd(deltaH[e.i][e.j], -DELTA_CLIP, DELTA_CLIP);\n                    cntH[e.i][e.j] = c + 1;\n                } else {\n                    int c = cntV[e.i][e.j];\n                    double lr = etaDelta / sqrt(c + 1.0);\n                    deltaV[e.i][e.j] += lr * perEdge;\n                    deltaV[e.i][e.j] = clampd(deltaV[e.i][e.j], -DELTA_CLIP, DELTA_CLIP);\n                    cntV[e.i][e.j] = c + 1;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M;\n    int CELL, PPS, P;\n    vector<vector<uint8_t>> strs;\n    vector<uint8_t> len;\n    vector<int> groupLen;\n    vector<vector<uint32_t>> cellEntries; // packed: (pid << 3) | req(0..7)\n\n    vector<int16_t> matchCount;           // [0..12]\n    vector<array<int,13>> hist;           // hist[sid][match]\n    vector<uint8_t> best;                 // best match per string\n\n    vector<uint8_t> grid;\n    vector<uint8_t> bestGlobalGrid;\n    int bestGlobalC = -1;\n    int bestGlobalSoft = -1;\n\n    int g1[13];\n    int scoreTbl[13][13];\n\n    vector<int> order;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 2.90; // keep some safety margin from 3.0\n\n    Solver(int N_, int M_, const vector<string>& S): N(N_), M(M_) {\n        CELL = N * N;\n        PPS = 2 * CELL;\n        P = M * PPS;\n\n        strs.resize(M);\n        len.resize(M);\n        groupLen.resize(M);\n\n        for (int i = 0; i < M; i++) {\n            len[i] = (uint8_t)S[i].size();\n            groupLen[i] = 2 * (int)len[i];\n            strs[i].resize(len[i]);\n            for (int j = 0; j < (int)len[i]; j++) strs[i][j] = (uint8_t)(S[i][j] - 'A');\n        }\n\n        cellEntries.assign(CELL, {});\n        buildEntries();\n\n        matchCount.assign(P, 0);\n        hist.resize(M);\n        for (auto &a : hist) a.fill(0);\n        best.assign(M, 0);\n\n        grid.assign(CELL, 0);\n        bestGlobalGrid.assign(CELL, 0);\n\n        order.resize(CELL);\n        iota(order.begin(), order.end(), 0);\n\n        g1[0] = 1;\n        for (int i = 1; i <= 12; i++) g1[i] = g1[i-1] << 1;\n\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng.seed((uint32_t)(seed ^ (uint64_t(M) << 21) ^ uint64_t(P)));\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void buildEntries() {\n        int perCell = 0;\n        for (int i = 0; i < M; i++) perCell += groupLen[i];\n        for (int c = 0; c < CELL; c++) cellEntries[c].reserve(perCell);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            int k = len[sid];\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    int start = r * N + c;\n                    int pidH = base + start;\n                    int pidV = base + CELL + start;\n                    for (int p = 0; p < k; p++) {\n                        uint32_t req = strs[sid][p];\n                        int ch = r * N + ((c + p) % N);\n                        int cv = ((r + p) % N) * N + c;\n                        cellEntries[ch].push_back((uint32_t(pidH) << 3) | req);\n                        cellEntries[cv].push_back((uint32_t(pidV) << 3) | req);\n                    }\n                }\n            }\n        }\n    }\n\n    void initRandomGrid() {\n        for (int i = 0; i < CELL; i++) grid[i] = (uint8_t)(rng() & 7);\n    }\n\n    void recomputeMatchCount() {\n        fill(matchCount.begin(), matchCount.end(), 0);\n        for (int cell = 0; cell < CELL; cell++) {\n            int ch = grid[cell];\n            if (ch > 7) continue;\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                if ((int)(x & 7u) == ch) {\n                    int pid = (int)(x >> 3);\n                    matchCount[pid]++;\n                }\n            }\n        }\n    }\n\n    int phase1Sweep() {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int cell : order) {\n            int old = grid[cell];\n            long long bonus[8] = {0,0,0,0,0,0,0,0};\n\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n                int base = mc - ((old == req) ? 1 : 0);\n                bonus[req] += (long long)g1[base + 1] - g1[base];\n            }\n\n            int nw = old;\n            long long bestv = bonus[old];\n            for (int a = 0; a < 8; a++) {\n                if (bonus[a] > bestv) {\n                    bestv = bonus[a];\n                    nw = a;\n                }\n            }\n            if (nw == old) continue;\n\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                if (req == old) {\n                    if (req != nw) matchCount[pid]--;\n                } else if (req == nw) {\n                    matchCount[pid]++;\n                }\n            }\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildHistBest() {\n        for (int sid = 0; sid < M; sid++) hist[sid].fill(0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            for (int t = 0; t < PPS; t++) {\n                int mc = matchCount[base + t];\n                hist[sid][mc]++;\n            }\n        }\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = k;\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    void refreshBestAll() {\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            while (b < k && hist[sid][b + 1] > 0) b++;\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    inline int calcC() const {\n        int c = 0;\n        for (int sid = 0; sid < M; sid++) if (best[sid] == len[sid]) c++;\n        return c;\n    }\n\n    inline int calcSoft() const {\n        int s = 0;\n        for (int sid = 0; sid < M; sid++) s += best[sid];\n        return s;\n    }\n\n    void updateGlobal() {\n        int c = calcC();\n        int soft = calcSoft();\n        if (c > bestGlobalC || (c == bestGlobalC && soft > bestGlobalSoft)) {\n            bestGlobalC = c;\n            bestGlobalSoft = soft;\n            bestGlobalGrid = grid;\n        }\n    }\n\n    void buildScoreTbl(int bonusFull) {\n        for (int k = 0; k <= 12; k++) {\n            for (int b = 0; b <= 12; b++) {\n                if (b > k) scoreTbl[k][b] = -1000000000;\n                else scoreTbl[k][b] = b * b + ((b == k) ? bonusFull : 0);\n            }\n        }\n    }\n\n    int chooseLetterPhase2(int cell) {\n        int old = grid[cell];\n        long long delta[8] = {0,0,0,0,0,0,0,0};\n\n        const auto &vec = cellEntries[cell];\n        int pos = 0;\n\n        // Entries are grouped by sid (build order is sid-major),\n        // and each sid contributes exactly 2*len[sid] entries for every cell.\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            int gsz = groupLen[sid];\n\n            int cnt[8][3] = {}; // [req][0:b-1, 1:b, 2:b+1]\n\n            for (int t = 0; t < gsz; t++) {\n                uint32_t x = vec[pos + t];\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n\n                if (b > 0 && mc == b - 1) cnt[req][0]++;\n                if (mc == b) cnt[req][1]++;\n                if (b < k && mc == b + 1) cnt[req][2]++;\n            }\n            pos += gsz;\n\n            int baseScore = scoreTbl[k][b];\n            int hb = hist[sid][b];\n            int hbp1 = (b < k ? hist[sid][b + 1] : 0);\n\n            int old0 = cnt[old][1];\n            int oldp1 = cnt[old][2];\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                int nb;\n\n                if (b < k) {\n                    int cb1 = hbp1 - oldp1 + cnt[a][1];\n                    if (cb1 > 0) {\n                        nb = b + 1;\n                    } else {\n                        int cb = hb - old0 + oldp1 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                        nb = (cb > 0 ? b : b - 1);\n                        if (nb < 0) nb = 0;\n                    }\n                } else {\n                    int cb = hb - old0 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                    nb = (cb > 0 ? b : b - 1);\n                    if (nb < 0) nb = 0;\n                }\n\n                delta[a] += (long long)scoreTbl[k][nb] - baseScore;\n            }\n        }\n\n        int nw = old;\n        long long bestD = 0;\n        for (int a = 0; a < 8; a++) {\n            if (delta[a] > bestD) {\n                bestD = delta[a];\n                nw = a;\n            }\n        }\n        return nw;\n    }\n\n    int phase2Sweep() {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int cell : order) {\n            int old = grid[cell];\n            int nw = chooseLetterPhase2(cell);\n            if (nw == old) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        if (req != nw) {\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc - 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc - 1]++;\n                        }\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc + 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc + 1]++;\n                    }\n                }\n                pos += gsz;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            refreshBestAll();\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void runOne(double deadline) {\n        initRandomGrid();\n        recomputeMatchCount();\n\n        // Phase 1: smoother objective on all placements\n        for (int s = 0; s < 6; s++) {\n            if (elapsed() >= deadline) return;\n            int ch = phase1Sweep();\n            if (ch == 0) break;\n        }\n\n        if (elapsed() >= deadline) return;\n        buildHistBest();\n        updateGlobal();\n\n        // Phase 2: closer-to-score objective\n        const int stageBonus[] = {0, 200, 100000};\n        const int stageSweep[] = {3, 4, 3};\n\n        for (int st = 0; st < 3; st++) {\n            buildScoreTbl(stageBonus[st]);\n            for (int it = 0; it < stageSweep[st]; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep();\n                updateGlobal();\n                if (ch == 0) break;\n            }\n        }\n\n        // Extra polishing with strong full-match bonus\n        buildScoreTbl(100000);\n        while (elapsed() < deadline) {\n            int ch = phase2Sweep();\n            updateGlobal();\n            if (ch == 0) break;\n        }\n    }\n\n    void dotPostprocessIfPossible() {\n        if (bestGlobalC != M) return;\n        if (elapsed() > TL - 0.03) return;\n\n        grid = bestGlobalGrid;\n        recomputeMatchCount();\n        buildHistBest();\n        if (calcC() != M) return; // safety\n\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int cell : order) {\n            if (elapsed() > TL - 0.005) break;\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            bool touched = false;\n\n            // Try old -> '.'\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    if (req == old) {\n                        int pid = (int)(x >> 3);\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                        touched = true;\n                    }\n                }\n                pos += gsz;\n            }\n\n            if (!touched) {\n                grid[cell] = 8;\n                continue;\n            }\n\n            refreshBestAll();\n            if (calcC() == M) {\n                grid[cell] = 8; // keep '.'\n            } else {\n                // Revert\n                pos = 0;\n                for (int sid = 0; sid < M; sid++) {\n                    int gsz = groupLen[sid];\n                    for (int t = 0; t < gsz; t++) {\n                        uint32_t x = vec[pos + t];\n                        int req = (int)(x & 7u);\n                        if (req == old) {\n                            int pid = (int)(x >> 3);\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc + 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc + 1]++;\n                        }\n                    }\n                    pos += gsz;\n                }\n                refreshBestAll();\n            }\n        }\n\n        bestGlobalGrid = grid;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        int restart = 0;\n        while (true) {\n            double now = elapsed();\n            double rem = TL - now;\n            if (rem < 0.15) break;\n\n            double budget = (restart == 0 ? min(1.6, rem - 0.02) : min(1.0, rem - 0.02));\n            if (budget < 0.10) break;\n\n            runOne(now + budget);\n            restart++;\n        }\n\n        if (bestGlobalC < 0) {\n            initRandomGrid();\n            bestGlobalGrid = grid;\n            bestGlobalC = 0;\n        }\n\n        dotPostprocessIfPossible();\n    }\n\n    void output() const {\n        for (int r = 0; r < N; r++) {\n            string line(N, '.');\n            for (int c = 0; c < N; c++) {\n                int v = bestGlobalGrid[r * N + c];\n                if (0 <= v && v < 8) line[c] = char('A' + v);\n                else line[c] = '.';\n            }\n            cout << line << '\\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<string> S(M);\n    for (int i = 0; i < M; i++) cin >> S[i];\n\n    Solver solver(N, M, S);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    using ull = unsigned long long;\n    static constexpr int INF = 1e9;\n\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    const char dc[4] = {'U', 'D', 'L', 'R'};\n    const int opp[4] = {1, 0, 3, 2};\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0;                      // number of road cells\n    int startRid = -1;              // road-id of start\n    vector<vector<int>> id;         // grid -> road-id (-1 if obstacle)\n    vector<int> ri, rj, w;          // road-id -> row,col,cell cost\n    vector<array<int, 4>> nbr;      // road graph neighbors\n\n    int B = 0;                      // bit-block count\n    vector<ull> allBits;            // mask of all road ids\n\n    vector<int> candRid;                    // candidate index -> road-id\n    vector<vector<ull>> candVisBits;        // candidate visibility bitset\n    vector<vector<int>> candVisList;        // candidate visibility list\n    vector<char> inCand;                    // road-id is candidate?\n\n    vector<vector<int>> distC;              // candidate distance matrix (directed)\n\n    chrono::steady_clock::time_point t0;\n\n    long long elapsed_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n                   chrono::steady_clock::now() - t0)\n            .count();\n    }\n\n    void read_input() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void build_graph() {\n        R = 0;\n        id.assign(N, vector<int>(N, -1));\n        ri.clear();\n        rj.clear();\n        w.clear();\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    ri.push_back(i);\n                    rj.push_back(j);\n                    w.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n        startRid = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        for (int u = 0; u < R; u++) {\n            int i = ri[u], j = rj[u];\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                    nbr[u][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    pair<vector<ull>, vector<int>> compute_visibility(int rid) const {\n        vector<ull> bits(B, 0ULL);\n        vector<int> lst;\n\n        auto add = [&](int x) {\n            int b = x >> 6;\n            ull m = 1ULL << (x & 63);\n            if ((bits[b] & m) == 0) {\n                bits[b] |= m;\n                lst.push_back(x);\n            }\n        };\n\n        int i = ri[rid], j = rj[rid];\n        add(rid);\n\n        for (int y = j - 1; y >= 0; --y) {\n            int v = id[i][y];\n            if (v == -1) break;\n            add(v);\n        }\n        for (int y = j + 1; y < N; ++y) {\n            int v = id[i][y];\n            if (v == -1) break;\n            add(v);\n        }\n        for (int x = i - 1; x >= 0; --x) {\n            int v = id[x][j];\n            if (v == -1) break;\n            add(v);\n        }\n        for (int x = i + 1; x < N; ++x) {\n            int v = id[x][j];\n            if (v == -1) break;\n            add(v);\n        }\n        return {move(bits), move(lst)};\n    }\n\n    void build_candidates() {\n        B = (R + 63) >> 6;\n        allBits.assign(B, ~0ULL);\n        if (B > 0 && (R & 63)) {\n            allBits.back() = (1ULL << (R & 63)) - 1ULL;\n        }\n\n        candRid.clear();\n        candVisBits.clear();\n        candVisList.clear();\n        inCand.assign(R, 0);\n\n        auto add_candidate = [&](int rid) {\n            if (inCand[rid]) return;\n            inCand[rid] = 1;\n            candRid.push_back(rid);\n            auto [bits, lst] = compute_visibility(rid);\n            candVisBits.push_back(move(bits));\n            candVisList.push_back(move(lst));\n        };\n\n        add_candidate(startRid);\n\n        for (int u = 0; u < R; u++) {\n            if (u == startRid) continue;\n            int deg = 0;\n            for (int d = 0; d < 4; d++) if (nbr[u][d] != -1) deg++;\n\n            bool isCand = false;\n            if (deg != 2) {\n                isCand = true;\n            } else {\n                bool U = (nbr[u][0] != -1);\n                bool D = (nbr[u][1] != -1);\n                bool L = (nbr[u][2] != -1);\n                bool Rr = (nbr[u][3] != -1);\n                bool straight = (U && D) || (L && Rr);\n                isCand = !straight; // turn point\n            }\n            if (isCand) add_candidate(u);\n        }\n\n        // Safety: if some road cell is still not visible from any candidate, add it.\n        vector<ull> uni(B, 0ULL);\n        for (auto &vb : candVisBits) {\n            for (int b = 0; b < B; b++) uni[b] |= vb[b];\n        }\n\n        for (int b = 0; b < B; b++) {\n            ull miss = allBits[b] & (~uni[b]);\n            while (miss) {\n                int t = __builtin_ctzll(miss);\n                int rid = (b << 6) + t;\n                if (rid < R) add_candidate(rid);\n                miss &= (miss - 1);\n            }\n        }\n    }\n\n    void dijkstra(int src, vector<int>& dist,\n                  vector<int>* prev = nullptr,\n                  vector<int>* prevDir = nullptr,\n                  int target = -1) const {\n        dist.assign(R, INF);\n        if (prev) prev->assign(R, -1);\n        if (prevDir) prevDir->assign(R, -1);\n\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\n        while (!pq.empty()) {\n            auto [du, u] = pq.top();\n            pq.pop();\n            if (du != dist[u]) continue;\n            if (u == target) break;\n\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1) continue;\n                int nd = du + w[v]; // cost to enter v\n                if (nd < dist[v]) {\n                    dist[v] = nd;\n                    if (prev) (*prev)[v] = u;\n                    if (prevDir) (*prevDir)[v] = d;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    }\n\n    void precompute_distances() {\n        int C = (int)candRid.size();\n        distC.assign(C, vector<int>(C, INF));\n\n        vector<int> dist;\n        for (int s = 0; s < C; s++) {\n            dijkstra(candRid[s], dist, nullptr, nullptr, -1);\n            for (int t = 0; t < C; t++) {\n                distC[s][t] = dist[candRid[t]];\n            }\n        }\n    }\n\n    vector<int> build_cycle_cover() {\n        int C = (int)candRid.size();\n        vector<int> seq;\n        seq.push_back(0); // start candidate index fixed at 0\n\n        vector<char> used(C, 0);\n        used[0] = 1;\n\n        vector<ull> unc = allBits;\n        for (int b = 0; b < B; b++) unc[b] &= ~candVisBits[0][b];\n\n        auto is_empty_bits = [&](const vector<ull>& bits) {\n            for (ull x : bits) if (x) return false;\n            return true;\n        };\n\n        while (!is_empty_bits(unc)) {\n            double bestScore = -1.0;\n            int bestIdx = -1;\n            int bestPos = 0;\n            int bestGain = -1;\n            int bestInc = INF;\n\n            int m = (int)seq.size();\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n\n                int gain = 0;\n                for (int b = 0; b < B; b++) {\n                    gain += __builtin_popcountll(candVisBits[c][b] & unc[b]);\n                }\n                if (gain == 0) continue;\n\n                int incMin = INF;\n                int pos = 0;\n\n                if (m == 1) {\n                    incMin = distC[0][c] + distC[c][0];\n                    pos = 0;\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p];\n                        int v = seq[(p + 1) % m];\n                        int inc = distC[u][c] + distC[c][v] - distC[u][v];\n                        if (inc < incMin) {\n                            incMin = inc;\n                            pos = p;\n                        }\n                    }\n                }\n\n                double score = 1.0 * gain * gain / (incMin + 1.0);\n\n                if (score > bestScore + 1e-12 ||\n                    (fabs(score - bestScore) <= 1e-12 &&\n                     (gain > bestGain ||\n                      (gain == bestGain && incMin < bestInc)))) {\n                    bestScore = score;\n                    bestIdx = c;\n                    bestPos = pos;\n                    bestGain = gain;\n                    bestInc = incMin;\n                }\n            }\n\n            if (bestIdx == -1) {\n                // should not happen due safety candidate completion\n                break;\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestIdx);\n            used[bestIdx] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candVisBits[bestIdx][b];\n        }\n\n        return seq;\n    }\n\n    void prune_cycle(vector<int>& seq) {\n        if (seq.size() <= 1) return;\n\n        vector<int> coverCnt(R, 0);\n        for (int idx : seq) {\n            for (int rid : candVisList[idx]) coverCnt[rid]++;\n        }\n\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int p = 1; p < (int)seq.size(); p++) { // keep start fixed\n                int idx = seq[p];\n                bool removable = true;\n                for (int rid : candVisList[idx]) {\n                    if (coverCnt[rid] == 1) {\n                        removable = false;\n                        break;\n                    }\n                }\n                if (removable) {\n                    for (int rid : candVisList[idx]) coverCnt[rid]--;\n                    seq.erase(seq.begin() + p);\n                    changed = true;\n                    --p;\n                }\n            }\n        }\n    }\n\n    long long cycle_cost(const vector<int>& seq) const {\n        int m = (int)seq.size();\n        if (m <= 1) return 0;\n        long long cost = 0;\n        for (int i = 0; i < m; i++) {\n            cost += distC[seq[i]][seq[(i + 1) % m]];\n        }\n        return cost;\n    }\n\n    void improve_cycle(vector<int>& seq) {\n        int m = (int)seq.size();\n        if (m <= 2) return;\n        if (m > 220) return; // avoid expensive LS on huge cycles\n\n        long long cur = cycle_cost(seq);\n\n        for (int iter = 0; iter < 8; iter++) {\n            if (elapsed_ms() > 2600) break;\n\n            auto try_relocate = [&]() -> bool {\n                int mm = (int)seq.size();\n                for (int i = 1; i < mm; i++) {\n                    if (elapsed_ms() > 2600) return false;\n\n                    vector<int> base = seq;\n                    int node = base[i];\n                    base.erase(base.begin() + i); // size mm-1\n\n                    for (int j = 1; j <= mm - 1; j++) {\n                        if (j == i) continue;\n                        vector<int> cand = base;\n                        cand.insert(cand.begin() + j, node);\n                        long long cc = cycle_cost(cand);\n                        if (cc < cur) {\n                            seq.swap(cand);\n                            cur = cc;\n                            return true;\n                        }\n                    }\n                }\n                return false;\n            };\n\n            auto try_swap = [&]() -> bool {\n                int mm = (int)seq.size();\n                for (int i = 1; i < mm; i++) {\n                    if (elapsed_ms() > 2600) return false;\n                    for (int j = i + 1; j < mm; j++) {\n                        vector<int> cand = seq;\n                        swap(cand[i], cand[j]);\n                        long long cc = cycle_cost(cand);\n                        if (cc < cur) {\n                            seq.swap(cand);\n                            cur = cc;\n                            return true;\n                        }\n                    }\n                }\n                return false;\n            };\n\n            bool improved = false;\n            if (try_relocate()) improved = true;\n            else if (try_swap()) improved = true;\n\n            if (!improved) break;\n        }\n    }\n\n    string path_moves(int srcRid, int dstRid) const {\n        if (srcRid == dstRid) return \"\";\n\n        vector<int> dist, prev, pdir;\n        dijkstra(srcRid, dist, &prev, &pdir, dstRid);\n\n        if (prev[dstRid] == -1) return \"\";\n\n        string rev;\n        int cur = dstRid;\n        while (cur != srcRid) {\n            int d = pdir[cur];\n            if (d < 0) return \"\";\n            rev.push_back(dc[d]); // move from prev[cur] -> cur\n            cur = prev[cur];\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    string build_answer_from_cycle(const vector<int>& seq) const {\n        if (seq.size() <= 1) return \"\";\n        string ans;\n        ans.reserve(100000);\n\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            int aRid = candRid[seq[i]];\n            int bRid = candRid[seq[(i + 1) % m]];\n            ans += path_moves(aRid, bRid);\n        }\n        return ans;\n    }\n\n    void mark_visible(int rid, vector<char>& seen) const {\n        int i = ri[rid], j = rj[rid];\n        seen[rid] = 1;\n\n        for (int y = j - 1; y >= 0; --y) {\n            int v = id[i][y];\n            if (v == -1) break;\n            seen[v] = 1;\n        }\n        for (int y = j + 1; y < N; ++y) {\n            int v = id[i][y];\n            if (v == -1) break;\n            seen[v] = 1;\n        }\n        for (int x = i - 1; x >= 0; --x) {\n            int v = id[x][j];\n            if (v == -1) break;\n            seen[v] = 1;\n        }\n        for (int x = i + 1; x < N; ++x) {\n            int v = id[x][j];\n            if (v == -1) break;\n            seen[v] = 1;\n        }\n    }\n\n    bool validate_full(const string& ans) const {\n        vector<char> seen(R, 0);\n\n        auto dir_id = [&](char c) -> int {\n            if (c == 'U') return 0;\n            if (c == 'D') return 1;\n            if (c == 'L') return 2;\n            if (c == 'R') return 3;\n            return -1;\n        };\n\n        int cur = startRid;\n        mark_visible(cur, seen);\n\n        for (char ch : ans) {\n            int d = dir_id(ch);\n            if (d == -1) return false;\n            int nx = nbr[cur][d];\n            if (nx == -1) return false;\n            cur = nx;\n            mark_visible(cur, seen);\n        }\n\n        if (cur != startRid) return false;\n        for (char f : seen) if (!f) return false;\n        return true;\n    }\n\n    string fallback_dfs_tour() const {\n        vector<char> vis(R, 0);\n        string out;\n        out.reserve(max(0, 2 * R));\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1 || vis[v]) continue;\n                out.push_back(dc[d]);\n                dfs(v);\n                out.push_back(dc[opp[d]]);\n            }\n        };\n\n        dfs(startRid);\n        return out;\n    }\n\n    string solve() {\n        t0 = chrono::steady_clock::now();\n\n        build_graph();\n        if (R == 0) return \"\";\n\n        build_candidates();\n        precompute_distances();\n\n        vector<int> seq = build_cycle_cover();\n        prune_cycle(seq);\n        improve_cycle(seq);\n\n        string ans = build_answer_from_cycle(seq);\n\n        // Safety check to avoid WA\n        if (!validate_full(ans)) {\n            ans = fallback_dfs_tour();\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    string ans = solver.solve();\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstruct Solver {\n    int N, M, K, R;\n    vector<vector<int>> d;          // task requirements\n    vector<vector<int>> succ;       // DAG edges\n    vector<int> indeg0, indegRem;\n    vector<int> outdeg, sumd, lp;\n    vector<int> taskState;          // 0:not started, 1:in progress, 2:done\n\n    vector<int> ready;\n    vector<int> readyPos;\n\n    struct Member {\n        bool busy = false;\n        int task = -1;\n        int startDay = 0;\n        vector<int> s;              // estimated skill vector\n        vector<int> histTask;\n        vector<int> histDur;\n        bool dirty = false;\n        int doneCount = 0;\n    };\n    vector<Member> members;\n\n    int day = 1;\n\n    // Skill fitting parameters\n    static constexpr int INIT_SKILL = 8;\n    static constexpr int SKILL_MAX = 60;\n    static constexpr int MAX_HIST = 80;\n\n    // Candidate/task scoring parameters\n    static constexpr int MAX_CAND = 120;\n    static constexpr int TOP_CAND = 80;\n\n    static constexpr int LP_W = 100;\n    static constexpr int UNLOCK_W = 40;\n    static constexpr int OUT_W = 10;\n    static constexpr int PRED_W = 25;\n\n    static constexpr int SCORE_SHIFT = 250000; // for non-negative MCF costs\n\n    void add_ready(int t) {\n        if (t < 0 || t >= N) return;\n        if (taskState[t] != 0) return;\n        if (indegRem[t] != 0) return;\n        if (readyPos[t] != -1) return;\n        readyPos[t] = (int)ready.size();\n        ready.push_back(t);\n    }\n\n    void remove_ready(int t) {\n        int p = readyPos[t];\n        if (p == -1) return;\n        int last = ready.back();\n        ready[p] = last;\n        readyPos[last] = p;\n        ready.pop_back();\n        readyPos[t] = -1;\n    }\n\n    inline int sample_loss(int w, int obs) const {\n        int pred = (w <= 0 ? 1 : w);\n        int e = pred - obs;\n        return e * e;\n    }\n\n    inline int predict_time(int member, int task) const {\n        const auto &s = members[member].s;\n        const auto &req = d[task];\n        int w = 0;\n        for (int k = 0; k < K; k++) {\n            if (req[k] > s[k]) w += req[k] - s[k];\n        }\n        return (w <= 0 ? 1 : w);\n    }\n\n    int task_base(int task) const {\n        int unlock = 0;\n        for (int ch : succ[task]) {\n            if (taskState[ch] == 0 && indegRem[ch] == 1) unlock++;\n        }\n        int base = LP_W * lp[task] + UNLOCK_W * unlock + OUT_W * outdeg[task];\n        base += (N - task) / 20; // tiny tie-break toward smaller index\n        return base;\n    }\n\n    void optimize_member(int j) {\n        Member &mb = members[j];\n        int total = (int)mb.histTask.size();\n        if (total == 0) {\n            mb.dirty = false;\n            return;\n        }\n\n        int st = max(0, total - MAX_HIST);\n        int h = total - st;\n\n        vector<int> tasks(h), obs(h);\n        for (int i = 0; i < h; i++) {\n            tasks[i] = mb.histTask[st + i];\n            obs[i] = mb.histDur[st + i];\n        }\n\n        vector<int> w(h);\n        long long loss = 0;\n        for (int i = 0; i < h; i++) {\n            int wi = 0;\n            const auto &req = d[tasks[i]];\n            for (int k = 0; k < K; k++) {\n                if (req[k] > mb.s[k]) wi += req[k] - mb.s[k];\n            }\n            w[i] = wi;\n            loss += sample_loss(wi, obs[i]);\n        }\n\n        // stronger regularization when h is small\n        int reg_w = 100 / (h + 10); // h=1 -> 9, h=40 -> 2, h=90 -> 1\n        if (reg_w > 0) {\n            for (int k = 0; k < K; k++) {\n                int diff = mb.s[k] - INIT_SKILL;\n                loss += 1LL * reg_w * diff * diff;\n            }\n        }\n\n        const int deltas[4] = {-2, -1, 1, 2};\n        int passes = (h < 8 ? 4 : (h < 20 ? 3 : 2));\n\n        for (int pass = 0; pass < passes; pass++) {\n            bool improved = false;\n\n            for (int k = 0; k < K; k++) {\n                int curS = mb.s[k];\n                long long bestLoss = loss;\n                int bestS = curS;\n\n                for (int delta : deltas) {\n                    int ns = curS + delta;\n                    if (ns < 0 || ns > SKILL_MAX) continue;\n\n                    long long newLoss = loss;\n                    if (reg_w > 0) {\n                        int oldDiff = curS - INIT_SKILL;\n                        int newDiff = ns - INIT_SKILL;\n                        newLoss += 1LL * reg_w * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > ns ? dval - ns : 0);\n                        if (oldComp == newComp) continue;\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n                        newLoss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                    }\n\n                    if (newLoss < bestLoss) {\n                        bestLoss = newLoss;\n                        bestS = ns;\n                    }\n                }\n\n                if (bestS != curS) {\n                    if (reg_w > 0) {\n                        int oldDiff = curS - INIT_SKILL;\n                        int newDiff = bestS - INIT_SKILL;\n                        loss += 1LL * reg_w * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > bestS ? dval - bestS : 0);\n                        if (oldComp == newComp) continue;\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n                        loss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                        w[i] = nw;\n                    }\n\n                    mb.s[k] = bestS;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        mb.dirty = false;\n    }\n\n    vector<int> make_candidates() const {\n        if ((int)ready.size() <= MAX_CAND) return ready;\n\n        vector<pair<int, int>> byBase; // (-base, task)\n        byBase.reserve(ready.size());\n        for (int t : ready) {\n            byBase.push_back({-task_base(t), t});\n        }\n        sort(byBase.begin(), byBase.end());\n\n        vector<int> cand;\n        cand.reserve(MAX_CAND);\n\n        vector<char> picked(N, 0);\n        int takeTop = min(TOP_CAND, (int)byBase.size());\n        for (int i = 0; i < takeTop; i++) {\n            int t = byBase[i].second;\n            cand.push_back(t);\n            picked[t] = 1;\n        }\n\n        vector<pair<int, int>> byEasy; // (sumd, task)\n        byEasy.reserve(ready.size() - takeTop);\n        for (int t : ready) {\n            if (!picked[t]) byEasy.push_back({sumd[t], t});\n        }\n        sort(byEasy.begin(), byEasy.end());\n\n        int need = MAX_CAND - (int)cand.size();\n        for (int i = 0; i < need && i < (int)byEasy.size(); i++) {\n            cand.push_back(byEasy[i].second);\n        }\n        return cand;\n    }\n\n    vector<pair<int, int>> decide_assignments() {\n        vector<pair<int, int>> ret;\n\n        vector<int> freeMembers;\n        freeMembers.reserve(M);\n        for (int j = 0; j < M; j++) {\n            if (!members[j].busy) freeMembers.push_back(j);\n        }\n        if (freeMembers.empty() || ready.empty()) return ret;\n\n        vector<int> cand = make_candidates();\n        int F = (int)freeMembers.size();\n        int T = (int)cand.size();\n        int L = min(F, T);\n        if (L <= 0) return ret;\n\n        vector<int> base(T);\n        for (int i = 0; i < T; i++) base[i] = task_base(cand[i]);\n\n        int S = F + T;\n        int G = S + 1;\n        mcf_graph<int, int> graph(G + 1);\n\n        for (int fi = 0; fi < F; fi++) graph.add_edge(S, fi, 1, 0);\n        for (int ti = 0; ti < T; ti++) graph.add_edge(F + ti, G, 1, 0);\n\n        vector<int> eid(F * T, -1);\n        for (int fi = 0; fi < F; fi++) {\n            int member = freeMembers[fi];\n            for (int ti = 0; ti < T; ti++) {\n                int task = cand[ti];\n                int pred = predict_time(member, task);\n                int score = base[ti] - PRED_W * pred;\n                int cost = SCORE_SHIFT - score; // must be non-negative\n                eid[fi * T + ti] = graph.add_edge(fi, F + ti, 1, cost);\n            }\n        }\n\n        graph.flow(S, G, L);\n\n        for (int fi = 0; fi < F; fi++) {\n            for (int ti = 0; ti < T; ti++) {\n                auto e = graph.get_edge(eid[fi * T + ti]);\n                if (e.flow > 0) {\n                    int m = freeMembers[fi];\n                    int t = cand[ti];\n                    ret.push_back({m, t});\n                }\n            }\n        }\n\n        // Commit assignments\n        for (auto [m, t] : ret) {\n            members[m].busy = true;\n            members[m].task = t;\n            members[m].startDay = day;\n            taskState[t] = 1;\n            remove_ready(t);\n        }\n\n        return ret;\n    }\n\n    void read_initial() {\n        cin >> N >> M >> K >> R;\n\n        d.assign(N, vector<int>(K));\n        sumd.assign(N, 0);\n        for (int i = 0; i < N; i++) {\n            int s = 0;\n            for (int k = 0; k < K; k++) {\n                cin >> d[i][k];\n                s += d[i][k];\n            }\n            sumd[i] = s;\n        }\n\n        succ.assign(N, {});\n        indeg0.assign(N, 0);\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u;\n            --v;\n            succ[u].push_back(v);\n            indeg0[v]++;\n        }\n\n        outdeg.assign(N, 0);\n        for (int i = 0; i < N; i++) outdeg[i] = (int)succ[i].size();\n\n        lp.assign(N, 1);\n        for (int i = N - 1; i >= 0; i--) {\n            int best = 1;\n            for (int to : succ[i]) best = max(best, lp[to] + 1);\n            lp[i] = best;\n        }\n\n        indegRem = indeg0;\n        taskState.assign(N, 0);\n\n        ready.clear();\n        readyPos.assign(N, -1);\n        for (int i = 0; i < N; i++) {\n            if (indegRem[i] == 0) add_ready(i);\n        }\n\n        members.assign(M, Member());\n        for (int j = 0; j < M; j++) {\n            members[j].s.assign(K, INIT_SKILL);\n        }\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        read_initial();\n\n        day = 1;\n        while (true) {\n            auto assignments = decide_assignments();\n\n            cout << assignments.size();\n            for (auto [m, t] : assignments) {\n                cout << ' ' << (m + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int n;\n            if (!(cin >> n)) return;\n            if (n == -1) return;\n\n            vector<int> finished(n);\n            for (int i = 0; i < n; i++) {\n                cin >> finished[i];\n                --finished[i];\n            }\n\n            for (int m : finished) {\n                if (m < 0 || m >= M) continue;\n                Member &mb = members[m];\n                if (!mb.busy) continue; // safety\n\n                int task = mb.task;\n                int duration = day - mb.startDay + 1;\n\n                mb.busy = false;\n                mb.task = -1;\n                mb.doneCount++;\n                mb.histTask.push_back(task);\n                mb.histDur.push_back(duration);\n                mb.dirty = true;\n\n                taskState[task] = 2;\n                for (int ch : succ[task]) {\n                    indegRem[ch]--;\n                    if (indegRem[ch] == 0 && taskState[ch] == 0) {\n                        add_ready(ch);\n                    }\n                }\n            }\n\n            for (int j = 0; j < M; j++) {\n                if (members[j].dirty) optimize_member(j);\n            }\n\n            day++;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int N = 1000;\n    static constexpr int M = 50;\n    static constexpr int DEP = 400;\n\n    struct Insertion {\n        int delta;\n        int i;\n        int j; // delivery insertion index after pickup insertion\n    };\n\n    struct State {\n        vector<int> route; // + (id+1): pickup, - (id+1): delivery\n        vector<int> sel;   // selected order ids (0-indexed)\n        array<int, N> pos; // -1 if not selected, else index in sel\n        int len = INT_MAX;\n        State() { pos.fill(-1); }\n    };\n\n    int ax[N], ay[N], cx[N], cy[N];\n    int baseCost[N];\n\n    vector<int> sortedIds;\n    vector<int> pool;\n\n    mt19937 rng;\n    uniform_real_distribution<double> dist01;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 1.90; // seconds\n\n    // scratch\n    vector<int> work, work2;\n\n    Solver()\n        : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()),\n          dist01(0.0, 1.0) {}\n\n    static inline int md(int x1, int y1, int x2, int y2) {\n        return abs(x1 - x2) + abs(y1 - y2);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    int calcLen(const vector<int>& route) const {\n        int len = 0;\n        int px = DEP, py = DEP;\n        for (int e : route) {\n            int id = (e > 0 ? e : -e) - 1;\n            int nx = (e > 0 ? ax[id] : cx[id]);\n            int ny = (e > 0 ? ay[id] : cy[id]);\n            len += md(px, py, nx, ny);\n            px = nx;\n            py = ny;\n        }\n        len += md(px, py, DEP, DEP);\n        return len;\n    }\n\n    Insertion bestInsertPair(const vector<int>& route, int oid) const {\n        int n = (int)route.size();\n\n        int rx[105], ry[105];\n        for (int i = 0; i < n; i++) {\n            int e = route[i];\n            int id = (e > 0 ? e : -e) - 1;\n            if (e > 0) {\n                rx[i] = ax[id];\n                ry[i] = ay[id];\n            } else {\n                rx[i] = cx[id];\n                ry[i] = cy[id];\n            }\n        }\n\n        int px = ax[oid], py = ay[oid];\n        int qx = cx[oid], qy = cy[oid];\n\n        Insertion best{INT_MAX, 0, 1};\n\n        for (int i = 0; i <= n; i++) {\n            int Ax = (i == 0 ? DEP : rx[i - 1]);\n            int Ay = (i == 0 ? DEP : ry[i - 1]);\n            int Bx = (i == n ? DEP : rx[i]);\n            int By = (i == n ? DEP : ry[i]);\n\n            int dAB = md(Ax, Ay, Bx, By);\n            int baseP = md(Ax, Ay, px, py) + md(px, py, Bx, By) - dAB;\n\n            // adjacent: A -> P -> Q -> B\n            int deltaAdj = md(Ax, Ay, px, py) + md(px, py, qx, qy) + md(qx, qy, Bx, By) - dAB;\n            if (deltaAdj < best.delta) {\n                best = {deltaAdj, i, i + 1};\n            }\n\n            // separated Q insertion\n            for (int j = i + 2; j <= n + 1; j++) {\n                int Cx = rx[j - 2];\n                int Cy = ry[j - 2];\n                int Dx = (j - 1 == n ? DEP : rx[j - 1]);\n                int Dy = (j - 1 == n ? DEP : ry[j - 1]);\n\n                int deltaQ = md(Cx, Cy, qx, qy) + md(qx, qy, Dx, Dy) - md(Cx, Cy, Dx, Dy);\n                int delta = baseP + deltaQ;\n                if (delta < best.delta) {\n                    best = {delta, i, j};\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void insertPair(vector<int>& route, const Insertion& ins, int oid) const {\n        route.insert(route.begin() + ins.i, oid + 1);\n        route.insert(route.begin() + ins.j, -(oid + 1));\n    }\n\n    void removeOrder(const vector<int>& route, int oid, vector<int>& out) const {\n        out.clear();\n        int p = oid + 1;\n        int d = -p;\n        for (int e : route) {\n            if (e == p || e == d) continue;\n            out.push_back(e);\n        }\n    }\n\n    void rebuildPos(State& s) const {\n        s.pos.fill(-1);\n        for (int i = 0; i < (int)s.sel.size(); i++) s.pos[s.sel[i]] = i;\n    }\n\n    State buildTop50() const {\n        State s;\n        s.route.reserve(2 * M);\n        s.sel.reserve(M);\n\n        for (int i = 0; i < M; i++) s.sel.push_back(sortedIds[i]);\n        for (int oid : s.sel) {\n            Insertion ins = bestInsertPair(s.route, oid);\n            insertPair(s.route, ins, oid);\n        }\n        s.len = calcLen(s.route);\n        s.pos.fill(-1);\n        for (int i = 0; i < M; i++) s.pos[s.sel[i]] = i;\n        return s;\n    }\n\n    State buildRandomGreedy(int samplePerStep) {\n        State s;\n        s.route.reserve(2 * M);\n        s.sel.reserve(M);\n\n        array<char, N> chosen{};\n        chosen.fill(0);\n\n        for (int step = 0; step < M; step++) {\n            vector<int> cand;\n            cand.reserve(samplePerStep + 4);\n\n            int tries = samplePerStep * 40;\n            while ((int)cand.size() < samplePerStep && tries--) {\n                int id = pool[rng() % pool.size()];\n                if (chosen[id]) continue;\n                bool dup = false;\n                for (int x : cand) if (x == id) { dup = true; break; }\n                if (!dup) cand.push_back(id);\n            }\n\n            if (cand.empty()) {\n                for (int id : pool) {\n                    if (!chosen[id]) {\n                        cand.push_back(id);\n                        break;\n                    }\n                }\n            }\n\n            int bestId = -1;\n            Insertion bestIns{INT_MAX, 0, 1};\n\n            for (int id : cand) {\n                Insertion ins = bestInsertPair(s.route, id);\n                if (ins.delta < bestIns.delta) {\n                    bestIns = ins;\n                    bestId = id;\n                }\n            }\n\n            if (bestId == -1) {\n                for (int id : pool) if (!chosen[id]) {\n                    bestId = id;\n                    bestIns = bestInsertPair(s.route, id);\n                    break;\n                }\n            }\n\n            insertPair(s.route, bestIns, bestId);\n            chosen[bestId] = 1;\n            s.sel.push_back(bestId);\n        }\n\n        rebuildPos(s);\n        s.len = calcLen(s.route);\n        return s;\n    }\n\n    bool tryRelocate(State& s, int oid) {\n        removeOrder(s.route, oid, work);\n        int base = calcLen(work);\n\n        Insertion ins = bestInsertPair(work, oid);\n        int pred = base + ins.delta;\n        if (pred >= s.len) return false;\n\n        work2 = work;\n        insertPair(work2, ins, oid);\n        int real = calcLen(work2);\n\n        if (real < s.len) {\n            s.route.swap(work2);\n            s.len = real;\n            return true;\n        }\n        return false;\n    }\n\n    int randomUnselectedFromPool(const State& s) {\n        if (pool.empty()) return -1;\n        for (int t = 0; t < 40; t++) {\n            int id = pool[rng() % pool.size()];\n            if (s.pos[id] == -1) return id;\n        }\n        for (int id : pool) if (s.pos[id] == -1) return id;\n        return -1;\n    }\n\n    int randomUnselectedAny(const State& s) {\n        for (int t = 0; t < 60; t++) {\n            int id = rng() % N;\n            if (s.pos[id] == -1) return id;\n        }\n        for (int id = 0; id < N; id++) if (s.pos[id] == -1) return id;\n        return -1;\n    }\n\n    bool tryReplace(State& s, double temp) {\n        int old = s.sel[rng() % M];\n        for (int k = 0; k < 2; k++) {\n            int c = s.sel[rng() % M];\n            if (baseCost[c] > baseCost[old]) old = c;\n        }\n\n        removeOrder(s.route, old, work);\n        int base = calcLen(work);\n\n        int bestId = -1;\n        Insertion bestIns{INT_MAX, 0, 1};\n        int bestPred = INT_MAX;\n\n        int tried[16];\n        int tcnt = 0;\n\n        auto consider = [&](int id) {\n            if (id < 0) return;\n            if (s.pos[id] != -1) return;\n            for (int i = 0; i < tcnt; i++) if (tried[i] == id) return;\n            tried[tcnt++] = id;\n\n            Insertion ins = bestInsertPair(work, id);\n            int pred = base + ins.delta;\n            if (pred < bestPred) {\n                bestPred = pred;\n                bestIns = ins;\n                bestId = id;\n            }\n        };\n\n        for (int t = 0; t < 6; t++) consider(randomUnselectedFromPool(s));\n        consider(randomUnselectedAny(s));\n\n        if (bestId == -1) return false;\n\n        int delta = bestPred - s.len;\n        bool accept = false;\n        if (delta <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-double(delta) / temp);\n            if (dist01(rng) < prob) accept = true;\n        }\n        if (!accept) return false;\n\n        work2 = work;\n        insertPair(work2, bestIns, bestId);\n        int real = calcLen(work2);\n\n        int idx = s.pos[old];\n        s.pos[old] = -1;\n        s.pos[bestId] = idx;\n        s.sel[idx] = bestId;\n        s.route.swap(work2);\n        s.len = real;\n\n        return true;\n    }\n\n    void relaxAll(State& s, double deadline) {\n        while (elapsed() < deadline) {\n            bool improved = false;\n            vector<int> ord = s.sel;\n            shuffle(ord.begin(), ord.end(), rng);\n            for (int oid : ord) {\n                if (elapsed() >= deadline) break;\n                if (tryRelocate(s, oid)) improved = true;\n            }\n            if (!improved) break;\n        }\n    }\n\n    void output(const State& s) const {\n        cout << M;\n        for (int id : s.sel) cout << ' ' << (id + 1);\n        cout << '\\n';\n\n        int n = (int)s.route.size() + 2;\n        cout << n;\n        cout << ' ' << DEP << ' ' << DEP;\n        for (int e : s.route) {\n            int id = (e > 0 ? e : -e) - 1;\n            if (e > 0) {\n                cout << ' ' << ax[id] << ' ' << ay[id];\n            } else {\n                cout << ' ' << cx[id] << ' ' << cy[id];\n            }\n        }\n        cout << ' ' << DEP << ' ' << DEP << '\\n';\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 0; i < N; i++) {\n            if (!(cin >> ax[i] >> ay[i] >> cx[i] >> cy[i])) return;\n        }\n\n        sortedIds.resize(N);\n        iota(sortedIds.begin(), sortedIds.end(), 0);\n\n        for (int i = 0; i < N; i++) {\n            baseCost[i] = md(DEP, DEP, ax[i], ay[i])\n                        + md(ax[i], ay[i], cx[i], cy[i])\n                        + md(cx[i], cy[i], DEP, DEP);\n        }\n\n        sort(sortedIds.begin(), sortedIds.end(), [&](int l, int r) {\n            return baseCost[l] < baseCost[r];\n        });\n\n        int K = 350;\n        K = min(K, N);\n        pool.assign(sortedIds.begin(), sortedIds.begin() + K);\n\n        t0 = chrono::steady_clock::now();\n        work.reserve(2 * M);\n        work2.reserve(2 * M);\n\n        State cur = buildTop50();\n        for (int rep = 0; rep < 2; rep++) {\n            State cand = buildRandomGreedy(28);\n            if (cand.len < cur.len) cur = std::move(cand);\n        }\n\n        double mainEnd = TL - 0.06;\n        if (mainEnd < 0.0) mainEnd = TL;\n\n        double firstDeadline = min(mainEnd, elapsed() + 0.30);\n        relaxAll(cur, firstDeadline);\n\n        State best = cur;\n\n        int iter = 0;\n        while (elapsed() < mainEnd) {\n            iter++;\n\n            if ((iter & 3) == 0) {\n                int oid = cur.sel[rng() % M];\n                tryRelocate(cur, oid);\n            } else {\n                double p = elapsed() / TL;\n                double temp = 50.0 * (1.0 - p) + 1.0 * p;\n                bool changed = tryReplace(cur, temp);\n                if (changed) {\n                    for (int k = 0; k < 2; k++) {\n                        int oid = cur.sel[rng() % M];\n                        tryRelocate(cur, oid);\n                    }\n                }\n            }\n\n            if (cur.len < best.len) best = cur;\n\n            if ((iter & 255) == 0 && cur.len > best.len + 350) {\n                cur = best;\n            }\n        }\n\n        if (elapsed() < TL) {\n            relaxAll(best, TL);\n        }\n\n        output(best);\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int MC_SAMPLES = 10;\n\nstruct DSU {\n    array<int, N> p{};\n    array<int, N> sz{};\n    int comps = N;\n\n    DSU() { init(); }\n\n    void init() {\n        for (int i = 0; i < N; ++i) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n        comps = N;\n    }\n\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        --comps;\n        return true;\n    }\n\n    bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n};\n\nstruct Edge {\n    int u, v, d;\n};\n\nstruct ScenEdge {\n    int idx, u, v, w;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n\n    int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read fixed initial information\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) {\n        if (!(cin >> xs[i] >> ys[i])) return 0;\n    }\n\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = xs[u] - xs[v];\n        long long dy = ys[u] - ys[v];\n        int d = static_cast<int>(llround(sqrt((long double)dx * dx + (long double)dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    // Pre-sample future scenarios and sort each scenario by sampled weight.\n    XorShift64 rng(123456789123ull);\n    vector<vector<ScenEdge>> scenarios(MC_SAMPLES, vector<ScenEdge>(M));\n\n    for (int s = 0; s < MC_SAMPLES; ++s) {\n        for (int i = 0; i < M; ++i) {\n            int w = rng.next_int(edges[i].d, 3 * edges[i].d);\n            scenarios[s][i] = {i, edges[i].u, edges[i].v, w};\n        }\n        sort(scenarios[s].begin(), scenarios[s].end(),\n             [](const ScenEdge& a, const ScenEdge& b) {\n                 if (a.w != b.w) return a.w < b.w;\n                 return a.idx < b.idx;\n             });\n    }\n\n    DSU uf_selected; // adopted edges forest\n\n    for (int i = 0; i < M; ++i) {\n        int li;\n        if (!(cin >> li)) return 0;\n\n        const Edge& cur = edges[i];\n        int ans = 0;\n\n        // Cycle edges in selected forest are never useful.\n        if (uf_selected.same(cur.u, cur.v)) {\n            ans = 0;\n        } else {\n            // Mandatory check:\n            // Can we reject this edge while keeping possibility to connect?\n            // Need connectivity between cur.u and cur.v using selected + future edges.\n            DSU uf_possible = uf_selected;\n            bool can_reject = false;\n            for (int j = i + 1; j < M; ++j) {\n                uf_possible.unite(edges[j].u, edges[j].v);\n                if (uf_possible.same(cur.u, cur.v)) {\n                    can_reject = true;\n                    break;\n                }\n            }\n\n            if (!can_reject) {\n                ans = 1; // must adopt\n            } else {\n                // Monte Carlo expected completion-cost comparison\n                // gain = cost(reject) - cost(adopt)\n                // adopt if gain >= 0\n                long long gain_sum = 0;\n\n                for (int s = 0; s < MC_SAMPLES; ++s) {\n                    // Reject case\n                    DSU uf_rej = uf_selected;\n                    long long cost_rej = 0;\n                    for (const auto& se : scenarios[s]) {\n                        if (se.idx <= i) continue; // only future edges\n                        if (uf_rej.unite(se.u, se.v)) {\n                            cost_rej += se.w;\n                            if (uf_rej.comps == 1) break;\n                        }\n                    }\n\n                    // Adopt case\n                    DSU uf_acc = uf_selected;\n                    uf_acc.unite(cur.u, cur.v); // forced adoption\n                    long long cost_acc = li;\n                    for (const auto& se : scenarios[s]) {\n                        if (se.idx <= i) continue; // only future edges\n                        if (uf_acc.unite(se.u, se.v)) {\n                            cost_acc += se.w;\n                            if (uf_acc.comps == 1) break;\n                        }\n                    }\n\n                    gain_sum += (cost_rej - cost_acc);\n                }\n\n                ans = (gain_sum >= 0 ? 1 : 0);\n            }\n        }\n\n        if (ans == 1) {\n            uf_selected.unite(cur.u, cur.v);\n        }\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int r, c;\n};\nbool operator==(const Pos& a, const Pos& b) { return a.r == b.r && a.c == b.c; }\n\nstatic constexpr int BOARD = 30;\nstatic constexpr int BASE = 31;\nstatic constexpr int SZ = BASE * BASE;\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar MOVE_CH[4] = {'U', 'D', 'L', 'R'};\nchar BUILD_CH[4] = {'u', 'd', 'l', 'r'};\n\ninline bool inBoard(int r, int c) {\n    return 1 <= r && r <= BOARD && 1 <= c && c <= BOARD;\n}\ninline bool inBoard(const Pos& p) { return inBoard(p.r, p.c); }\ninline int pid(int r, int c) { return r * BASE + c; }\ninline int pid(const Pos& p) { return pid(p.r, p.c); }\n\nint manhattan(const Pos& a, const Pos& b) {\n    return abs(a.r - b.r) + abs(a.c - b.c);\n}\nPos moved(const Pos& p, int dir) {\n    return Pos{p.r + DR[dir], p.c + DC[dir]};\n}\nint dirFromUpper(char ch) {\n    if (ch == 'U') return 0;\n    if (ch == 'D') return 1;\n    if (ch == 'L') return 2;\n    if (ch == 'R') return 3;\n    return -1;\n}\nint dirFromLower(char ch) {\n    if (ch == 'u') return 0;\n    if (ch == 'd') return 1;\n    if (ch == 'l') return 2;\n    if (ch == 'r') return 3;\n    return -1;\n}\nchar lowerFromDelta(int dr, int dc) {\n    if (dr == -1 && dc == 0) return 'u';\n    if (dr == 1 && dc == 0) return 'd';\n    if (dr == 0 && dc == -1) return 'l';\n    if (dr == 0 && dc == 1) return 'r';\n    return '.';\n}\n\nstruct WallTask {\n    Pos target;\n    Pos standOut;\n    Pos standIn;\n    char buildOut;\n    char buildIn;\n};\n\nstruct RegionPlan {\n    int corner = 0;  // 0:TL 1:TR 2:BL 3:BR\n    int s = 6;\n    vector<WallTask> tasks;\n    int gateIdx = 0;\n    Pos safeCell{1, 1};\n    Pos decoyCell{30, 30};\n\n    bool inRegion(const Pos& p) const {\n        if (corner == 0) {\n            return (1 <= p.r && p.r <= s && 1 <= p.c && p.c <= s);\n        } else if (corner == 1) {\n            int cL = 31 - s;\n            return (1 <= p.r && p.r <= s && cL <= p.c && p.c <= 30);\n        } else if (corner == 2) {\n            int rT = 31 - s;\n            return (rT <= p.r && p.r <= 30 && 1 <= p.c && p.c <= s);\n        } else {\n            int rT = 31 - s;\n            int cL = 31 - s;\n            return (rT <= p.r && p.r <= 30 && cL <= p.c && p.c <= 30);\n        }\n    }\n};\n\nclass Solver {\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N)) return;\n        pets.resize(N);\n        petType.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> pets[i].r >> pets[i].c >> petType[i];\n        }\n        cin >> M;\n        humans.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> humans[i].r >> humans[i].c;\n        }\n\n        for (int r = 0; r <= BOARD; r++) {\n            for (int c = 0; c <= BOARD; c++) {\n                passable[r][c] = false;\n            }\n        }\n        for (int r = 1; r <= BOARD; r++) {\n            for (int c = 1; c <= BOARD; c++) {\n                passable[r][c] = true;\n            }\n        }\n\n        plan = choosePlan();\n        phase = BUILD;\n        gateCloser = -1;\n\n        for (int turn = 0; turn < 300; turn++) {\n            int humanCnt[31][31]{};\n            int petCnt[31][31]{};\n            buildCounts(humanCnt, petCnt);\n\n            // Phase transitions\n            if (phase == BUILD) {\n                if (remainingNonGateWalls() == 0) {\n                    phase = ENTER;\n                    gateCloser = pickGateCloser();\n                }\n            }\n\n            int insideHum = countInsideHumans();\n            int insidePets = countInsidePets();\n\n            if (phase == ENTER) {\n                if (insideHum == M || (insideHum >= M - 1 && turn >= 200) ||\n                    (insideHum >= M - 1 && insidePets > 0 && turn >= 140)) {\n                    phase = CLOSE;\n                }\n            }\n            if (phase == CLOSE) {\n                const WallTask& gate = plan.tasks[plan.gateIdx];\n                if (!passable[gate.target.r][gate.target.c]) {\n                    phase = DONE;\n                }\n            }\n\n            vector<char> actions = decideActions(turn, humanCnt, petCnt);\n            sanitizeActions(actions, humanCnt, petCnt);\n\n            string out;\n            out.reserve(M);\n            for (char ch : actions) out.push_back(ch);\n            cout << out << endl;  // flush\n\n            applyActions(actions, humanCnt, petCnt);\n\n            vector<string> pMoves(N);\n            for (int i = 0; i < N; i++) {\n                if (!(cin >> pMoves[i])) return;\n            }\n            applyPetMoves(pMoves);\n        }\n    }\n\nprivate:\n    int N = 0, M = 0;\n    vector<Pos> pets;\n    vector<int> petType;\n    vector<Pos> humans;\n    bool passable[31][31]{};\n\n    RegionPlan plan;\n\n    enum Phase { BUILD, ENTER, CLOSE, DONE } phase = BUILD;\n    int gateCloser = -1;\n\n    void buildCounts(int humanCnt[31][31], int petCnt[31][31]) const {\n        for (const auto& h : humans) humanCnt[h.r][h.c]++;\n        for (const auto& p : pets) petCnt[p.r][p.c]++;\n    }\n\n    bool canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const {\n        if (!inBoard(t)) return false;\n        if (humanCnt[t.r][t.c] > 0) return false;\n        if (petCnt[t.r][t.c] > 0) return false;\n        for (int d = 0; d < 4; d++) {\n            int nr = t.r + DR[d];\n            int nc = t.c + DC[d];\n            if (!inBoard(nr, nc)) continue;\n            if (petCnt[nr][nc] > 0) return false;\n        }\n        return true;\n    }\n\n    void runBFS(const Pos& st, array<int, SZ>& dist, array<int, SZ>& first) const {\n        dist.fill(-1);\n        first.fill(-1);\n        queue<Pos> q;\n        dist[pid(st)] = 0;\n        q.push(st);\n\n        while (!q.empty()) {\n            Pos cur = q.front();\n            q.pop();\n            int cid = pid(cur);\n            for (int d = 0; d < 4; d++) {\n                Pos nx{cur.r + DR[d], cur.c + DC[d]};\n                if (!inBoard(nx)) continue;\n                if (!passable[nx.r][nx.c]) continue;\n                int nid = pid(nx);\n                if (dist[nid] != -1) continue;\n                dist[nid] = dist[cid] + 1;\n                if (cur == st)\n                    first[nid] = d;\n                else\n                    first[nid] = first[cid];\n                q.push(nx);\n            }\n        }\n    }\n\n    RegionPlan generatePlan(int corner, int s) const {\n        RegionPlan p;\n        p.corner = corner;\n        p.s = s;\n        p.tasks.clear();\n\n        auto addTask = [&](Pos target, Pos standOut, Pos standIn) {\n            WallTask w;\n            w.target = target;\n            w.standOut = standOut;\n            w.standIn = standIn;\n            w.buildOut = lowerFromDelta(target.r - standOut.r, target.c - standOut.c);\n            w.buildIn = lowerFromDelta(target.r - standIn.r, target.c - standIn.c);\n            p.tasks.push_back(w);\n        };\n\n        Pos gate{-1, -1};\n\n        if (corner == 0) {\n            // TL\n            for (int c = 1; c <= s; c++) {\n                addTask(Pos{s + 1, c}, Pos{s + 2, c}, Pos{s, c});\n            }\n            for (int r = 1; r <= s; r++) {\n                addTask(Pos{r, s + 1}, Pos{r, s + 2}, Pos{r, s});\n            }\n            gate = Pos{s + 1, 1};\n            p.safeCell = Pos{1, 1};\n            p.decoyCell = Pos{30, 30};\n        } else if (corner == 1) {\n            // TR\n            int cL = 30 - s;\n            for (int c = 31 - s; c <= 30; c++) {\n                addTask(Pos{s + 1, c}, Pos{s + 2, c}, Pos{s, c});\n            }\n            for (int r = 1; r <= s; r++) {\n                addTask(Pos{r, cL}, Pos{r, cL - 1}, Pos{r, cL + 1});\n            }\n            gate = Pos{s + 1, 30};\n            p.safeCell = Pos{1, 30};\n            p.decoyCell = Pos{30, 1};\n        } else if (corner == 2) {\n            // BL\n            int rT = 30 - s;\n            for (int c = 1; c <= s; c++) {\n                addTask(Pos{rT, c}, Pos{rT - 1, c}, Pos{rT + 1, c});\n            }\n            for (int r = 31 - s; r <= 30; r++) {\n                addTask(Pos{r, s + 1}, Pos{r, s + 2}, Pos{r, s});\n            }\n            gate = Pos{rT, 1};\n            p.safeCell = Pos{30, 1};\n            p.decoyCell = Pos{1, 30};\n        } else {\n            // BR\n            int rT = 30 - s;\n            int cL = 30 - s;\n            for (int c = 31 - s; c <= 30; c++) {\n                addTask(Pos{rT, c}, Pos{rT - 1, c}, Pos{rT + 1, c});\n            }\n            for (int r = 31 - s; r <= 30; r++) {\n                addTask(Pos{r, cL}, Pos{r, cL - 1}, Pos{r, cL + 1});\n            }\n            gate = Pos{rT, 30};\n            p.safeCell = Pos{30, 30};\n            p.decoyCell = Pos{1, 1};\n        }\n\n        p.gateIdx = 0;\n        for (int i = 0; i < (int)p.tasks.size(); i++) {\n            if (p.tasks[i].target == gate) {\n                p.gateIdx = i;\n                break;\n            }\n        }\n\n        return p;\n    }\n\n    long long evaluatePlan(const RegionPlan& p) const {\n        int inside = 0;\n        int nearBoundary = 0;\n        int nearGate = 0;\n        const Pos gate = p.tasks[p.gateIdx].target;\n\n        for (const auto& pet : pets) {\n            if (p.inRegion(pet)) inside++;\n            bool nb = false;\n            for (const auto& t : p.tasks) {\n                if (manhattan(pet, t.target) <= 1) {\n                    nb = true;\n                    break;\n                }\n            }\n            if (nb) nearBoundary++;\n            if (manhattan(pet, gate) <= 3) nearGate++;\n        }\n\n        long long distHum = 0;\n        Pos gateOut = p.tasks[p.gateIdx].standOut;\n        for (const auto& h : humans) {\n            distHum += manhattan(h, gateOut);\n        }\n\n        long long score = 0;\n        score += 100000000LL * inside;\n        score += 200000LL * nearBoundary;\n        score += 80000LL * nearGate;\n        score += 500LL * distHum;\n        score -= 3000LL * p.s * p.s;\n        return score;\n    }\n\n    RegionPlan choosePlan() const {\n        int sMin = 5;\n        int sMax = min(11, 7 + M / 2);\n\n        long long bestScore = (1LL << 62);\n        RegionPlan bestPlan = generatePlan(0, sMin);\n\n        for (int corner = 0; corner < 4; corner++) {\n            for (int s = sMin; s <= sMax; s++) {\n                RegionPlan cand = generatePlan(corner, s);\n                long long sc = evaluatePlan(cand);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestPlan = cand;\n                }\n            }\n        }\n        return bestPlan;\n    }\n\n    int remainingNonGateWalls() const {\n        int rem = 0;\n        for (int i = 0; i < (int)plan.tasks.size(); i++) {\n            if (i == plan.gateIdx) continue;\n            Pos t = plan.tasks[i].target;\n            if (passable[t.r][t.c]) rem++;\n        }\n        return rem;\n    }\n\n    int countInsideHumans() const {\n        int cnt = 0;\n        for (const auto& h : humans) {\n            if (plan.inRegion(h)) cnt++;\n        }\n        return cnt;\n    }\n\n    int countInsidePets() const {\n        int cnt = 0;\n        for (const auto& p : pets) {\n            if (plan.inRegion(p)) cnt++;\n        }\n        return cnt;\n    }\n\n    int pickGateCloser() const {\n        const Pos standIn = plan.tasks[plan.gateIdx].standIn;\n        int best = 0;\n        int bestD = 1e9;\n        for (int i = 0; i < M; i++) {\n            int d = manhattan(humans[i], standIn);\n            if (d < bestD) {\n                bestD = d;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    vector<char> decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]) {\n        vector<char> act(M, '.');\n\n        const WallTask& gate = plan.tasks[plan.gateIdx];\n\n        if (phase == DONE) {\n            return act;\n        }\n\n        if (phase == BUILD) {\n            vector<int> unfinished;\n            unfinished.reserve(plan.tasks.size());\n            for (int i = 0; i < (int)plan.tasks.size(); i++) {\n                if (i == plan.gateIdx) continue;\n                Pos t = plan.tasks[i].target;\n                if (passable[t.r][t.c]) unfinished.push_back(i);\n            }\n            if (unfinished.empty()) {\n                return act;\n            }\n\n            vector<bool> taskBuildable(plan.tasks.size(), false);\n            for (int idx : unfinished) {\n                taskBuildable[idx] = canBuildCell(plan.tasks[idx].target, humanCnt, petCnt);\n            }\n\n            vector<array<int, SZ>> dists(M), firsts(M);\n            for (int i = 0; i < M; i++) {\n                runBFS(humans[i], dists[i], firsts[i]);\n            }\n\n            bool plannedBuild[31][31]{};\n            vector<int> taskUse(plan.tasks.size(), 0);\n\n            // Immediate build if already at build position.\n            for (int i = 0; i < M; i++) {\n                for (int idx : unfinished) {\n                    const WallTask& t = plan.tasks[idx];\n                    Pos tar = t.target;\n                    if (plannedBuild[tar.r][tar.c]) continue;\n                    if (!taskBuildable[idx]) continue;\n\n                    if (humans[i] == t.standOut) {\n                        act[i] = t.buildOut;\n                        plannedBuild[tar.r][tar.c] = true;\n                        taskUse[idx]++;\n                        break;\n                    }\n                    if (humans[i] == t.standIn) {\n                        act[i] = t.buildIn;\n                        plannedBuild[tar.r][tar.c] = true;\n                        taskUse[idx]++;\n                        break;\n                    }\n                }\n            }\n\n            // Move/build decision for the rest.\n            for (int i = 0; i < M; i++) {\n                if (act[i] != '.') continue;\n\n                int bestCost = 1e9;\n                int bestIdx = -1;\n                int bestMode = 0;  // 0 out, 1 in\n                int bestD = -1;\n\n                for (int idx : unfinished) {\n                    const WallTask& t = plan.tasks[idx];\n                    Pos tar = t.target;\n                    if (plannedBuild[tar.r][tar.c]) continue;\n                    bool buildable = taskBuildable[idx];\n\n                    for (int mode = 0; mode < 2; mode++) {\n                        Pos stand = (mode == 0 ? t.standOut : t.standIn);\n                        int d = dists[i][pid(stand)];\n                        if (d < 0) continue;\n                        if (d == 0 && !buildable) continue;\n\n                        int cost = d * 10 + taskUse[idx] * 25 + (buildable ? 0 : 40) + (mode == 1 ? 2 : 0);\n                        if (cost < bestCost) {\n                            bestCost = cost;\n                            bestIdx = idx;\n                            bestMode = mode;\n                            bestD = d;\n                        }\n                    }\n                }\n\n                if (bestIdx == -1) continue;\n\n                taskUse[bestIdx]++;\n                const WallTask& t = plan.tasks[bestIdx];\n                Pos tar = t.target;\n                bool buildable = taskBuildable[bestIdx];\n                Pos stand = (bestMode == 0 ? t.standOut : t.standIn);\n\n                if (bestD == 0 && buildable && !plannedBuild[tar.r][tar.c]) {\n                    act[i] = (bestMode == 0 ? t.buildOut : t.buildIn);\n                    plannedBuild[tar.r][tar.c] = true;\n                } else if (bestD > 0) {\n                    int fd = firsts[i][pid(stand)];\n                    if (fd >= 0) act[i] = MOVE_CH[fd];\n                }\n            }\n\n            return act;\n        }\n\n        if (phase == ENTER) {\n            vector<array<int, SZ>> dists(M), firsts(M);\n            for (int i = 0; i < M; i++) {\n                runBFS(humans[i], dists[i], firsts[i]);\n            }\n\n            for (int i = 0; i < M; i++) {\n                Pos target = (i == gateCloser ? gate.standIn : plan.safeCell);\n\n                if (humans[i] == target) continue;\n\n                int d = dists[i][pid(target)];\n                if (d > 0) {\n                    int fd = firsts[i][pid(target)];\n                    if (fd >= 0) act[i] = MOVE_CH[fd];\n                } else {\n                    // fallback: approach gate\n                    int dg = dists[i][pid(gate.target)];\n                    if (dg > 0) {\n                        int fd = firsts[i][pid(gate.target)];\n                        if (fd >= 0) act[i] = MOVE_CH[fd];\n                    }\n                }\n            }\n\n            return act;\n        }\n\n        // CLOSE\n        {\n            vector<array<int, SZ>> dists(M), firsts(M);\n            for (int i = 0; i < M; i++) {\n                runBFS(humans[i], dists[i], firsts[i]);\n            }\n\n            int builder = -1;\n            pair<int, int> best = {2, (int)1e9};  // (outsideFlag, dist)\n            for (int i = 0; i < M; i++) {\n                int d = dists[i][pid(gate.standIn)];\n                if (d < 0) continue;\n                int outsideFlag = plan.inRegion(humans[i]) ? 0 : 1;\n                pair<int, int> cand = {outsideFlag, d};\n                if (cand < best) {\n                    best = cand;\n                    builder = i;\n                }\n            }\n\n            if (builder == -1) {\n                return act;\n            }\n\n            for (int i = 0; i < M; i++) {\n                if (i == builder) {\n                    if (humans[i] == gate.standIn) {\n                        if (canBuildCell(gate.target, humanCnt, petCnt)) {\n                            act[i] = gate.buildIn;\n                        }\n                    } else {\n                        int d = dists[i][pid(gate.standIn)];\n                        if (d > 0) {\n                            int fd = firsts[i][pid(gate.standIn)];\n                            if (fd >= 0) act[i] = MOVE_CH[fd];\n                        }\n                    }\n                } else {\n                    bool inside = plan.inRegion(humans[i]);\n                    Pos target = inside ? plan.safeCell : plan.decoyCell;\n                    bool needMove = (!inside) || (humans[i] == gate.target) || (humans[i] == gate.standIn);\n                    if (needMove && !(humans[i] == target)) {\n                        int d = dists[i][pid(target)];\n                        if (d > 0) {\n                            int fd = firsts[i][pid(target)];\n                            if (fd >= 0) act[i] = MOVE_CH[fd];\n                        }\n                    }\n                }\n            }\n\n            return act;\n        }\n    }\n\n    void sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const {\n        bool buildNow[31][31]{};\n\n        // sanitize build actions\n        for (int i = 0; i < M; i++) {\n            int d = dirFromLower(act[i]);\n            if (d == -1) continue;\n            Pos t = moved(humans[i], d);\n            if (inBoard(t) && canBuildCell(t, humanCnt, petCnt)) {\n                buildNow[t.r][t.c] = true;\n            } else {\n                act[i] = '.';\n            }\n        }\n\n        // sanitize move actions\n        for (int i = 0; i < M; i++) {\n            int d = dirFromUpper(act[i]);\n            if (d == -1) continue;\n            Pos to = moved(humans[i], d);\n            if (!inBoard(to) || !passable[to.r][to.c] || buildNow[to.r][to.c]) {\n                act[i] = '.';\n            }\n        }\n    }\n\n    void applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) {\n        bool passBefore[31][31];\n        for (int r = 1; r <= BOARD; r++) {\n            for (int c = 1; c <= BOARD; c++) {\n                passBefore[r][c] = passable[r][c];\n            }\n        }\n\n        bool buildNow[31][31]{};\n        for (int i = 0; i < M; i++) {\n            int d = dirFromLower(act[i]);\n            if (d == -1) continue;\n            Pos t = moved(humans[i], d);\n            if (inBoard(t) && canBuildCell(t, humanCnt, petCnt)) {\n                buildNow[t.r][t.c] = true;\n            }\n        }\n\n        for (int r = 1; r <= BOARD; r++) {\n            for (int c = 1; c <= BOARD; c++) {\n                if (buildNow[r][c]) passable[r][c] = false;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            int d = dirFromUpper(act[i]);\n            if (d == -1) continue;\n            Pos to = moved(humans[i], d);\n            if (!inBoard(to)) continue;\n            if (!passBefore[to.r][to.c]) continue;\n            if (buildNow[to.r][to.c]) continue;\n            humans[i] = to;\n        }\n    }\n\n    void applyPetMoves(const vector<string>& pMoves) {\n        for (int i = 0; i < N; i++) {\n            const string& s = pMoves[i];\n            if (s == \".\") continue;\n            for (char ch : s) {\n                int d = dirFromUpper(ch);\n                if (d == -1) continue;\n                pets[i].r += DR[d];\n                pets[i].c += DC[d];\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    static constexpr int H = 20;\n    static constexpr int W = 20;\n    static constexpr int N = H * W;\n    static constexpr int L = 200;\n\n    int si, sj, ti, tj;\n    int start, target;\n    double p, q;\n\n    string h[H];\n    string v[H - 1];\n\n    int to_raw[N][4];\n    int to_eval[N][4];\n\n    vector<array<double, N>> fw, bw;\n    array<double, L + 1> pref{};\n\n    vector<uint8_t> seq, bestSeq;\n    double curScore = -1e100, bestScore = -1e100;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\n    Solver()\n        : fw(L + 1), bw(L + 1), seq(L), bestSeq(L),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline int id(int i, int j) const { return i * W + j; }\n\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void readInput() {\n        cin >> si >> sj >> ti >> tj >> p;\n        for (int i = 0; i < H; i++) cin >> h[i];\n        for (int i = 0; i < H - 1; i++) cin >> v[i];\n        start = id(si, sj);\n        target = id(ti, tj);\n        q = 1.0 - p;\n    }\n\n    void buildTransitions() {\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                int s = id(i, j);\n\n                // U\n                if (i == 0 || v[i - 1][j] == '1') to_raw[s][0] = s;\n                else to_raw[s][0] = id(i - 1, j);\n\n                // D\n                if (i == H - 1 || v[i][j] == '1') to_raw[s][1] = s;\n                else to_raw[s][1] = id(i + 1, j);\n\n                // L\n                if (j == 0 || h[i][j - 1] == '1') to_raw[s][2] = s;\n                else to_raw[s][2] = id(i, j - 1);\n\n                // R\n                if (j == W - 1 || h[i][j] == '1') to_raw[s][3] = s;\n                else to_raw[s][3] = id(i, j + 1);\n            }\n        }\n\n        for (int s = 0; s < N; s++) {\n            for (int a = 0; a < 4; a++) to_eval[s][a] = to_raw[s][a];\n        }\n        // absorbing target\n        for (int a = 0; a < 4; a++) to_eval[target][a] = target;\n    }\n\n    vector<int> shortestPathBFS() {\n        vector<int> dist(N, -1), par(N, -1), parDir(N, -1);\n        queue<int> qu;\n        dist[start] = 0;\n        qu.push(start);\n\n        // Prefer D,R first for tie-break.\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            if (s == target) break;\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (dist[n] != -1) continue;\n                dist[n] = dist[s] + 1;\n                par[n] = s;\n                parDir[n] = a;\n                qu.push(n);\n            }\n        }\n\n        vector<int> path;\n        if (dist[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(parDir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> weightedPath(double penUL) {\n        const double INF = 1e100;\n        vector<double> dist(N, INF);\n        vector<int> par(N, -1), parDir(N, -1);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!pq.empty()) {\n            auto [d, s] = pq.top();\n            pq.pop();\n            if (d > dist[s]) continue;\n            if (s == target) break;\n\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                double w = 1.0 + ((a == 0 || a == 2) ? penUL : 0.0);\n                double nd = d + w;\n                if (nd < dist[n]) {\n                    dist[n] = nd;\n                    par[n] = s;\n                    parDir[n] = a;\n                    pq.push({nd, n});\n                }\n            }\n        }\n\n        vector<int> path;\n        if (par[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(parDir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> distToTarget() {\n        const int INF = 1e9;\n        vector<int> d(N, INF);\n        queue<int> qu;\n        d[target] = 0;\n        qu.push(target);\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            for (int a = 0; a < 4; a++) {\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (d[n] > d[s] + 1) {\n                    d[n] = d[s] + 1;\n                    qu.push(n);\n                }\n            }\n        }\n        return d;\n    }\n\n    vector<uint8_t> makeFromBase(const vector<int>& base) {\n        vector<uint8_t> res(L);\n        if (base.empty()) {\n            for (int i = 0; i < L; i++) res[i] = (uint8_t)rng.nextInt(4);\n            return res;\n        }\n        if ((int)base.size() >= L) {\n            for (int i = 0; i < L; i++) res[i] = (uint8_t)base[i];\n        } else {\n            for (int i = 0; i < L; i++) res[i] = (uint8_t)base[i % (int)base.size()];\n        }\n        return res;\n    }\n\n    vector<uint8_t> makeFromBaseRepeatEach(const vector<int>& base, int rep) {\n        if (base.empty()) return makeFromBase(base);\n        vector<int> ex;\n        ex.reserve((int)base.size() * rep);\n        for (int d : base) for (int k = 0; k < rep; k++) ex.push_back(d);\n        return makeFromBase(ex);\n    }\n\n    vector<uint8_t> makeGreedy(const vector<double>& value) {\n        vector<uint8_t> res(L);\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int bestA = 0;\n            double bestV = -1e100;\n\n            for (int a = 0; a < 4; a++) {\n                double vexp = 0.0;\n                for (int s = 0; s < N; s++) {\n                    double pr = cur[s];\n                    if (pr == 0.0) continue;\n                    int n = to_eval[s][a];\n                    if (n == s) {\n                        vexp += pr * value[s];\n                    } else {\n                        vexp += pr * (p * value[s] + q * value[n]);\n                    }\n                }\n                if (vexp > bestV) {\n                    bestV = vexp;\n                    bestA = a;\n                }\n            }\n\n            res[t] = (uint8_t)bestA;\n\n            nxt.fill(0.0);\n            for (int s = 0; s < N; s++) {\n                double pr = cur[s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][bestA];\n                if (n == s) {\n                    nxt[s] += pr;\n                } else {\n                    double mv = pr * q;\n                    nxt[n] += mv;\n                    nxt[s] += pr - mv;\n                }\n            }\n            cur = nxt;\n        }\n\n        return res;\n    }\n\n    double recompute() {\n        fw[0].fill(0.0);\n        fw[0][start] = 1.0;\n        pref[0] = 0.0;\n\n        for (int t = 0; t < L; t++) {\n            fw[t + 1].fill(0.0);\n            int a = seq[t];\n            for (int s = 0; s < N; s++) {\n                double pr = fw[t][s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                if (n == s) {\n                    fw[t + 1][s] += pr;\n                } else {\n                    double mv = pr * q;\n                    fw[t + 1][n] += mv;\n                    fw[t + 1][s] += pr - mv;\n                }\n            }\n            int coef = (t + 1 == L ? 201 : 1);\n            pref[t + 1] = pref[t] + coef * fw[t + 1][target];\n        }\n\n        bw[L].fill(0.0);\n        for (int t = L - 1; t >= 0; t--) {\n            int a = seq[t];\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                int n = to_eval[s][a];\n                if (n == s) {\n                    bw[t][s] = bw[t + 1][s] + (s == target ? (double)coef : 0.0);\n                } else {\n                    bw[t][s] = p * bw[t + 1][s] + q * (bw[t + 1][n] + (n == target ? (double)coef : 0.0));\n                }\n            }\n        }\n\n        return pref[L];\n    }\n\n    double evalChange(int pos, int act) const {\n        double total = pref[pos];\n        int coef = (pos + 1 == L ? 201 : 1);\n\n        const auto& dist = fw[pos];\n        const auto& suf = bw[pos + 1];\n\n        for (int s = 0; s < N; s++) {\n            double pr = dist[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][act];\n            double v;\n            if (n == s) {\n                v = suf[s] + (s == target ? (double)coef : 0.0);\n            } else {\n                v = p * suf[s] + q * (suf[n] + (n == target ? (double)coef : 0.0));\n            }\n            total += pr * v;\n        }\n\n        return total;\n    }\n\n    void improve(double deadline) {\n        array<int, L> ord;\n        iota(ord.begin(), ord.end(), 0);\n\n        while (now() < deadline) {\n            bool improved = false;\n\n            for (int i = L - 1; i > 0; i--) {\n                int j = rng.nextInt(i + 1);\n                swap(ord[i], ord[j]);\n            }\n\n            for (int ii = 0; ii < L; ii++) {\n                if (now() >= deadline) return;\n                int pos = ord[ii];\n\n                int curA = seq[pos];\n                int bestA = curA;\n                double localBest = curScore;\n\n                for (int a = 0; a < 4; a++) {\n                    double sc = evalChange(pos, a);\n                    if (sc > localBest + 1e-12) {\n                        localBest = sc;\n                        bestA = a;\n                    }\n                }\n\n                if (bestA != curA) {\n                    seq[pos] = (uint8_t)bestA;\n                    curScore = recompute();\n                    improved = true;\n\n                    if (curScore > bestScore) {\n                        bestScore = curScore;\n                        bestSeq = seq;\n                    }\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    void solve() {\n        readInput();\n        buildTransitions();\n        st = chrono::steady_clock::now();\n\n        auto path1 = shortestPathBFS();\n        auto path2 = weightedPath(0.7);\n        auto d = distToTarget();\n\n        int rep = (int)llround(1.0 / max(1e-9, q));\n        rep = max(1, min(6, rep));\n\n        vector<vector<uint8_t>> cands;\n        cands.push_back(makeFromBase(path1));\n        cands.push_back(makeFromBaseRepeatEach(path1, rep));\n        cands.push_back(makeFromBaseRepeatEach(path1, min(6, rep + 1)));\n        if (!path2.empty()) {\n            cands.push_back(makeFromBase(path2));\n            cands.push_back(makeFromBaseRepeatEach(path2, rep));\n        }\n\n        vector<double> val1(N), val2(N), val3(N);\n        for (int s = 0; s < N; s++) {\n            int ds = d[s];\n            val1[s] = -1.0 * ds;\n            val2[s] = -1.0 * ds * ds;\n            val3[s] = exp(-0.20 * ds);\n        }\n        cands.push_back(makeGreedy(val1));\n        cands.push_back(makeGreedy(val2));\n        cands.push_back(makeGreedy(val3));\n\n        // Simple backup patterns\n        vector<uint8_t> pat(L);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 1 : 3); // D then R\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 3 : 1); // R then D\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i & 1 ? 3 : 1); // D,R,D,R,...\n        cands.push_back(pat);\n\n        bestScore = -1e100;\n        for (auto &cand : cands) {\n            seq = cand;\n            curScore = recompute();\n            if (curScore > bestScore) {\n                bestScore = curScore;\n                bestSeq = seq;\n            }\n        }\n\n        seq = bestSeq;\n        curScore = recompute();\n\n        const double TL = 1.85;\n\n        // First local optimization from best seed.\n        improve(min(TL, 0.60));\n\n        // Iterated local search: perturb + local optimize.\n        while (now() < TL) {\n            seq = bestSeq;\n\n            int r = rng.nextInt(100);\n            int m = (r < 75 ? (1 + rng.nextInt(3)) : (3 + rng.nextInt(10)));\n\n            for (int i = 0; i < m; i++) {\n                int pos = rng.nextInt(L);\n                seq[pos] = (uint8_t)rng.nextInt(4);\n            }\n\n            curScore = recompute();\n\n            double rem = TL - now();\n            if (rem <= 0.0) break;\n            double budget = min(0.05, rem * 0.8);\n            improve(now() + budget);\n        }\n\n        // Final polish from best found.\n        seq = bestSeq;\n        curScore = recompute();\n        improve(TL);\n\n        const char mp[4] = {'U', 'D', 'L', 'R'};\n        string ans(L, 'U');\n        for (int i = 0; i < L; i++) ans[i] = mp[bestSeq[i]];\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}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int C = N * N;\nstatic constexpr int S = C * 4;\n\nint 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\nuint8_t SIDE[8] = {\n    (1 << 0) | (1 << 1), // 0\n    (1 << 0) | (1 << 3), // 1\n    (1 << 2) | (1 << 3), // 2\n    (1 << 1) | (1 << 2), // 3\n    0b1111,              // 4\n    0b1111,              // 5\n    (1 << 0) | (1 << 2), // 6\n    (1 << 1) | (1 << 3), // 7\n};\n\nint ROT1[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nint ROT[8][4];\nint NEI[C][4];\nint OPP[4] = {2, 3, 0, 1};\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463393265ull) {\n        x = seed ^ 0x9e3779b97f4a7c15ULL;\n        if (x == 0) x = 88172645463393265ull;\n        for (int i = 0; i < 10; i++) next_u64();\n    }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t next_u32() { return static_cast<uint32_t>(next_u64()); }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstruct Eval {\n    int l1 = 0;\n    int l2 = 0;\n    int loopCnt = 0;\n    int sumLoop = 0;\n    int matched = 0;\n    long long contest = 0;\n    double obj = -1e100;\n};\n\ninline bool better(const Eval& a, const Eval& b) {\n    if (a.contest != b.contest) return a.contest > b.contest;\n    return a.obj > b.obj;\n}\n\nstruct Evaluator {\n    int nxt[S];\n    int partner[S];\n    int visTag[S];\n    int visPos[S];\n    int stk[S];\n    uint8_t done[S];\n\n    Eval eval(const array<uint8_t, C>& board) {\n        int matched = 0;\n\n        // Internal matched boundaries (auxiliary metric).\n        for (int i = 0; i < N; i++) {\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                int c = base + j;\n                uint8_t m = SIDE[board[c]];\n                if (j + 1 < N) {\n                    if ((m & (1 << 2)) && (SIDE[board[c + 1]] & (1 << 0))) matched++;\n                }\n                if (i + 1 < N) {\n                    if ((m & (1 << 3)) && (SIDE[board[c + N]] & (1 << 1))) matched++;\n                }\n            }\n        }\n\n        // Build deterministic transition graph on 3600 states.\n        for (int c = 0; c < C; c++) {\n            int t = board[c];\n            int c4 = c << 2;\n            for (int d = 0; d < 4; d++) {\n                int s = c4 | d;\n                int d2 = TO[t][d];\n                if (d2 < 0) {\n                    nxt[s] = -1;\n                    partner[s] = -1;\n                    continue;\n                }\n                partner[s] = c4 | d2;\n\n                int nc = NEI[c][d2];\n                if (nc < 0) {\n                    nxt[s] = -1;\n                    continue;\n                }\n                if (SIDE[board[nc]] & (1 << OPP[d2])) {\n                    nxt[s] = (nc << 2) | OPP[d2];\n                } else {\n                    nxt[s] = -1;\n                }\n            }\n        }\n\n        memset(done, 0, sizeof(done));\n        memset(visTag, 0, sizeof(visTag));\n\n        int iter = 1;\n        int loopCnt = 0;\n        int sumLoop = 0;\n        int l1 = 0, l2 = 0;\n\n        // Functional graph decomposition.\n        for (int s0 = 0; s0 < S; s0++) {\n            if (done[s0]) continue;\n\n            int cur = s0;\n            int top = 0;\n            while (cur != -1 && !done[cur] && visTag[cur] != iter) {\n                visTag[cur] = iter;\n                visPos[cur] = top;\n                stk[top++] = cur;\n                cur = nxt[cur];\n            }\n\n            if (cur != -1 && !done[cur] && visTag[cur] == iter) {\n                int st = visPos[cur];\n                int len = top - st;\n\n                // Undirected loop dedup:\n                // one physical loop => two directed cycles (forward/backward).\n                int mn1 = INT_MAX, mn2 = INT_MAX;\n                for (int k = st; k < top; k++) {\n                    int v = stk[k];\n                    mn1 = min(mn1, v);\n                    mn2 = min(mn2, partner[v]);\n                }\n                if (mn1 < mn2) {\n                    loopCnt++;\n                    sumLoop += len;\n                    if (len > l1) {\n                        l2 = l1;\n                        l1 = len;\n                    } else if (len > l2) {\n                        l2 = len;\n                    }\n                }\n            }\n\n            for (int k = 0; k < top; k++) done[stk[k]] = 1;\n            iter++;\n        }\n\n        long long contest = (loopCnt >= 2 ? 1LL * l1 * l2 : 0LL);\n        int effL2 = (loopCnt >= 2 ? l2 : 0);\n\n        // Smoothed objective for SA; final best is still contest-first.\n        double obj = sqrt((double)contest + 1.0)\n                   + 0.02 * effL2\n                   + 0.005 * l1\n                   + 0.001 * sumLoop\n                   + 0.0002 * matched;\n\n        Eval e;\n        e.l1 = l1;\n        e.l2 = effL2;\n        e.loopCnt = loopCnt;\n        e.sumLoop = sumLoop;\n        e.matched = matched;\n        e.contest = contest;\n        e.obj = obj;\n        return e;\n    }\n};\n\ninline int local_potential(int c, uint8_t cand, const array<uint8_t, C>& board) {\n    int score = 0;\n    uint8_t m = SIDE[cand];\n\n    // Side match / open-end penalties.\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) score -= 3;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 && b2) score += 3;\n            else if (b1 ^ b2) score -= 2;\n        }\n    }\n\n    // Transition validity term (helps orient 4/5 and 6/7).\n    for (int d = 0; d < 4; d++) {\n        int d2 = TO[cand][d];\n        if (d2 < 0) continue;\n        int nc = NEI[c][d2];\n        if (nc >= 0 && (SIDE[board[nc]] & (1 << OPP[d2]))) score += 1;\n        else score -= 1;\n    }\n\n    return score;\n}\n\nvoid improve_connectivity(\n    array<uint8_t, C>& board,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng,\n    int passes\n) {\n    array<int, C> ord;\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int p = 0; p < passes; p++) {\n        for (int i = C - 1; i > 0; i--) {\n            int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n            swap(ord[i], ord[j]);\n        }\n\n        for (int idx = 0; idx < C; idx++) {\n            int c = ord[idx];\n            int bestScore = INT_MIN;\n            uint8_t bestState = board[c];\n\n            for (int k = 0; k < possCnt[c]; k++) {\n                uint8_t cand = poss[c][k];\n                int sc = local_potential(c, cand, board);\n                if (sc > bestScore || (sc == bestScore && (rng.next_u32() & 1))) {\n                    bestScore = sc;\n                    bestState = cand;\n                }\n            }\n            board[c] = bestState;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Precompute rotations.\n    for (int t = 0; t < 8; t++) {\n        ROT[t][0] = t;\n        for (int k = 1; k < 4; k++) ROT[t][k] = ROT1[ROT[t][k - 1]];\n    }\n\n    // Precompute neighbors.\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = i * N + j;\n            NEI[c][0] = (j > 0 ? c - 1 : -1);\n            NEI[c][1] = (i > 0 ? c - N : -1);\n            NEI[c][2] = (j + 1 < N ? c + 1 : -1);\n            NEI[c][3] = (i + 1 < N ? c + N : -1);\n        }\n    }\n\n    array<uint8_t, C> orig{};\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            orig[i * N + j] = (uint8_t)(s[j] - '0');\n        }\n    }\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)(uintptr_t)&seed;\n    RNG rng(seed);\n\n    auto startTime = chrono::steady_clock::now();\n    const double TL = 1.92;\n\n    // Candidate states for each cell.\n    array<array<uint8_t, 4>, C> poss{};\n    array<uint8_t, C> possCnt{};\n    for (int c = 0; c < C; c++) {\n        int t = orig[c];\n        if (t <= 3) {\n            possCnt[c] = 4;\n            for (int k = 0; k < 4; k++) poss[c][k] = (uint8_t)ROT[t][k];\n        } else if (t <= 5) {\n            possCnt[c] = 2;\n            poss[c][0] = 4;\n            poss[c][1] = 5;\n        } else {\n            possCnt[c] = 2;\n            poss[c][0] = 6;\n            poss[c][1] = 7;\n        }\n    }\n\n    Evaluator evaluator;\n\n    // Multistart initialization.\n    Eval bestEval;\n    bestEval.contest = -1;\n    bestEval.obj = -1e100;\n    array<uint8_t, C> bestState = orig;\n\n    const int INIT_TRIALS = 6;\n    for (int tr = 0; tr < INIT_TRIALS; tr++) {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        if (elapsed > 0.35) break; // reserve time for SA\n\n        array<uint8_t, C> cand;\n        if (tr == 0) {\n            cand = orig;\n        } else {\n            for (int c = 0; c < C; c++) {\n                if (possCnt[c] == 4) cand[c] = poss[c][rng.next_u32() & 3];\n                else cand[c] = poss[c][rng.next_u32() & 1];\n            }\n        }\n\n        improve_connectivity(cand, poss, possCnt, rng, (tr == 0 ? 8 : 6));\n        Eval e = evaluator.eval(cand);\n        if (better(e, bestEval)) {\n            bestEval = e;\n            bestState = cand;\n        }\n    }\n\n    array<uint8_t, C> curState = bestState;\n    Eval curEval = bestEval;\n\n    long long iter = 0;\n    long long lastBestIter = 0;\n    long long lastShakeIter = 0;\n\n    const double T0 = 4.0;\n    const double T1 = 0.01;\n    double temp = T0;\n\n    // Simulated annealing.\n    while (true) {\n        if ((iter & 127LL) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= TL) break;\n\n            double progress = elapsed / TL;\n            temp = T0 * pow(T1 / T0, progress);\n\n            // Occasional kick.\n            if (iter - lastBestIter > 7000 && iter - lastShakeIter > 3000) {\n                curState = bestState;\n                for (int s = 0; s < 24; s++) {\n                    int c = (int)(rng.next_u32() % C);\n                    if (possCnt[c] == 4) {\n                        uint8_t old = curState[c];\n                        uint8_t ns = old;\n                        do ns = poss[c][rng.next_u32() & 3];\n                        while (ns == old);\n                        curState[c] = ns;\n                    } else {\n                        curState[c] = (curState[c] == poss[c][0] ? poss[c][1] : poss[c][0]);\n                    }\n                }\n                curEval = evaluator.eval(curState);\n                lastShakeIter = iter;\n            }\n        }\n\n        int moveType = (int)(rng.next_u32() % 100);\n\n        if (moveType < 88) {\n            // Single tile.\n            int c = (int)(rng.next_u32() % C);\n            uint8_t old = curState[c];\n            uint8_t nw = old;\n\n            if (possCnt[c] == 4) {\n                do nw = poss[c][rng.next_u32() & 3];\n                while (nw == old);\n            } else {\n                nw = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n            }\n\n            curState[c] = nw;\n            Eval ne = evaluator.eval(curState);\n\n            double diff = ne.obj - curEval.obj;\n            bool accept = (diff >= 0.0) || (rng.next_double() < exp(diff / temp));\n\n            if (accept) {\n                curEval = ne;\n                if (better(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    lastBestIter = iter;\n                }\n            } else {\n                curState[c] = old;\n            }\n        } else {\n            // 2x2 rotate move.\n            int i = (int)(rng.next_u32() % (N - 1));\n            int j = (int)(rng.next_u32() % (N - 1));\n            int c0 = i * N + j;\n\n            int cells[4] = {c0, c0 + 1, c0 + N, c0 + N + 1};\n            uint8_t old[4] = {\n                curState[cells[0]],\n                curState[cells[1]],\n                curState[cells[2]],\n                curState[cells[3]]\n            };\n\n            int delta = (rng.next_u32() & 1) ? 1 : 3; // odd -> flip 2-period tiles\n            for (int k = 0; k < 4; k++) {\n                curState[cells[k]] = (uint8_t)ROT[curState[cells[k]]][delta];\n            }\n\n            Eval ne = evaluator.eval(curState);\n            double diff = ne.obj - curEval.obj;\n            bool accept = (diff >= 0.0) || (rng.next_double() < exp(diff / temp));\n\n            if (accept) {\n                curEval = ne;\n                if (better(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    lastBestIter = iter;\n                }\n            } else {\n                for (int k = 0; k < 4; k++) curState[cells[k]] = old[k];\n            }\n        }\n\n        iter++;\n    }\n\n    // Convert final states to rotation counts from original.\n    string ans(C, '0');\n    for (int c = 0; c < C; c++) {\n        int o = orig[c];\n        int f = bestState[c];\n        int rot = 0;\n        for (; rot < 4; rot++) {\n            if (ROT[o][rot] == f) break;\n        }\n        if (rot == 4) rot = 0; // should not happen\n        ans[c] = char('0' + rot);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N_global, T_global, NN_global, FULLV;\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};\n\nuint64_t splitmix64(uint64_t &x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n    return z ^ (z >> 31);\n}\n\nstruct AdjEdge {\n    uint8_t u, v;\n    uint8_t mu, mv;\n};\n\nvector<AdjEdge> g_edges;\nuint64_t zobrist[100][16];\n\nconst int DR[4] = {-1, 1, 0, 0}; // blank movement for U,D,L,R\nconst int DC[4] = {0, 0, -1, 1};\nconst char OP[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\ninline int uf_find(int x, int parent[]) {\n    while (parent[x] != x) {\n        parent[x] = parent[parent[x]];\n        x = parent[x];\n    }\n    return x;\n}\n\nstruct EvalInfo {\n    int S = 0;            // largest tree component size\n    int cmax = 0;         // largest connected component size\n    int cmaxEx = 0;       // cycle excess of largest connected component\n    int potential = 0;    // max(v - cycleW * excess)\n    int totalEdges = 0;\n    int totalExcess = 0;\n    long long key = LLONG_MIN;\n};\n\nEvalInfo evaluate_state(const array<uint8_t, 100> &b, int cycleW) {\n    int parent[100];\n    int sz[100];\n    int ed[100];\n\n    for (int i = 0; i < NN_global; i++) {\n        if (b[i] != 0) {\n            parent[i] = i;\n            sz[i] = 1;\n            ed[i] = 0;\n        } else {\n            parent[i] = -1;\n        }\n    }\n\n    for (const auto &e : g_edges) {\n        uint8_t a = b[e.u];\n        uint8_t c = b[e.v];\n        if (a != 0 && c != 0 && (a & e.mu) && (c & e.mv)) {\n            int ra = uf_find((int)e.u, parent);\n            int rb = uf_find((int)e.v, parent);\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\n    EvalInfo r;\n    bool first = true;\n    for (int i = 0; i < NN_global; i++) {\n        if (parent[i] == i) {\n            int v = sz[i];\n            int e = ed[i];\n            int ex = e - (v - 1);\n\n            if (ex == 0) r.S = max(r.S, v);\n            r.totalEdges += e;\n            if (ex > 0) r.totalExcess += ex;\n\n            int p = v - cycleW * ex;\n            r.potential = max(r.potential, p);\n\n            if (first || v > r.cmax || (v == r.cmax && ex < r.cmaxEx)) {\n                r.cmax = v;\n                r.cmaxEx = ex;\n                first = false;\n            }\n        }\n    }\n\n    if (r.S == 0) r.S = 1;\n    if (r.potential < 0) r.potential = 0;\n\n    // Beam priority key (heuristic)\n    r.key = 400000LL * r.potential\n          + 100000LL * r.S\n          +   1000LL * r.cmax\n          -   8000LL * r.cmaxEx\n          +     20LL * r.totalEdges\n          -   1000LL * r.totalExcess;\n    return r;\n}\n\nuint64_t compute_hash(const array<uint8_t, 100> &b) {\n    uint64_t h = 0;\n    for (int i = 0; i < NN_global; i++) h ^= zobrist[i][b[i]];\n    return h;\n}\n\nstruct Node {\n    array<uint8_t, 100> b{};\n    uint16_t blank = 0;\n    int parent = -1;\n    int depth = 0;\n    uint8_t lastDir = 4; // 0..3 or 4=none\n    char mv = '?';\n\n    int S = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN; // key + random jitter\n    uint64_t hash = 0;\n};\n\nbool better_node(const Node &a, const Node &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.depth != b.depth) return a.depth < b.depth;\n    if (a.key != b.key) return a.key > b.key;\n    return a.depth < b.depth;\n}\n\nstruct SearchResult {\n    string path;\n    array<uint8_t, 100> board{};\n    int blank = 0;\n    int lastDir = 4;\n    int S = 0;\n    long long key = LLONG_MIN;\n};\n\nbool better_result(const SearchResult &a, const SearchResult &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    if (a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    return a.key > b.key;\n}\n\nSearchResult run_beam(\n    const array<uint8_t, 100> &initBoard,\n    int initBlank,\n    int width,\n    int cycleW,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng\n) {\n    vector<Node> nodes;\n    nodes.reserve((size_t)width * (size_t)T_global * 3 + 1024);\n\n    Node root;\n    root.b = initBoard;\n    root.blank = (uint16_t)initBlank;\n    root.parent = -1;\n    root.depth = 0;\n    root.lastDir = 4;\n    root.mv = '?';\n    root.hash = compute_hash(root.b);\n    {\n        EvalInfo e0 = evaluate_state(root.b, cycleW);\n        root.S = e0.S;\n        root.key = e0.key;\n        root.pri = e0.key;\n    }\n    nodes.push_back(root);\n\n    int bestId = 0;\n\n    vector<int> beam, nextBeam, cand;\n    beam.reserve(width);\n    nextBeam.reserve(width);\n    cand.reserve(width * 4 + 8);\n    beam.push_back(0);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(width * 8 + 16);\n\n    for (int depth = 0; depth < T_global; depth++) {\n        if ((depth & 7) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        cand.clear();\n        bool timeout = false;\n\n        for (int bi = 0; bi < (int)beam.size(); bi++) {\n            if ((bi & 31) == 0 && chrono::steady_clock::now() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int id = beam[bi];\n            const Node &cur = nodes[id];\n            int br = cur.blank / N_global;\n            int bc = cur.blank % N_global;\n\n            for (int d = 0; d < 4; d++) {\n                if (cur.lastDir < 4 && d == OPP[cur.lastDir]) continue;\n\n                int nr = br + DR[d];\n                int nc = bc + DC[d];\n                if ((unsigned)nr >= (unsigned)N_global || (unsigned)nc >= (unsigned)N_global) continue;\n\n                int nb = nr * N_global + nc;\n\n                Node child;\n                child.b = cur.b;\n                uint8_t tile = child.b[nb];\n                child.b[cur.blank] = tile;\n                child.b[nb] = 0;\n\n                child.blank = (uint16_t)nb;\n                child.parent = id;\n                child.depth = cur.depth + 1;\n                child.lastDir = (uint8_t)d;\n                child.mv = OP[d];\n\n                child.hash = cur.hash\n                           ^ zobrist[cur.blank][0]\n                           ^ zobrist[cur.blank][tile]\n                           ^ zobrist[nb][tile]\n                           ^ zobrist[nb][0];\n\n                EvalInfo ec = evaluate_state(child.b, cycleW);\n                child.S = ec.S;\n                child.key = ec.key;\n                child.pri = ec.key * 1024LL + (long long)(rng.next() & 1023ULL);\n\n                nodes.push_back(std::move(child));\n                int nid = (int)nodes.size() - 1;\n                cand.push_back(nid);\n\n                if (better_node(nodes[nid], nodes[bestId])) bestId = nid;\n            }\n        }\n\n        if (timeout || cand.empty()) break;\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            if (nodes[a].pri != nodes[b].pri) return nodes[a].pri > nodes[b].pri;\n            return nodes[a].key > nodes[b].key;\n        });\n\n        nextBeam.clear();\n        seen.clear();\n\n        for (int id : cand) {\n            uint64_t key = nodes[id].hash ^ (0x9e3779b97f4a7c15ull * (uint64_t)(nodes[id].lastDir + 1));\n            if (seen.insert(key).second) {\n                nextBeam.push_back(id);\n                if ((int)nextBeam.size() >= width) break;\n            }\n        }\n\n        if (nextBeam.empty()) break;\n        beam.swap(nextBeam);\n\n        if (nodes[bestId].S == FULLV) break;\n    }\n\n    SearchResult res;\n    res.S = nodes[bestId].S;\n    res.key = nodes[bestId].key;\n    res.board = nodes[bestId].b;\n    res.blank = nodes[bestId].blank;\n    res.lastDir = nodes[bestId].lastDir;\n\n    string p;\n    for (int cur = bestId; nodes[cur].parent != -1; cur = nodes[cur].parent) {\n        p.push_back(nodes[cur].mv);\n    }\n    reverse(p.begin(), p.end());\n    res.path = std::move(p);\n\n    return res;\n}\n\nSearchResult greedy_polish(\n    const SearchResult &base,\n    int cycleW,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng\n) {\n    SearchResult best = base;\n    if (best.S == FULLV) return best;\n\n    array<uint8_t, 100> board = base.board;\n    int blank = base.blank;\n    int lastDir = base.lastDir;\n    string curPath = base.path;\n\n    for (int step = (int)curPath.size(); step < T_global; step++) {\n        if ((step & 31) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        int br = blank / N_global;\n        int bc = blank % N_global;\n\n        long long bestVal = LLONG_MIN;\n        int bestDir = -1;\n        int bestNb = -1;\n        EvalInfo bestEi;\n        array<uint8_t, 100> bestBoard{};\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n\n            int nr = br + DR[d];\n            int nc = bc + DC[d];\n            if ((unsigned)nr >= (unsigned)N_global || (unsigned)nc >= (unsigned)N_global) continue;\n\n            int nb = nr * N_global + nc;\n\n            array<uint8_t, 100> nbBoard = board;\n            uint8_t tile = nbBoard[nb];\n            nbBoard[blank] = tile;\n            nbBoard[nb] = 0;\n\n            EvalInfo ei = evaluate_state(nbBoard, cycleW);\n            long long val = (long long)ei.S * 1'000'000'000LL + ei.key + (long long)(rng.next() & 1023ULL);\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestDir = d;\n                bestNb = nb;\n                bestEi = ei;\n                bestBoard = nbBoard;\n            }\n        }\n\n        if (bestDir == -1) break;\n\n        board = bestBoard;\n        blank = bestNb;\n        lastDir = bestDir;\n        curPath.push_back(OP[bestDir]);\n\n        if (bestEi.S > best.S || (bestEi.S == FULLV && (int)curPath.size() < (int)best.path.size())) {\n            best.S = bestEi.S;\n            best.key = bestEi.key;\n            best.board = board;\n            best.blank = blank;\n            best.lastDir = lastDir;\n            best.path = curPath;\n            if (best.S == FULLV) break;\n        }\n    }\n\n    return best;\n}\n\nint hex_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N_global >> T_global;\n    NN_global = N_global * N_global;\n    FULLV = NN_global - 1;\n\n    array<uint8_t, 100> init{};\n    int blank = -1;\n\n    for (int i = 0; i < N_global; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N_global; j++) {\n            int v = hex_to_int(s[j]);\n            init[i * N_global + j] = (uint8_t)v;\n            if (v == 0) blank = i * N_global + j;\n        }\n    }\n\n    g_edges.clear();\n    g_edges.reserve(2 * N_global * (N_global - 1));\n    for (int i = 0; i < N_global; i++) {\n        for (int j = 0; j < N_global; j++) {\n            int id = i * N_global + j;\n            if (j + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + 1), 4, 1});\n            if (i + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + N_global), 8, 2});\n        }\n    }\n\n    uint64_t seed = 0x123456789abcdef0ull;\n    for (int i = 0; i < NN_global; i++) {\n        seed ^= (uint64_t)init[i] + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n    }\n\n    uint64_t zseed = seed ^ 0xdeadbeefcafebabeull;\n    for (int i = 0; i < 100; i++) {\n        for (int v = 0; v < 16; v++) {\n            zobrist[i][v] = splitmix64(zseed);\n        }\n    }\n    XorShift64 rng(seed ^ 0x517cc1b727220a95ull);\n\n    EvalInfo e0 = evaluate_state(init, 3);\n    SearchResult globalBest;\n    globalBest.path = \"\";\n    globalBest.board = init;\n    globalBest.blank = blank;\n    globalBest.lastDir = 4;\n    globalBest.S = e0.S;\n    globalBest.key = e0.key;\n\n    auto start = chrono::steady_clock::now();\n    const long long TOTAL_MS = 2850;\n    auto globalDeadline = start + chrono::milliseconds(TOTAL_MS);\n\n    vector<pair<int, int>> params;\n    if (N_global <= 7) {\n        params = {{220, 2}, {260, 3}, {180, 4}};\n    } else if (N_global == 8) {\n        params = {{170, 2}, {210, 3}, {150, 4}};\n    } else if (N_global == 9) {\n        params = {{150, 2}, {190, 3}, {130, 4}};\n    } else {\n        params = {{130, 2}, {170, 3}, {110, 4}};\n    }\n    vector<int> percent = {65, 85, 100};\n\n    for (int i = 0; i < (int)params.size(); i++) {\n        auto now = chrono::steady_clock::now();\n        if (now >= globalDeadline) break;\n\n        auto runDeadline = start + chrono::milliseconds(TOTAL_MS * percent[i] / 100);\n        if (runDeadline > globalDeadline) runDeadline = globalDeadline;\n        if (now >= runDeadline) continue;\n\n        int width = params[i].first;\n        int cycleW = params[i].second;\n\n        SearchResult r = run_beam(init, blank, width, cycleW, runDeadline, rng);\n        r = greedy_polish(r, cycleW, runDeadline, rng);\n\n        if (better_result(r, globalBest)) globalBest = std::move(r);\n        if (globalBest.S == FULLV) break;\n    }\n\n    if ((int)globalBest.path.size() > T_global) {\n        globalBest.path.resize(T_global);\n    }\n    cout << globalBest.path << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int x, y;\n};\n\nstruct Line {\n    long long x1, y1, x2, y2;\n    long long dx, dy;\n};\n\nstruct EvalKey {\n    int F;            // official numerator\n    int def2;         // squared deficit\n    long long over;   // oversized-piece penalty\n    int active;       // remaining strawberries\n};\n\nstatic inline bool betterKey(const EvalKey& a, const EvalKey& b) {\n    if (a.F != b.F) return a.F > b.F;\n    if (a.def2 != b.def2) return a.def2 < b.def2;\n    if (a.over != b.over) return a.over < b.over;\n    return a.active > b.active;\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) {\n        x = seed ? seed : 88172645463325252ull;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double nextDouble() {\n        // [0, 1)\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct State {\n    vector<vector<int>> pieces; // list of strawberry indices per piece\n    vector<int> pieceSize;      // size per piece id\n    vector<int> pieceOf;        // piece id per strawberry, -1 if deleted\n    vector<int> active;         // active strawberry indices\n    array<int, 11> h{};         // h[d] = #pieces with exactly d strawberries\n    int F = 0;\n    int def2 = 0;\n    long long over = 0;\n    vector<Line> lines;\n};\n\nstruct RunResult {\n    vector<Line> lines;\n    EvalKey key;\n};\n\nclass Solver {\n    static constexpr double PI = 3.1415926535897932384626433832795;\n    static constexpr long long BIG_OVER = (1LL << 62);\n\n    int N, K;\n    array<int, 11> a{};\n    vector<Point> pts;\n    int totalA = 0;              // sum a_d\n    vector<long long> pen;       // pen[s] = max(0, s-10)^2\n\n    chrono::steady_clock::time_point start;\n    const double TL = 2.75;      // safe margin\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    }\n\n    inline long long orient(const Line& ln, const Point& p) const {\n        return ln.dx * ((long long)p.y - ln.y1) - ln.dy * ((long long)p.x - ln.x1);\n    }\n\n    inline int calcF(const array<int, 11>& h) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], h[d]);\n        return s;\n    }\n\n    inline int calcDef2(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int sat = min(a[d], h[d]);\n            int def = a[d] - sat;\n            v += def * def;\n        }\n        return v;\n    }\n\n    Line makeLineFromNormal(double nx, double ny, double c) const {\n        // line: n\u00b7x = c\n        // choose very long endpoints to preserve angle/offset after rounding\n        const double T = 1e8;\n        double dx = -ny, dy = nx;\n        double cx = nx * c, cy = ny * c;\n\n        long long x1 = llround(cx + dx * T);\n        long long y1 = llround(cy + dy * T);\n        long long x2 = llround(cx - dx * T);\n        long long y2 = llround(cy - dy * T);\n\n        if (x1 == x2 && y1 == y2) x2 += 1;\n\n        Line ln;\n        ln.x1 = x1; ln.y1 = y1;\n        ln.x2 = x2; ln.y2 = y2;\n        ln.dx = ln.x2 - ln.x1;\n        ln.dy = ln.y2 - ln.y1;\n        if (ln.dx == 0 && ln.dy == 0) {\n            ln.x2 += 1;\n            ln.dx = 1;\n        }\n        return ln;\n    }\n\n    Line makeLine(double theta, double c) const {\n        return makeLineFromNormal(cos(theta), sin(theta), c);\n    }\n\n    EvalKey evalLine(const State& st, const Line& ln, vector<int>& L, vector<int>& R) const {\n        int P = (int)st.pieces.size();\n        fill(L.begin(), L.begin() + P, 0);\n        fill(R.begin(), R.begin() + P, 0);\n\n        for (int idx : st.active) {\n            int pid = st.pieceOf[idx];\n            long long v = orient(ln, pts[idx]);\n            if (v > 0) L[pid]++;\n            else if (v < 0) R[pid]++;\n        }\n\n        array<int, 11> h2 = st.h;\n        long long over2 = st.over;\n        int removed = 0;\n\n        for (int pid = 0; pid < P; pid++) {\n            int s = st.pieceSize[pid];\n            int l = L[pid];\n            int r = R[pid];\n\n            // unchanged piece (all points on one side, no deletion)\n            if (l == s || r == s) continue;\n\n            removed += s - l - r;\n\n            over2 -= pen[s];\n            if (l > 0) over2 += pen[l];\n            if (r > 0) over2 += pen[r];\n\n            if (1 <= s && s <= 10) h2[s]--;\n            if (1 <= l && l <= 10) h2[l]++;\n            if (1 <= r && r <= 10) h2[r]++;\n        }\n\n        EvalKey key;\n        key.F = calcF(h2);\n        key.def2 = calcDef2(h2);\n        key.over = over2;\n        key.active = (int)st.active.size() - removed;\n        return key;\n    }\n\n    void applyLine(State& st, const Line& ln) const {\n        vector<vector<int>> newPieces;\n        vector<int> newPieceSize;\n        vector<int> newActive;\n\n        newPieces.reserve(st.pieces.size() * 2 + 2);\n        newPieceSize.reserve(st.pieces.size() * 2 + 2);\n        newActive.reserve(st.active.size());\n\n        fill(st.pieceOf.begin(), st.pieceOf.end(), -1);\n\n        for (const auto& pc : st.pieces) {\n            vector<int> left, right;\n            left.reserve(pc.size());\n            right.reserve(pc.size());\n\n            for (int idx : pc) {\n                long long v = orient(ln, pts[idx]);\n                if (v > 0) left.push_back(idx);\n                else if (v < 0) right.push_back(idx);\n                // v==0 -> deleted\n            }\n\n            if (!left.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : left) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newPieceSize.push_back((int)left.size());\n                newPieces.push_back(move(left));\n            }\n            if (!right.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : right) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newPieceSize.push_back((int)right.size());\n                newPieces.push_back(move(right));\n            }\n        }\n\n        st.pieces.swap(newPieces);\n        st.pieceSize.swap(newPieceSize);\n        st.active.swap(newActive);\n        st.lines.push_back(ln);\n\n        st.h.fill(0);\n        st.over = 0;\n        for (int s : st.pieceSize) {\n            if (1 <= s && s <= 10) st.h[s]++;\n            st.over += pen[s];\n        }\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n    }\n\n    RunResult runOne(uint64_t seed, int runId) {\n        XorShift64 rng(seed);\n\n        State st;\n        st.pieceOf.assign(N, 0);\n        st.pieces.resize(1);\n        st.pieces[0].resize(N);\n        iota(st.pieces[0].begin(), st.pieces[0].end(), 0);\n        st.pieceSize.assign(1, N);\n        st.active = st.pieces[0];\n\n        st.h.fill(0);\n        if (1 <= N && N <= 10) st.h[N] = 1;\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.over = pen[N];\n\n        int baseCand;\n        if (N >= 4500) baseCand = 45;\n        else if (N >= 3000) baseCand = 55;\n        else if (N >= 1800) baseCand = 70;\n        else if (N >= 900) baseCand = 90;\n        else baseCand = 120;\n\n        if (runId == 0) baseCand += 20;\n        if (runId >= 3) baseCand = max(35, baseCand - 10);\n\n        vector<int> L(N), R(N);\n        vector<double> projScratch;\n        int noImprove = 0;\n\n        auto randomGlobal = [&]() -> Line {\n            double theta = rng.nextDouble() * PI;\n            double dist = (rng.nextDouble() * 2.0 - 1.0) * 9000.0;\n            return makeLine(theta, dist);\n        };\n\n        auto pickPiece = [&](int minSize) -> int {\n            if (st.active.empty()) return -1;\n            int S = (int)st.active.size();\n            for (int t = 0; t < 24; t++) {\n                int idx = st.active[rng.nextInt(0, S - 1)];\n                int pid = st.pieceOf[idx];\n                if (st.pieceSize[pid] >= minSize) return pid;\n            }\n            int best = -1, bestSize = 0;\n            for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n                int s = st.pieceSize[pid];\n                if (s >= minSize && s > bestSize) {\n                    bestSize = s;\n                    best = pid;\n                }\n            }\n            return best;\n        };\n\n        auto lineByQuantile = [&](int pid, double theta, int t) -> Line {\n            const auto& vec = st.pieces[pid];\n            int s = (int)vec.size();\n            if (t <= 0 || t >= s) return randomGlobal();\n\n            double nx = cos(theta), ny = sin(theta);\n            projScratch.resize(s);\n            for (int i = 0; i < s; i++) {\n                const auto& p = pts[vec[i]];\n                projScratch[i] = p.x * nx + p.y * ny;\n            }\n\n            // choose c between t-th and (t+1)-th (0-index: [0..t-1] / [t..])\n            nth_element(projScratch.begin(), projScratch.begin() + t, projScratch.end());\n            double v2 = projScratch[t];\n            double v1 = -1e100;\n            for (int i = 0; i < t; i++) v1 = max(v1, projScratch[i]);\n\n            double c;\n            if (v2 - v1 < 1e-9) c = v2 + 1e-4;\n            else c = (v1 + v2) * 0.5;\n\n            return makeLineFromNormal(nx, ny, c);\n        };\n\n        auto balancedSplit = [&]() -> Line {\n            int pid = pickPiece(2);\n            if (pid < 0) return randomGlobal();\n\n            int s = st.pieceSize[pid];\n            int w = max(1, s / 6);\n            int t = s / 2 + rng.nextInt(-w, w);\n            t = max(1, min(s - 1, t));\n\n            double theta = rng.nextDouble() * PI;\n            return lineByQuantile(pid, theta, t);\n        };\n\n        auto deficitSplit = [&]() -> Line {\n            int pid = pickPiece(2);\n            if (pid < 0) return randomGlobal();\n\n            int s = st.pieceSize[pid];\n            int mx = min(10, s - 1);\n            if (mx <= 0) return randomGlobal();\n\n            int w[11] = {};\n            int sumW = 0;\n            for (int t = 1; t <= mx; t++) {\n                int def1 = max(0, a[t] - st.h[t]);\n                int wt = 1 + def1 * def1;\n                int other = s - t;\n                if (1 <= other && other <= 10) {\n                    int def2 = max(0, a[other] - st.h[other]);\n                    wt += def2 * def2;\n                }\n                w[t] = wt;\n                sumW += wt;\n            }\n\n            int r = rng.nextInt(1, sumW);\n            int t = 1;\n            while (r > w[t]) {\n                r -= w[t];\n                t++;\n            }\n\n            double theta = rng.nextDouble() * PI;\n            return lineByQuantile(pid, theta, t);\n        };\n\n        auto genCandidate = [&]() -> Line {\n            double u = rng.nextDouble();\n            if (st.over > 0) {\n                if (u < 0.25) return randomGlobal();\n                if (u < 0.55) return balancedSplit();\n                return deficitSplit();\n            } else {\n                if (u < 0.15) return randomGlobal();\n                if (u < 0.25) return balancedSplit();\n                return deficitSplit();\n            }\n        };\n\n        for (int step = 0; step < K; step++) {\n            if (elapsed() > TL) break;\n            if (st.active.empty()) break;\n            if (st.lines.size() >= (size_t)K) break;\n\n            int cand = baseCand;\n            if (step < 8) cand += baseCand / 3;\n            double rem = TL - elapsed();\n            if (rem < 0.25) cand = max(20, cand / 2);\n\n            EvalKey bestEv{-1, INT_MAX, BIG_OVER, -1};\n            Line bestLn{};\n            bool found = false;\n\n            for (int c = 0; c < cand; c++) {\n                Line ln = genCandidate();\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            EvalKey cur{st.F, st.def2, st.over, (int)st.active.size()};\n            if (found && betterKey(bestEv, cur)) {\n                applyLine(st, bestLn);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= 12) break;\n            }\n\n            if (st.F >= totalA) break;\n        }\n\n        RunResult rr;\n        rr.lines = move(st.lines);\n        rr.key = EvalKey{st.F, st.def2, st.over, (int)st.active.size()};\n        return rr;\n    }\n\npublic:\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> K;\n        a.fill(0);\n        totalA = 0;\n        for (int d = 1; d <= 10; d++) {\n            cin >> a[d];\n            totalA += a[d];\n        }\n\n        pts.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> pts[i].x >> pts[i].y;\n        }\n\n        pen.assign(N + 1, 0);\n        for (int s = 0; s <= N; s++) {\n            if (s > 10) {\n                long long t = s - 10;\n                pen[s] = t * t;\n            }\n        }\n    }\n\n    void solve() {\n        start = chrono::steady_clock::now();\n\n        uint64_t seedBase = 0x1234567890abcdefULL;\n        auto mix = [&](uint64_t v) {\n            v += 0x9e3779b97f4a7c15ULL;\n            v = (v ^ (v >> 30)) * 0xbf58476d1ce4e5b9ULL;\n            v = (v ^ (v >> 27)) * 0x94d049bb133111ebULL;\n            v ^= (v >> 31);\n            seedBase ^= v + 0x9e3779b97f4a7c15ULL + (seedBase << 6) + (seedBase >> 2);\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)K);\n        for (int d = 1; d <= 10; d++) mix((uint64_t)a[d]);\n        for (const auto& p : pts) {\n            uint64_t v = ((uint64_t)(p.x + 100000) << 21) ^ (uint64_t)(p.y + 100000);\n            mix(v);\n        }\n\n        EvalKey bestKey{-1, INT_MAX, BIG_OVER, -1};\n        vector<Line> bestLines;\n\n        int runId = 0;\n        while (elapsed() < TL) {\n            uint64_t seed = seedBase + 0x9e3779b97f4a7c15ULL * (uint64_t)(runId + 1);\n            RunResult rr = runOne(seed, runId);\n\n            if (bestLines.empty() || betterKey(rr.key, bestKey)) {\n                bestKey = rr.key;\n                bestLines = move(rr.lines);\n            }\n\n            runId++;\n            if (bestKey.F >= totalA) break;\n        }\n\n        if (bestLines.empty()) {\n            cout << 0 << '\\n';\n            return;\n        }\n\n        cout << bestLines.size() << '\\n';\n        for (const auto& ln : bestLines) {\n            cout << ln.x1 << ' ' << ln.y1 << ' ' << ln.x2 << ' ' << ln.y2 << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL)\n        : x(seed ? seed : 88172645463325252ULL) {}\n\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { // n > 0\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstruct Move {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n};\nstruct Point {\n    int x, y;\n};\nstruct Params {\n    double l0, l1;  // lambda schedule: l0 -> l1\n    bool stochastic;\n    int topK;\n};\nstruct Candidate {\n    Move mv;\n    double val;\n    int w;\n    int L;\n};\nstruct RunResult {\n    long long sumW;\n    vector<Move> ops;\n};\n\nclass Solver {\n    using Clock = chrono::steady_clock;\n\n    struct State {\n        vector<uint64_t> row, col, diagPos, diagNeg;\n        vector<uint64_t> usedH, usedV, usedPos, usedNeg;\n        long long sumW = 0;\n        int dotCount = 0;\n        vector<Move> ops;\n    };\n\n    int N = 0, M = 0, off = 0;\n    vector<pair<int, int>> initDots;\n    vector<vector<int>> W;\n    vector<pair<int, int>> cellsByWeight;\n    vector<vector<uint64_t>> rangeMask;\n\n    // direction index:\n    // 0:E 1:N 2:W 3:S 4:NE 5:NW 6:SW 7:SE\n    const int pairU[8] = {0, 1, 2, 3, 4, 5, 6, 7};\n    const int pairV[8] = {1, 2, 3, 0, 5, 6, 7, 4};\n\n    static inline int ctz64(uint64_t v) { return __builtin_ctzll(v); }\n    static inline int msb64(uint64_t v) { return 63 - __builtin_clzll(v); }\n\n    void buildTables() {\n        off = N - 1;\n\n        int c = (N - 1) / 2;\n        W.assign(N, vector<int>(N, 0));\n        cellsByWeight.clear();\n        cellsByWeight.reserve(N * N);\n\n        for (int y = 0; y < N; y++) {\n            for (int x = 0; x < N; x++) {\n                int dx = x - c;\n                int dy = y - c;\n                W[y][x] = dx * dx + dy * dy + 1;\n                cellsByWeight.emplace_back(x, y);\n            }\n        }\n        sort(cellsByWeight.begin(), cellsByWeight.end(),\n             [&](const auto &a, const auto &b) {\n                 int wa = W[a.second][a.first];\n                 int wb = W[b.second][b.first];\n                 if (wa != wb) return wa > wb;\n                 if (a.second != b.second) return a.second < b.second;\n                 return a.first < b.first;\n             });\n\n        rangeMask.assign(N + 1, vector<uint64_t>(N + 1, 0));\n        for (int l = 0; l <= N; l++) {\n            uint64_t m = 0;\n            for (int r = l + 1; r <= N; r++) {\n                m |= (1ULL << (r - 1)); // set bit r-1\n                rangeMask[l][r] = m;    // [l, r)\n            }\n        }\n    }\n\n    inline bool hasDot(const State &st, int x, int y) const {\n        return (st.row[y] >> x) & 1ULL;\n    }\n\n    inline void addDot(State &st, int x, int y) const {\n        uint64_t bx = 1ULL << x;\n        st.row[y] |= bx;\n        st.col[x] |= (1ULL << y);\n        st.diagPos[x - y + off] |= bx; // store by x-bit\n        st.diagNeg[x + y] |= bx;       // store by x-bit\n        st.dotCount++;\n    }\n\n    inline Point nearestDot(const State &st, int x, int y, int dir) const {\n        uint64_t m = 0;\n        switch (dir) {\n            case 0: { // E\n                m = st.row[y] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                return {ctz64(m), y};\n            }\n            case 1: { // N\n                m = st.col[x] & (~0ULL << (y + 1));\n                if (!m) return {-1, -1};\n                return {x, ctz64(m)};\n            }\n            case 2: { // W\n                m = st.row[y] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                return {msb64(m), y};\n            }\n            case 3: { // S\n                m = st.col[x] & ((1ULL << y) - 1);\n                if (!m) return {-1, -1};\n                return {x, msb64(m)};\n            }\n            case 4: { // NE (diag +, x increases)\n                int d = x - y + off;\n                m = st.diagPos[d] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                int k = d - off; // x - y\n                int ny = nx - k;\n                return {nx, ny};\n            }\n            case 5: { // NW (diag -, x decreases)\n                int s = x + y;\n                m = st.diagNeg[s] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                return {nx, s - nx};\n            }\n            case 6: { // SW (diag +, x decreases)\n                int d = x - y + off;\n                m = st.diagPos[d] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                int k = d - off;\n                int ny = nx - k;\n                return {nx, ny};\n            }\n            case 7: { // SE (diag -, x increases)\n                int s = x + y;\n                m = st.diagNeg[s] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                return {nx, s - nx};\n            }\n        }\n        return {-1, -1};\n    }\n\n    inline bool edgeFree(const State &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) { // vertical\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            return (st.usedV[x] & rangeMask[l][r]) == 0;\n        }\n        if (y1 == y2) { // horizontal\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedH[y] & rangeMask[l][r]) == 0;\n        }\n        if ((x2 - x1) == (y2 - y1)) { // diag +\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedPos[d] & rangeMask[l][r]) == 0;\n        }\n        // diag -\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        return (st.usedNeg[s] & rangeMask[l][r]) == 0;\n    }\n\n    inline void useEdge(State &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) { // vertical\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            st.usedV[x] |= rangeMask[l][r];\n            return;\n        }\n        if (y1 == y2) { // horizontal\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedH[y] |= rangeMask[l][r];\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) { // diag +\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedPos[d] |= rangeMask[l][r];\n            return;\n        }\n        // diag -\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        st.usedNeg[s] |= rangeMask[l][r];\n    }\n\n    inline bool betterCand(const Candidate &a, const Candidate &b) const {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.w != b.w) return a.w > b.w;\n        return a.L < b.L;\n    }\n\n    bool findBestMove(const State &st, const Params &par, double progress,\n                      XorShift64 &rng, Move &out) const {\n        constexpr int TOP = 12;\n        array<Candidate, TOP> top;\n        int sz = 0;\n\n        double lam = par.l0 + (par.l1 - par.l0) * progress;\n        if (lam < 0.0) lam = 0.0;\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n            int w = W[y][x];\n\n            // Upper-bound pruning (since cells are sorted by descending w)\n            if (sz == TOP) {\n                double upper = (double)w - lam * 2.0; // L >= 2\n                if (upper < top[sz - 1].val) break;\n            }\n\n            Point nearP[8];\n            for (int d = 0; d < 8; d++) {\n                nearP[d] = nearestDot(st, x, y, d);\n            }\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = nearP[du];\n                Point p4 = nearP[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                // Rule 2 (no extra dots on perimeter): nearest checks on remaining 2 sides\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                // Rule 3 (no shared segment)\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double val = (double)w - lam * (double)L;\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                int pos = 0;\n                while (pos < sz && !betterCand(cand, top[pos])) pos++;\n                if (pos >= TOP) continue;\n\n                if (sz < TOP) sz++;\n                for (int j = sz - 1; j > pos; --j) top[j] = top[j - 1];\n                top[pos] = cand;\n            }\n        }\n\n        if (sz == 0) return false;\n\n        int idx = 0;\n        if (par.stochastic) {\n            int k = min(sz, max(1, par.topK));\n            if (k > 1) {\n                int total = k * (k + 1) / 2; // weighted: best has largest prob\n                int r = rng.nextInt(total);\n                for (int i = 0; i < k; i++) {\n                    int wt = k - i;\n                    if (r < wt) {\n                        idx = i;\n                        break;\n                    }\n                    r -= wt;\n                }\n            }\n        }\n\n        out = top[idx].mv;\n        return true;\n    }\n\n    inline void applyMove(State &st, const Move &mv) const {\n        useEdge(st, mv.x1, mv.y1, mv.x2, mv.y2);\n        useEdge(st, mv.x2, mv.y2, mv.x3, mv.y3);\n        useEdge(st, mv.x3, mv.y3, mv.x4, mv.y4);\n        useEdge(st, mv.x4, mv.y4, mv.x1, mv.y1);\n\n        addDot(st, mv.x1, mv.y1);\n        st.sumW += W[mv.y1][mv.x1];\n        st.ops.push_back(mv);\n    }\n\n    State makeBaseState() const {\n        State st;\n        st.row.assign(N, 0);\n        st.col.assign(N, 0);\n        st.diagPos.assign(2 * N - 1, 0);\n        st.diagNeg.assign(2 * N - 1, 0);\n        st.usedH.assign(N, 0);\n        st.usedV.assign(N, 0);\n        st.usedPos.assign(2 * N - 1, 0);\n        st.usedNeg.assign(2 * N - 1, 0);\n        st.sumW = 0;\n        st.dotCount = 0;\n\n        for (auto [x, y] : initDots) {\n            if (!((st.row[y] >> x) & 1ULL)) { // just in case\n                addDot(st, x, y);\n                st.sumW += W[y][x];\n            }\n        }\n        return st;\n    }\n\n    RunResult runOne(const State &base, const Params &par, XorShift64 &rng,\n                     Clock::time_point deadline) const {\n        State st = base;\n        st.ops.clear();\n        st.ops.reserve(max(0, N * N - base.dotCount));\n\n        int totalAddable = max(1, N * N - base.dotCount);\n\n        while (true) {\n            if (Clock::now() >= deadline) break;\n\n            Move mv;\n            double progress = (double)(st.dotCount - base.dotCount) / (double)totalAddable;\n            if (!findBestMove(st, par, progress, rng, mv)) break;\n\n            applyMove(st, mv);\n        }\n\n        return {st.sumW, std::move(st.ops)};\n    }\n\n    Params randomParams(XorShift64 &rng) const {\n        Params p;\n        double t = rng.nextDouble();\n        if (t < 0.40) {\n            p.l0 = 2.0 + 2.5 * rng.nextDouble();\n            p.l1 = 0.0 + 1.0 * rng.nextDouble();\n        } else if (t < 0.80) {\n            p.l0 = 1.0 + 2.0 * rng.nextDouble();\n            p.l1 = 0.0 + 1.5 * rng.nextDouble();\n        } else {\n            p.l0 = 0.0 + 1.2 * rng.nextDouble();\n            p.l1 = 0.0 + 1.2 * rng.nextDouble();\n        }\n        if (rng.nextInt(4) == 0) swap(p.l0, p.l1); // sometimes increasing schedule\n        p.stochastic = true;\n        p.topK = 2 + rng.nextInt(5); // 2..6\n        return p;\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t seed = 1469598103934665603ULL; // FNV offset\n        auto mix = [&](uint64_t v) {\n            seed ^= v;\n            seed *= 1099511628211ULL; // FNV prime\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        for (auto [x, y] : initDots) {\n            mix(((uint64_t)(uint32_t)x << 32) | (uint32_t)y);\n        }\n        if (seed == 0) seed = 1;\n        return seed;\n    }\n\npublic:\n    void readInput() {\n        cin >> N >> M;\n        initDots.resize(M);\n        for (int i = 0; i < M; i++) {\n            int x, y;\n            cin >> x >> y;\n            initDots[i] = {x, y};\n        }\n        buildTables();\n    }\n\n    void solve() {\n        State base = makeBaseState();\n\n        long long bestSum = base.sumW;\n        vector<Move> bestOps;\n\n        XorShift64 rng(makeSeed());\n\n        auto deadline = Clock::now() + chrono::milliseconds(4750);\n\n        // deterministic-ish presets\n        vector<Params> presets = {\n            {3.0, 0.2, false, 1},\n            {1.5, 0.0, false, 1},\n            {0.0, 0.0, false, 1},\n            {2.5, 0.3, true, 3}\n        };\n\n        for (const auto &p : presets) {\n            if (Clock::now() >= deadline) break;\n            RunResult rr = runOne(base, p, rng, deadline);\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = std::move(rr.ops);\n            }\n        }\n\n        // random multi-start until time\n        while (Clock::now() + chrono::milliseconds(20) < deadline) {\n            Params p = randomParams(rng);\n            RunResult rr = runOne(base, p, rng, deadline);\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = std::move(rr.ops);\n            }\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (const auto &m : bestOps) {\n            cout << m.x1 << ' ' << m.y1 << ' '\n                 << m.x2 << ' ' << m.y2 << ' '\n                 << m.x3 << ' ' << m.y3 << ' '\n                 << m.x4 << ' ' << m.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int CELLS = 100;\nstatic constexpr int MAX_K = 24;\nstatic constexpr double TIME_LIMIT = 1.85;\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nstruct Timer {\n    chrono::high_resolution_clock::time_point st;\n    Timer() : st(chrono::high_resolution_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::high_resolution_clock::now() - st).count();\n    }\n};\n\nstruct Board {\n    uint8_t a[CELLS];\n    int filled;\n};\n\nint F[101];\nint NEI[CELLS][4];\nconst char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\ninline void init_neighbors() {\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int id = r * N + c;\n            NEI[id][0] = (r > 0) ? id - N : -1;      // up (F)\n            NEI[id][1] = (r + 1 < N) ? id + N : -1;  // down (B)\n            NEI[id][2] = (c > 0) ? id - 1 : -1;      // left\n            NEI[id][3] = (c + 1 < N) ? id + 1 : -1;  // right\n        }\n    }\n}\n\ninline void tilt(const Board& src, Board& dst, int dir) {\n    dst.filled = src.filled;\n    if (dir == 2) { // L\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = 0;\n            for (int c = 0; c < N; ++c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w++)] = v;\n            }\n            while (w < N) dst.a[base + (w++)] = 0;\n        }\n    } else if (dir == 3) { // R\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w--)] = v;\n            }\n            while (w >= 0) dst.a[base + (w--)] = 0;\n        }\n    } else if (dir == 0) { // F (up)\n        for (int c = 0; c < N; ++c) {\n            int w = 0;\n            for (int r = 0; r < N; ++r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w++) * N + c] = v;\n            }\n            while (w < N) dst.a[(w++) * N + c] = 0;\n        }\n    } else { // B (down)\n        for (int c = 0; c < N; ++c) {\n            int w = N - 1;\n            for (int r = N - 1; r >= 0; --r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w--) * N + c] = v;\n            }\n            while (w >= 0) dst.a[(w--) * N + c] = 0;\n        }\n    }\n}\n\ninline void place_by_rank(Board& b, int rank, uint8_t flavor) {\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            if (--rank == 0) {\n                b.a[i] = flavor;\n                ++b.filled;\n                return;\n            }\n        }\n    }\n    // Fallback (should not happen)\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            b.a[i] = flavor;\n            ++b.filled;\n            return;\n        }\n    }\n}\n\ninline long long component_square(const Board& b) {\n    static uint32_t seen[CELLS];\n    static uint32_t stamp = 1;\n    ++stamp;\n    if (stamp == 0) {\n        memset(seen, 0, sizeof(seen));\n        stamp = 1;\n    }\n\n    long long sum = 0;\n    int q[CELLS];\n\n    for (int i = 0; i < CELLS; ++i) {\n        uint8_t col = b.a[i];\n        if (col == 0 || seen[i] == stamp) continue;\n\n        seen[i] = stamp;\n        int head = 0, tail = 0;\n        q[tail++] = i;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            ++sz;\n            for (int k = 0; k < 4; ++k) {\n                int to = NEI[v][k];\n                if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                    seen[to] = stamp;\n                    q[tail++] = to;\n                }\n            }\n        }\n        sum += 1LL * sz * sz;\n    }\n    return sum;\n}\n\ninline int best_dir_one_step(const Board& b) {\n    long long best = LLONG_MIN;\n    int bestDir = 0;\n    Board tmp;\n    for (int d = 0; d < 4; ++d) {\n        tilt(b, tmp, d);\n        long long v = component_square(tmp);\n        if (v > best) {\n            best = v;\n            bestDir = d;\n        }\n    }\n    return bestDir;\n}\n\ninline void greedy_tilt(Board& b) {\n    Board tmp, bestBoard;\n    long long best = LLONG_MIN;\n    for (int d = 0; d < 4; ++d) {\n        tilt(b, tmp, d);\n        long long v = component_square(tmp);\n        if (v > best) {\n            best = v;\n            bestBoard = tmp;\n        }\n    }\n    b = bestBoard;\n}\n\nint choose_move(const Board& cur, int t, XorShift& rng, const Timer& timer) {\n    int rem = 100 - t;\n    if (rem <= 0) return 0;\n\n    double remainTime = TIME_LIMIT - timer.elapsed();\n    if (remainTime < 0.02) return best_dir_one_step(cur);\n\n    int K;\n    if (rem >= 70) K = 6;\n    else if (rem >= 40) K = 9;\n    else if (rem >= 20) K = 14;\n    else K = 22;\n\n    int remDecisions = 101 - t; // including current decision\n    double avgBudget = remainTime / max(1, remDecisions);\n\n    if (avgBudget < 0.012) K = min(K, 12);\n    if (avgBudget < 0.009) K = min(K, 8);\n    if (avgBudget < 0.006) K = min(K, 5);\n    if (avgBudget < 0.004) K = min(K, 3);\n    if (avgBudget < 0.0025) K = 1;\n\n    K = max(1, min(K, MAX_K));\n\n    if (K == 1 && rem >= 40) {\n        return best_dir_one_step(cur);\n    }\n\n    static uint8_t ranks[MAX_K][101];\n    for (int s = 0; s < K; ++s) {\n        for (int u = t + 1; u <= 100; ++u) {\n            ranks[s][u] = static_cast<uint8_t>(rng.next_int(1, 101 - u));\n        }\n    }\n\n    Board first[4];\n    long long firstVal[4];\n    for (int d = 0; d < 4; ++d) {\n        tilt(cur, first[d], d);\n        firstVal[d] = component_square(first[d]);\n    }\n\n    long long bestTotal = LLONG_MIN;\n    int bestDir = 0;\n\n    for (int d = 0; d < 4; ++d) {\n        long long total = 0;\n        for (int s = 0; s < K; ++s) {\n            Board b = first[d];\n\n            for (int u = t + 1; u <= 100; ++u) {\n                place_by_rank(b, static_cast<int>(ranks[s][u]), static_cast<uint8_t>(F[u]));\n                if (u < 100) greedy_tilt(b);\n            }\n\n            total += component_square(b);\n        }\n\n        if (total > bestTotal || (total == bestTotal && firstVal[d] > firstVal[bestDir])) {\n            bestTotal = total;\n            bestDir = d;\n        }\n    }\n\n    return bestDir;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 1; i <= 100; ++i) {\n        if (!(cin >> F[i])) return 0;\n    }\n\n    uint64_t seed = 1469598103934665603ull;\n    for (int i = 1; i <= 100; ++i) {\n        seed ^= static_cast<uint64_t>(F[i] + 31 * i);\n        seed *= 1099511628211ull;\n    }\n    XorShift rng(seed);\n    Timer timer;\n\n    init_neighbors();\n\n    Board cur;\n    memset(cur.a, 0, sizeof(cur.a));\n    cur.filled = 0;\n\n    for (int t = 1; t <= 100; ++t) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        place_by_rank(cur, p, static_cast<uint8_t>(F[t]));\n\n        int dir = 0; // F\n        if (t < 100) {\n            dir = choose_move(cur, t, rng, timer);\n            Board nxt;\n            tilt(cur, nxt, dir);\n            cur = nxt;\n        }\n\n        cout << DIR_CH[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    inline 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    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline uint64_t prob_to_u64(double p) {\n    if (p <= 0.0) return 0ULL;\n    if (p >= 1.0) return numeric_limits<uint64_t>::max();\n    long double v = p * (long double)numeric_limits<uint64_t>::max();\n    if (v < 0) v = 0;\n    if (v > (long double)numeric_limits<uint64_t>::max()) v = (long double)numeric_limits<uint64_t>::max();\n    return (uint64_t)v;\n}\n\nstatic inline double compute_wnd(double eps, int N) {\n    double a = max(0.0, 1.0 - 2.0 * eps);\n    return (0.02 * a * a) / (double)(N * N);\n}\n\nstruct Graph {\n    vector<uint8_t> bits;     // length L\n    vector<int> deg_sorted;   // length N\n    vector<int> nd_sorted;    // length N (neighbor-degree sums, sorted with deg)\n    int edges = 0;\n};\n\nstruct Codebook {\n    int N = 0;\n    int L = 0;\n    vector<int> eu, ev;       // endpoints for each edge index\n    vector<Graph> graphs;     // size M\n};\n\nstruct PrototypeSet {\n    vector<vector<float>> deg;\n    vector<vector<float>> nd;\n    double wnd = 0.0;\n};\n\nstruct FeatureWork {\n    vector<int> deg, nd;\n    vector<pair<int,int>> sig;\n    vector<uint8_t> bits;\n    FeatureWork() {}\n    FeatureWork(int N, int L) { init(N, L); }\n    void init(int N, int L) {\n        deg.assign(N, 0);\n        nd.assign(N, 0);\n        sig.assign(N, {0, 0});\n        bits.assign(L, 0);\n    }\n};\n\nvoid build_edges(int N, vector<int>& eu, vector<int>& ev) {\n    eu.clear(); ev.clear();\n    eu.reserve(N * (N - 1) / 2);\n    ev.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            eu.push_back(i);\n            ev.push_back(j);\n        }\n    }\n}\n\nGraph make_graph_from_bits(vector<uint8_t>&& bits, int N, const vector<int>& eu, const vector<int>& ev) {\n    Graph g;\n    g.bits = std::move(bits);\n    g.edges = 0;\n\n    vector<int> deg(N, 0), nd(N, 0);\n    int L = (int)eu.size();\n\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            g.edges++;\n            int u = eu[e], v = ev[e];\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd[u] += deg[v];\n            nd[v] += deg[u];\n        }\n    }\n\n    vector<pair<int,int>> sig(N);\n    for (int i = 0; i < N; i++) sig[i] = {deg[i], nd[i]};\n    sort(sig.begin(), sig.end());\n\n    g.deg_sorted.resize(N);\n    g.nd_sorted.resize(N);\n    for (int i = 0; i < N; i++) {\n        g.deg_sorted[i] = sig[i].first;\n        g.nd_sorted[i] = sig[i].second;\n    }\n    return g;\n}\n\nvector<int> random_group_ids(int N, int K, RNG& rng) {\n    vector<int> sz(K, 1);\n    int rem = N - K;\n    for (int i = 0; i < rem; i++) sz[rng.next_int(0, K - 1)]++;\n\n    vector<int> gid;\n    gid.reserve(N);\n    for (int g = 0; g < K; g++) {\n        for (int c = 0; c < sz[g]; c++) gid.push_back(g);\n    }\n    for (int i = N - 1; i >= 1; i--) {\n        int j = rng.next_int(0, i);\n        swap(gid[i], gid[j]);\n    }\n    return gid;\n}\n\nGraph generate_candidate_graph(int N, const vector<int>& eu, const vector<int>& ev, RNG& rng) {\n    int L = (int)eu.size();\n    vector<uint8_t> bits(L, 0);\n\n    int mode = rng.next_int(0, 5);\n\n    if (mode == 0) {\n        // Erdos-Renyi with biased p distribution\n        double p = rng.next_double();\n        if (rng.next_double() < 0.5) p = p * p;\n        else {\n            double q = 1.0 - p;\n            p = 1.0 - q * q;\n        }\n        uint64_t th = prob_to_u64(p);\n        for (int e = 0; e < L; e++) bits[e] = (rng.next_u64() < th);\n    } else if (mode == 1) {\n        // Binary block model\n        int K = rng.next_int(2, min(8, N));\n        auto gid = random_group_ids(N, K, rng);\n        vector<vector<uint8_t>> B(K, vector<uint8_t>(K, 0));\n        for (int i = 0; i < K; i++) {\n            for (int j = i; j < K; j++) {\n                uint8_t x = (uint8_t)(rng.next_u64() & 1ULL);\n                B[i][j] = B[j][i] = x;\n            }\n        }\n        for (int e = 0; e < L; e++) {\n            bits[e] = B[gid[eu[e]]][gid[ev[e]]];\n        }\n    } else if (mode == 2) {\n        // Union of cliques\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) {\n            bits[e] = (gid[eu[e]] == gid[ev[e]]);\n        }\n    } else if (mode == 3) {\n        // Complete multipartite\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) {\n            bits[e] = (gid[eu[e]] != gid[ev[e]]);\n        }\n    } else if (mode == 4) {\n        // Threshold graph style\n        vector<uint8_t> tp(N, 0);\n        for (int i = 1; i < N; i++) tp[i] = (uint8_t)(rng.next_u64() & 1ULL);\n        for (int e = 0; e < L; e++) {\n            bits[e] = tp[ev[e]]; // eu[e] < ev[e]\n        }\n    } else {\n        // Rank-1 threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int thv = rng.next_int(0, 2000);\n        for (int e = 0; e < L; e++) {\n            bits[e] = (w[eu[e]] + w[ev[e]] >= thv);\n        }\n    }\n\n    // Small perturbation for diversity\n    if (rng.next_double() < 0.7) {\n        double pmax = (mode == 0 ? 0.03 : 0.08);\n        double pf = rng.next_double() * pmax;\n        uint64_t th = prob_to_u64(pf);\n        for (int e = 0; e < L; e++) {\n            if (rng.next_u64() < th) bits[e] ^= 1;\n        }\n    }\n\n    return make_graph_from_bits(std::move(bits), N, eu, ev);\n}\n\nuint64_t hash_signature(const Graph& g) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)(g.edges + 1); h *= 1099511628211ULL;\n    int N = (int)g.deg_sorted.size();\n    for (int i = 0; i < N; i++) {\n        h ^= (uint64_t)(g.deg_sorted[i] + 1); h *= 1099511628211ULL;\n        h ^= (uint64_t)(g.nd_sorted[i] + 10007); h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nCodebook build_codebook(int N, int M, double eps, RNG& rng) {\n    Codebook cb;\n    cb.N = N;\n    build_edges(N, cb.eu, cb.ev);\n    cb.L = (int)cb.eu.size();\n\n    int C = max(400, M * 8);\n    vector<Graph> cand;\n    cand.reserve(C);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(C * 3);\n\n    int attempts = 0;\n    int maxAttempts = C * 40;\n    while ((int)cand.size() < C && attempts < maxAttempts) {\n        Graph g = generate_candidate_graph(N, cb.eu, cb.ev, rng);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        attempts++;\n    }\n\n    // Fallback: edge-prefix graphs\n    for (int m = 0; (int)cand.size() < C && m <= cb.L; m++) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < m; e++) bits[e] = 1;\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n    }\n\n    if (cand.empty()) {\n        vector<uint8_t> bits(cb.L, 0);\n        cand.push_back(make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev));\n    }\n\n    int Cn = (int)cand.size();\n    double wnd_sel = compute_wnd(eps, N);\n\n    auto dist_idx = [&](int a, int b) -> double {\n        double s = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)cand[a].deg_sorted[i] - (double)cand[b].deg_sorted[i];\n            s += d * d;\n        }\n        if (wnd_sel > 0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)cand[a].nd_sorted[i] - (double)cand[b].nd_sorted[i];\n                s += wnd_sel * d * d;\n            }\n        }\n        return s;\n    };\n\n    vector<int> selected;\n    selected.reserve(M);\n    vector<char> used(Cn, false);\n\n    int imin = 0, imax = 0;\n    for (int i = 1; i < Cn; i++) {\n        if (cand[i].edges < cand[imin].edges) imin = i;\n        if (cand[i].edges > cand[imax].edges) imax = i;\n    }\n    selected.push_back(imin);\n    used[imin] = true;\n    if ((int)selected.size() < M && imax != imin) {\n        selected.push_back(imax);\n        used[imax] = true;\n    }\n\n    vector<double> minDist(Cn, 1e100);\n    for (int i = 0; i < Cn; i++) {\n        double d = 1e100;\n        for (int s : selected) d = min(d, dist_idx(i, s));\n        minDist[i] = d;\n    }\n\n    while ((int)selected.size() < M) {\n        int best = -1;\n        double bestVal = -1.0;\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i] && minDist[i] > bestVal) {\n                bestVal = minDist[i];\n                best = i;\n            }\n        }\n        if (best == -1) break;\n        selected.push_back(best);\n        used[best] = true;\n\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i]) {\n                double d = dist_idx(i, best);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    int ptr = 0;\n    while ((int)selected.size() < M) {\n        selected.push_back(ptr % Cn);\n        ptr++;\n    }\n\n    cb.graphs.reserve(M);\n    for (int i = 0; i < M; i++) cb.graphs.push_back(cand[selected[i]]);\n    return cb;\n}\n\nvoid extract_sorted_features_from_bits(const vector<uint8_t>& bits, const Codebook& cb, FeatureWork& w,\n                                       vector<int>& outDeg, vector<int>& outNd) {\n    int N = cb.N, L = cb.L;\n    fill(w.deg.begin(), w.deg.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.sig[i] = {w.deg[i], w.nd[i]};\n    sort(w.sig.begin(), w.sig.end());\n\n    if ((int)outDeg.size() != N) {\n        outDeg.resize(N);\n        outNd.resize(N);\n    }\n    for (int i = 0; i < N; i++) {\n        outDeg[i] = w.sig[i].first;\n        outNd[i] = w.sig[i].second;\n    }\n}\n\nvoid extract_sorted_features_from_string(const string& H, const Codebook& cb, FeatureWork& w,\n                                         vector<int>& outDeg, vector<int>& outNd) {\n    int N = cb.N, L = cb.L;\n    fill(w.deg.begin(), w.deg.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.sig[i] = {w.deg[i], w.nd[i]};\n    sort(w.sig.begin(), w.sig.end());\n\n    if ((int)outDeg.size() != N) {\n        outDeg.resize(N);\n        outNd.resize(N);\n    }\n    for (int i = 0; i < N; i++) {\n        outDeg[i] = w.sig[i].first;\n        outNd[i] = w.sig[i].second;\n    }\n}\n\nvoid sample_noisy_sorted_features(const Graph& g, const Codebook& cb, double eps, uint64_t flipThr,\n                                  RNG& rng, FeatureWork& w, vector<int>& outDeg, vector<int>& outNd) {\n    if (eps <= 0.0) {\n        outDeg = g.deg_sorted;\n        outNd = g.nd_sorted;\n        return;\n    }\n    int L = cb.L;\n    for (int e = 0; e < L; e++) {\n        uint8_t b = g.bits[e];\n        if (rng.next_u64() < flipThr) b ^= 1;\n        w.bits[e] = b;\n    }\n    extract_sorted_features_from_bits(w.bits, cb, w, outDeg, outNd);\n}\n\nPrototypeSet calibrate_prototypes(const Codebook& cb, double eps, int S, double wnd, RNG& rng) {\n    int M = (int)cb.graphs.size();\n    int N = cb.N;\n    PrototypeSet proto;\n    proto.wnd = wnd;\n    proto.deg.assign(M, vector<float>(N, 0));\n    proto.nd.assign(M, vector<float>(N, 0));\n\n    if (eps <= 0.0 || S <= 0) {\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < N; i++) {\n                proto.deg[k][i] = (float)cb.graphs[k].deg_sorted[i];\n                proto.nd[k][i] = (float)cb.graphs[k].nd_sorted[i];\n            }\n        }\n        return proto;\n    }\n\n    uint64_t flipThr = prob_to_u64(eps);\n    FeatureWork w(N, cb.L);\n    vector<int> tmpDeg(N), tmpNd(N);\n    vector<double> sumDeg(N), sumNd(N);\n\n    for (int k = 0; k < M; k++) {\n        fill(sumDeg.begin(), sumDeg.end(), 0.0);\n        fill(sumNd.begin(), sumNd.end(), 0.0);\n\n        for (int s = 0; s < S; s++) {\n            sample_noisy_sorted_features(cb.graphs[k], cb, eps, flipThr, rng, w, tmpDeg, tmpNd);\n            for (int i = 0; i < N; i++) {\n                sumDeg[i] += tmpDeg[i];\n                sumNd[i] += tmpNd[i];\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            proto.deg[k][i] = (float)(sumDeg[i] / S);\n            proto.nd[k][i] = (float)(sumNd[i] / S);\n        }\n    }\n\n    return proto;\n}\n\nint decode_with_prototypes(const vector<int>& obsDeg, const vector<int>& obsNd, const PrototypeSet& proto) {\n    int M = (int)proto.deg.size();\n    int N = (int)obsDeg.size();\n\n    int best = 0;\n    double bestScore = 1e300;\n\n    for (int k = 0; k < M; k++) {\n        const auto& pd = proto.deg[k];\n        const auto& pn = proto.nd[k];\n\n        double s = 0.0;\n        bool pruned = false;\n        for (int i = 0; i < N; i++) {\n            double d = (double)obsDeg[i] - (double)pd[i];\n            s += d * d;\n            if (s >= bestScore) {\n                pruned = true;\n                break;\n            }\n        }\n        if (pruned) continue;\n\n        if (proto.wnd > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)obsNd[i] - (double)pn[i];\n                s += proto.wnd * d * d;\n                if (s >= bestScore) {\n                    pruned = true;\n                    break;\n                }\n            }\n            if (pruned) continue;\n        }\n\n        if (s < bestScore) {\n            bestScore = s;\n            best = k;\n        }\n    }\n    return best;\n}\n\ndouble evaluate_codebook(const Codebook& cb, const PrototypeSet& proto, double eps, int T, RNG& rng) {\n    int M = (int)cb.graphs.size();\n    if (T <= 0) return 0.0;\n\n    int err = 0;\n    FeatureWork w(cb.N, cb.L);\n    vector<int> obsDeg(cb.N), obsNd(cb.N);\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int t = 0; t < T; t++) {\n        int s = rng.next_int(0, M - 1);\n        sample_noisy_sorted_features(cb.graphs[s], cb, eps, flipThr, rng, w, obsDeg, obsNd);\n        int pred = decode_with_prototypes(obsDeg, obsNd, proto);\n        if (pred != s) err++;\n    }\n\n    double q = (double)err / (double)T;\n    double survive = 1.0 - 0.1 * q;\n    if (survive < 0.0) survive = 0.0;\n    return pow(survive, 100.0) / (double)cb.N;\n}\n\nvector<int> choose_candidate_Ns(int M, double eps) {\n    int Nmin = 4;\n    while (Nmin * (Nmin - 1) / 2 < M - 1) Nmin++;\n\n    vector<int> Ns;\n    auto add = [&](int n) {\n        n = max(n, Nmin);\n        n = max(4, min(100, n));\n        if (find(Ns.begin(), Ns.end(), n) == Ns.end()) Ns.push_back(n);\n    };\n\n    add(Nmin);\n    if (eps < 0.03) {\n        add(Nmin + 2); add(18); add(24); add(30); add(40); add(52);\n    } else if (eps < 0.10) {\n        add(Nmin + 2); add(24); add(32); add(40); add(52); add(66);\n    } else if (eps < 0.20) {\n        add(28); add(40); add(52); add(64); add(78); add(92);\n    } else if (eps < 0.30) {\n        add(36); add(52); add(68); add(84); add(100);\n    } else {\n        add(44); add(60); add(76); add(92); add(100);\n    }\n\n    sort(Ns.begin(), Ns.end());\n    Ns.erase(unique(Ns.begin(), Ns.end()), Ns.end());\n    return Ns;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count();\n    };\n\n    uint64_t epsInt = (uint64_t)llround(eps * 100.0);\n    uint64_t baseSeed = 0x3141592653589793ULL ^ (uint64_t)M * 10007ULL ^ (epsInt * 1000003ULL);\n\n    vector<int> Ns = choose_candidate_Ns(M, eps);\n\n    int S_eval = (eps < 0.08 ? 1 : (eps < 0.20 ? 2 : 3));\n    int T_eval = (eps < 0.05 ? 120 : 60);\n\n    double bestEst = -1.0;\n    Codebook bestCb;\n\n    for (int idx = 0; idx < (int)Ns.size(); idx++) {\n        if (idx > 0 && elapsed_ms() > 2500) break;\n\n        int N = Ns[idx];\n        double wnd = compute_wnd(eps, N);\n\n        RNG rngBuild(baseSeed + 10000019ULL * (uint64_t)N + (uint64_t)idx * 11939ULL + 17ULL);\n        Codebook cb = build_codebook(N, M, eps, rngBuild);\n\n        RNG rngCal(baseSeed + 20000003ULL * (uint64_t)N + (uint64_t)idx * 9176ULL + 31ULL);\n        PrototypeSet proto = calibrate_prototypes(cb, eps, S_eval, wnd, rngCal);\n\n        RNG rngEval(baseSeed + 30000059ULL * (uint64_t)N + (uint64_t)idx * 811ULL + 43ULL);\n        double est = evaluate_codebook(cb, proto, eps, T_eval, rngEval);\n\n        if (est > bestEst) {\n            bestEst = est;\n            bestCb = std::move(cb);\n        }\n    }\n\n    if (bestCb.graphs.empty()) {\n        int N = 4;\n        while (N * (N - 1) / 2 < M - 1) N++;\n        RNG rngBuild(baseSeed + 555555ULL);\n        bestCb = build_codebook(N, M, eps, rngBuild);\n    }\n\n    int S_final;\n    if (eps < 0.05) S_final = 5;\n    else if (eps < 0.15) S_final = 8;\n    else if (eps < 0.30) S_final = 10;\n    else S_final = 12;\n\n    if (elapsed_ms() > 3200) S_final = max(3, S_final / 2);\n\n    double wndFinal = compute_wnd(eps, bestCb.N);\n    RNG rngFinal(baseSeed + 0x9e3779b97f4a7c15ULL);\n    PrototypeSet protoFinal = calibrate_prototypes(bestCb, eps, S_final, wndFinal, rngFinal);\n\n    // Output codebook\n    cout << bestCb.N << '\\n';\n    for (int k = 0; k < M; k++) {\n        string s(bestCb.L, '0');\n        const auto& bits = bestCb.graphs[k].bits;\n        for (int e = 0; e < bestCb.L; e++) {\n            if (bits[e]) s[e] = '1';\n        }\n        cout << s << '\\n';\n    }\n    cout.flush();\n\n    // Online prediction\n    FeatureWork qwork(bestCb.N, bestCb.L);\n    vector<int> obsDeg(bestCb.N), obsNd(bestCb.N);\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) return 0;\n\n        extract_sorted_features_from_string(H, bestCb, qwork, obsDeg, obsNd);\n        int ans = decode_with_prototypes(obsDeg, obsNd, protoFinal);\n\n        if (ans < 0) ans = 0;\n        if (ans >= M) ans = M - 1;\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;\nstatic constexpr int UNREACH = 1'000'000'000;\nstatic constexpr ll DISCONNECT_UNIT = 100'000'000LL;\n\nstruct Edge {\n    int u, v, w;\n    int cell = 0;\n    double imp = 0.0;\n};\n\nint N, M, D, K;\nint GRID = 10;\n\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj; // (to, edge id)\nvector<int> X, Y, degv;\n\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\nvector<int> samples;\nint S = 0;\nvector<vector<int>> baseDist;\nvector<int> tmpDist;\n\n// current solution state\nvector<int> dayOf;               // edge -> day [0..D-1]\nvector<int> cntDay;              // day -> count\nvector<vector<int>> incCnt;      // vertex, day -> #incident edges repaired that day\nvector<vector<int>> dayEdges;    // day -> edge list\nvector<int> posInDay;            // edge -> position in dayEdges[dayOf[edge]]\nvector<ll> dayScore;             // approximate score per day\n\nvector<int> seen;\nint seenToken = 1;\n\ninline int rnd_int(int n) {\n    return (int)(rng() % (uint32_t)n);\n}\ninline double rnd01() {\n    return (rng() + 0.5) * (1.0 / 4294967296.0);\n}\n\nvoid dijkstra_full_parent(int src, vector<int>& dist, vector<int>& parent) {\n    fill(dist.begin(), dist.end(), UNREACH);\n    fill(parent.begin(), parent.end(), -1);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                parent[to] = eid;\n                pq.push({nd, to});\n            } else if (nd == dist[to] && parent[to] != -1) {\n                // deterministic tie-break\n                if (eid < parent[to]) parent[to] = eid;\n            }\n        }\n    }\n}\n\nvoid dijkstra_ban_day(int src, int banDay, vector<int>& dist) {\n    fill(dist.begin(), dist.end(), UNREACH);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            if (dayOf[eid] == banDay) continue;\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                pq.push({nd, to});\n            }\n        }\n    }\n}\n\n// ordered pairs across different connected components after removing banDay edges.\n// 0 means connected.\nll disconnected_cross_pairs(int banDay) {\n    static vector<int> q;\n    if ((int)q.size() < N) q.resize(N);\n\n    ll sameOrdered = 0;\n    for (int st = 0; st < N; st++) {\n        if (seen[st] == seenToken) continue;\n        int head = 0, tail = 0;\n        q[tail++] = st;\n        seen[st] = seenToken;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (auto [to, eid] : adj[v]) {\n                if (dayOf[eid] == banDay) continue;\n                if (seen[to] == seenToken) continue;\n                seen[to] = seenToken;\n                q[tail++] = to;\n            }\n        }\n        sameOrdered += 1LL * sz * (sz - 1);\n    }\n\n    seenToken++;\n    if (seenToken == INT_MAX) {\n        fill(seen.begin(), seen.end(), 0);\n        seenToken = 1;\n    }\n\n    ll totalOrdered = 1LL * N * (N - 1);\n    return totalOrdered - sameOrdered;\n}\n\nll compute_day_score(int day) {\n    // Strong connectivity penalty to avoid hidden catastrophic solutions.\n    ll crossPairs = disconnected_cross_pairs(day);\n    if (crossPairs > 0) {\n        return crossPairs * DISCONNECT_UNIT;\n    }\n\n    ll sum = 0;\n    for (int si = 0; si < S; si++) {\n        dijkstra_ban_day(samples[si], day, tmpDist);\n        const auto& b = baseDist[si];\n        for (int v = 0; v < N; v++) {\n            sum += (ll)tmpDist[v] - b[v];\n        }\n    }\n    return sum;\n}\n\nll evaluate_total(vector<ll>& outDayScore) {\n    outDayScore.assign(D, 0);\n    ll tot = 0;\n    for (int d = 0; d < D; d++) {\n        outDayScore[d] = compute_day_score(d);\n        tot += outDayScore[d];\n    }\n    return tot;\n}\n\nvector<int> select_samples(int cnt) {\n    cnt = min(cnt, N);\n    vector<int> res;\n    vector<double> minD2(N, 1e100);\n    vector<char> used(N, false);\n\n    int first = 0;\n    for (int i = 1; i < N; i++) {\n        if (degv[i] > degv[first]) first = i;\n    }\n\n    for (int it = 0; it < cnt; it++) {\n        int cur = -1;\n        if (it == 0) {\n            cur = first;\n        } else {\n            double best = -1.0;\n            for (int v = 0; v < N; v++) {\n                if (used[v]) continue;\n                if (minD2[v] > best) {\n                    best = minD2[v];\n                    cur = v;\n                }\n            }\n        }\n        used[cur] = true;\n        res.push_back(cur);\n\n        for (int v = 0; v < N; v++) {\n            if (used[v]) continue;\n            double dx = (double)X[v] - X[cur];\n            double dy = (double)Y[v] - Y[cur];\n            double d2 = dx * dx + dy * dy;\n            if (d2 < minD2[v]) minD2[v] = d2;\n        }\n    }\n\n    return res;\n}\n\nvector<int> build_initial_schedule(double alpha, double beta, double gamma) {\n    vector<int> assign(M, -1);\n    vector<int> cnt(D, 0);\n    vector<vector<int>> inc(N, vector<int>(D, 0));\n    int C = GRID * GRID;\n    vector<vector<int>> cellCnt(C, vector<int>(D, 0));\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n\n    vector<double> key(M);\n    for (int e = 0; e < M; e++) {\n        key[e] = edges[e].imp + (double)(rng() & 2047) * 1e-6;\n    }\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (key[a] != key[b]) return key[a] > key[b];\n        return a < b;\n    });\n\n    double maxImp = 1e-9;\n    for (int e = 0; e < M; e++) maxImp = max(maxImp, edges[e].imp);\n\n    for (int eid : order) {\n        const Edge& E = edges[eid];\n        int u = E.u, v = E.v, c = E.cell;\n        double impf = 1.0 + E.imp / maxImp;\n\n        int bestDay = -1;\n        double bestP = 1e100;\n\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] >= K) continue;\n            if (inc[u][d] >= degv[u] - 1) continue;\n            if (inc[v][d] >= degv[v] - 1) continue;\n\n            double p = alpha * cnt[d]\n                     + beta * impf * (inc[u][d] + inc[v][d])\n                     + gamma * cellCnt[c][d];\n            if (p < bestP) {\n                bestP = p;\n                bestDay = d;\n            }\n        }\n\n        // If hard constraints block all days, relax slightly with heavy penalty.\n        if (bestDay == -1) {\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] >= K) continue;\n                double viol = 0.0;\n                if (inc[u][d] >= degv[u] - 1) viol += 1000.0;\n                if (inc[v][d] >= degv[v] - 1) viol += 1000.0;\n                double p = alpha * cnt[d]\n                         + beta * impf * (inc[u][d] + inc[v][d])\n                         + gamma * cellCnt[c][d]\n                         + viol;\n                if (p < bestP) {\n                    bestP = p;\n                    bestDay = d;\n                }\n            }\n        }\n\n        if (bestDay == -1) {\n            // very defensive fallback\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] < K) {\n                    bestDay = d;\n                    break;\n                }\n            }\n            if (bestDay == -1) bestDay = 0;\n        }\n\n        assign[eid] = bestDay;\n        cnt[bestDay]++;\n        inc[u][bestDay]++;\n        inc[v][bestDay]++;\n        cellCnt[c][bestDay]++;\n    }\n\n    return assign;\n}\n\nvoid build_state_from_assignment() {\n    cntDay.assign(D, 0);\n    incCnt.assign(N, vector<int>(D, 0));\n    dayEdges.assign(D, vector<int>());\n    posInDay.assign(M, -1);\n\n    for (int e = 0; e < M; e++) {\n        int d = dayOf[e];\n        cntDay[d]++;\n        int u = edges[e].u, v = edges[e].v;\n        incCnt[u][d]++;\n        incCnt[v][d]++;\n        posInDay[e] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(e);\n    }\n}\n\ninline void day_remove_edge(int e, int d) {\n    int p = posInDay[e];\n    int last = dayEdges[d].back();\n    dayEdges[d][p] = last;\n    posInDay[last] = p;\n    dayEdges[d].pop_back();\n}\n\ninline void day_add_edge(int e, int d) {\n    posInDay[e] = (int)dayEdges[d].size();\n    dayEdges[d].push_back(e);\n}\n\nvoid apply_move(int e, int from, int to) {\n    day_remove_edge(e, from);\n    day_add_edge(e, to);\n\n    dayOf[e] = to;\n    cntDay[from]--;\n    cntDay[to]++;\n\n    int u = edges[e].u, v = edges[e].v;\n    incCnt[u][from]--;\n    incCnt[v][from]--;\n    incCnt[u][to]++;\n    incCnt[v][to]++;\n}\n\nvoid apply_swap(int e, int f, int d1, int d2) {\n    // e: d1 -> d2, f: d2 -> d1\n    int pe = posInDay[e];\n    int pf = posInDay[f];\n\n    dayEdges[d1][pe] = f;\n    posInDay[f] = pe;\n    dayEdges[d2][pf] = e;\n    posInDay[e] = pf;\n\n    dayOf[e] = d2;\n    dayOf[f] = d1;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    incCnt[eu][d1]--;\n    incCnt[ev][d1]--;\n    incCnt[eu][d2]++;\n    incCnt[ev][d2]++;\n\n    incCnt[fu][d2]--;\n    incCnt[fv][d2]--;\n    incCnt[fu][d1]++;\n    incCnt[fv][d1]++;\n}\n\nbool can_move_edge(int e, int to) {\n    int from = dayOf[e];\n    if (from == to) return false;\n    if (cntDay[to] >= K) return false;\n    int u = edges[e].u, v = edges[e].v;\n    if (incCnt[u][to] + 1 > degv[u] - 1) return false;\n    if (incCnt[v][to] + 1 > degv[v] - 1) return false;\n    return true;\n}\n\nbool can_swap_edges(int e, int f) {\n    int d1 = dayOf[e];\n    int d2 = dayOf[f];\n    if (d1 == d2) return false;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    int vv[4] = {eu, ev, fu, fv};\n    sort(vv, vv + 4);\n    int m = (int)(unique(vv, vv + 4) - vv);\n\n    for (int i = 0; i < m; i++) {\n        int x = vv[i];\n        int nd1 = incCnt[x][d1] - (eu == x) - (ev == x) + (fu == x) + (fv == x);\n        int nd2 = incCnt[x][d2] - (fu == x) - (fv == x) + (eu == x) + (ev == x);\n        if (nd1 > degv[x] - 1) return false;\n        if (nd2 > degv[x] - 1) return false;\n    }\n    return true;\n}\n\nint day_with_max_score() {\n    int id = 0;\n    for (int d = 1; d < D; d++) {\n        if (dayScore[d] > dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_move(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (cntDay[d] >= K) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_swap(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (dayEdges[d].empty()) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    adj.assign(N, {});\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        adj[u].push_back({v, i});\n        adj[v].push_back({u, i});\n    }\n\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n    }\n\n    degv.assign(N, 0);\n    for (int v = 0; v < N; v++) degv[v] = (int)adj[v].size();\n\n    // edge cell id\n    for (int e = 0; e < M; e++) {\n        int mx = X[edges[e].u] + X[edges[e].v]; // [0,2000]\n        int my = Y[edges[e].u] + Y[edges[e].v];\n        int gx = min(GRID - 1, mx * GRID / 2001);\n        int gy = min(GRID - 1, my * GRID / 2001);\n        edges[e].cell = gx * GRID + gy;\n    }\n\n    int sampleTarget = 14;\n    if (N > 850 || M > 2500) sampleTarget = 12;\n    S = min(N, sampleTarget);\n\n    samples = select_samples(S);\n\n    baseDist.assign(S, vector<int>(N, UNREACH));\n    vector<double> imp(M, 0.0);\n\n    vector<int> dist(N), parent(N);\n    for (int si = 0; si < S; si++) {\n        int src = samples[si];\n        dijkstra_full_parent(src, dist, parent);\n        baseDist[si] = dist;\n        for (int v = 0; v < N; v++) {\n            if (v == src) continue;\n            int pe = parent[v];\n            if (pe >= 0) imp[pe] += 1.0;\n        }\n    }\n\n    for (int e = 0; e < M; e++) {\n        imp[e] += 1000.0 / edges[e].w;\n        imp[e] += 0.1 * (1.0 / degv[edges[e].u] + 1.0 / degv[edges[e].v]);\n        edges[e].imp = imp[e];\n    }\n\n    dayOf.assign(M, 0);\n    tmpDist.assign(N, UNREACH);\n    seen.assign(N, 0);\n    seenToken = 1;\n\n    vector<array<double,3>> params = {\n        {1.0, 4.0, 1.8},\n        {0.8, 5.0, 0.7},\n        {1.2, 3.2, 2.6}\n    };\n\n    vector<int> bestAssignInit;\n    vector<ll> bestDayScoreInit;\n    ll bestTotInit = (1LL << 62);\n\n    for (auto p : params) {\n        auto initAssign = build_initial_schedule(p[0], p[1], p[2]);\n        dayOf = initAssign;\n        vector<ll> ds;\n        ll tot = evaluate_total(ds);\n        if (tot < bestTotInit) {\n            bestTotInit = tot;\n            bestAssignInit = move(initAssign);\n            bestDayScoreInit = move(ds);\n        }\n    }\n\n    dayOf = bestAssignInit;\n    dayScore = bestDayScoreInit;\n    ll currentTotal = bestTotInit;\n\n    build_state_from_assignment();\n\n    vector<int> bestAssign = dayOf;\n    ll bestTotal = currentTotal;\n\n    const double TIME_LIMIT = 5.60;\n    const double T0 = 5e6;\n    const double T1 = 1e3;\n    const double logT0 = log(T0);\n    const double logT1 = log(T1);\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= TIME_LIMIT) break;\n        }\n        iter++;\n\n        bool generated = false;\n        bool isMove = false;\n        int e = -1, f = -1, toDay = -1;\n\n        for (int tr = 0; tr < 25 && !generated; tr++) {\n            int mode = rnd_int(100);\n\n            if (mode < 35) {\n                // targeted move: bad day -> good day\n                int d1 = day_with_max_score();\n                if (dayEdges[d1].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                int d2 = day_with_min_score_move(d1);\n                if (d2 < 0) continue;\n                if (!can_move_edge(e, d2)) continue;\n                isMove = true;\n                toDay = d2;\n                generated = true;\n\n            } else if (mode < 65) {\n                // targeted swap: bad day <-> good day\n                int d1 = day_with_max_score();\n                int d2 = day_with_min_score_swap(d1);\n                if (d2 < 0) continue;\n                if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                f = dayEdges[d2][rnd_int((int)dayEdges[d2].size())];\n                if (!can_swap_edges(e, f)) continue;\n                isMove = false;\n                generated = true;\n\n            } else {\n                // random\n                e = rnd_int(M);\n                if (rnd_int(2) == 0) {\n                    int d2 = rnd_int(D);\n                    if (!can_move_edge(e, d2)) continue;\n                    isMove = true;\n                    toDay = d2;\n                    generated = true;\n                } else {\n                    f = rnd_int(M);\n                    if (e == f) continue;\n                    if (!can_swap_edges(e, f)) continue;\n                    isMove = false;\n                    generated = true;\n                }\n            }\n        }\n\n        if (!generated) continue;\n\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        double temp = exp(logT0 + (logT1 - logT0) * progress);\n\n        if (isMove) {\n            int from = dayOf[e];\n            int to = toDay;\n\n            ll oldA = dayScore[from];\n            ll oldB = dayScore[to];\n\n            apply_move(e, from, to);\n\n            ll newA = compute_day_score(from);\n            ll newB = compute_day_score(to);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[from] = newA;\n                dayScore[to] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_move(e, to, from); // revert\n            }\n\n        } else {\n            int d1 = dayOf[e];\n            int d2 = dayOf[f];\n\n            ll oldA = dayScore[d1];\n            ll oldB = dayScore[d2];\n\n            apply_swap(e, f, d1, d2);\n\n            ll newA = compute_day_score(d1);\n            ll newB = compute_day_score(d2);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[d1] = newA;\n                dayScore[d2] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_swap(e, f, d2, d1); // revert\n            }\n        }\n    }\n\n    dayOf = bestAssign;\n\n    // defensive validity check\n    bool ok = true;\n    vector<int> checkCnt(D, 0);\n    for (int e = 0; e < M; e++) {\n        if (dayOf[e] < 0 || dayOf[e] >= D) ok = false;\n        else checkCnt[dayOf[e]]++;\n    }\n    for (int d = 0; d < D; d++) if (checkCnt[d] > K) ok = false;\n\n    if (!ok) {\n        // guaranteed feasible fallback\n        for (int e = 0; e < M; e++) dayOf[e] = e % D;\n    }\n\n    for (int e = 0; e < M; e++) {\n        if (e) cout << ' ';\n        cout << (dayOf[e] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seg { int s, stride; };\nstruct Occupancy {\n    vector<char> occ;\n    int vol = 0;\n};\nstruct Solution {\n    double score = 1e100;\n    int n = 0;\n    vector<int> b1, b2;\n};\n\nint D, N;\nint SX, SY, SZ;\nint maxLen;\n\narray<vector<string>, 2> F, Rv;\narray<vector<vector<int>>, 2> Xset, Yset;\n\nvector<vector<Seg>> allSegs;      // allSegs[L] (L>=3)\nvector<vector<int>> neighbors;    // 6-neighborhood\nvector<int> parityCell;           // (x+y+z)%2\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nvoid precompute() {\n    SX = D * D;\n    SY = D;\n    SZ = 1;\n    N = D * D * D;\n\n    for (int obj = 0; obj < 2; obj++) {\n        Xset[obj].clear();\n        Yset[obj].clear();\n        Xset[obj].resize(D);\n        Yset[obj].resize(D);\n        for (int z = 0; z < D; z++) {\n            for (int x = 0; x < D; x++) if (F[obj][z][x] == '1') Xset[obj][z].push_back(x);\n            for (int y = 0; y < D; y++) if (Rv[obj][z][y] == '1') Yset[obj][z].push_back(y);\n        }\n    }\n\n    parityCell.assign(N, 0);\n    neighbors.assign(N, {});\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        parityCell[id] = (x + y + z) & 1;\n        auto &nb = neighbors[id];\n        if (x > 0) nb.push_back(id - SX);\n        if (x + 1 < D) nb.push_back(id + SX);\n        if (y > 0) nb.push_back(id - SY);\n        if (y + 1 < D) nb.push_back(id + SY);\n        if (z > 0) nb.push_back(id - SZ);\n        if (z + 1 < D) nb.push_back(id + SZ);\n    }\n\n    maxLen = min(D, 10);\n    allSegs.assign(maxLen + 1, {});\n    for (int L = 3; L <= maxLen; L++) {\n        auto &v = allSegs[L];\n        v.reserve(3 * (D - L + 1) * D * D);\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int s = idx3(x, y, z);\n            if (x + L <= D) v.push_back({s, SX});\n            if (y + L <= D) v.push_back({s, SY});\n            if (z + L <= D) v.push_back({s, SZ});\n        }\n    }\n}\n\n// mode:\n// 0 = minimal grouped deterministic\n// 1 = minimal grouped randomized\n// 2 = minimal random surjection\n// 3 = star-like (a+b-1)\n// 4 = full (a*b)\nOccupancy build_occ(int obj, int mode, mt19937_64& rng) {\n    Occupancy oc;\n    oc.occ.assign(N, 0);\n    oc.vol = 0;\n\n    auto put = [&](int x, int y, int z) {\n        int id = idx3(x, y, z);\n        if (!oc.occ[id]) {\n            oc.occ[id] = 1;\n            oc.vol++;\n        }\n    };\n\n    for (int z = 0; z < D; z++) {\n        const auto &X = Xset[obj][z];\n        const auto &Y = Yset[obj][z];\n        int a = (int)X.size();\n        int b = (int)Y.size();\n\n        if (mode == 4) {\n            for (int x : X) for (int y : Y) put(x, y, z);\n            continue;\n        }\n\n        if (mode == 3) {\n            if (a >= b) {\n                int py = Y[(int)(rng() % b)];\n                for (int x : X) put(x, py, z);\n                for (int y : Y) {\n                    if (y == py) continue;\n                    int x = X[(int)(rng() % a)];\n                    put(x, y, z);\n                }\n            } else {\n                int px = X[(int)(rng() % a)];\n                for (int y : Y) put(px, y, z);\n                for (int x : X) {\n                    if (x == px) continue;\n                    int y = Y[(int)(rng() % b)];\n                    put(x, y, z);\n                }\n            }\n            continue;\n        }\n\n        if (mode == 0 || mode == 1) {\n            vector<int> Xv = X, Yv = Y;\n            if (mode == 1) {\n                if (rng() & 1ULL) reverse(Xv.begin(), Xv.end());\n                if (rng() & 1ULL) reverse(Yv.begin(), Yv.end());\n            }\n\n            if (a >= b) {\n                int shift = (mode == 1 ? (int)(rng() % b) : 0);\n                for (int j = 0; j < a; j++) {\n                    int g = (int)((long long)j * b / a);\n                    int y = Yv[(g + shift) % b];\n                    put(Xv[j], y, z);\n                }\n            } else {\n                int shift = (mode == 1 ? (int)(rng() % a) : 0);\n                for (int j = 0; j < b; j++) {\n                    int g = (int)((long long)j * a / b);\n                    int x = Xv[(g + shift) % a];\n                    put(x, Yv[j], z);\n                }\n            }\n            continue;\n        }\n\n        // mode == 2 : random surjection\n        if (a >= b) {\n            vector<int> Xv = X;\n            shuffle(Xv.begin(), Xv.end(), rng);\n\n            vector<int> pool;\n            pool.reserve(a);\n            for (int y : Y) pool.push_back(y);\n            for (int t = 0; t < a - b; t++) pool.push_back(Y[(int)(rng() % b)]);\n            shuffle(pool.begin(), pool.end(), rng);\n\n            for (int j = 0; j < a; j++) put(Xv[j], pool[j], z);\n        } else {\n            vector<int> Yv = Y;\n            shuffle(Yv.begin(), Yv.end(), rng);\n\n            vector<int> pool;\n            pool.reserve(b);\n            for (int x : X) pool.push_back(x);\n            for (int t = 0; t < b - a; t++) pool.push_back(X[(int)(rng() % a)]);\n            shuffle(pool.begin(), pool.end(), rng);\n\n            for (int j = 0; j < b; j++) put(pool[j], Yv[j], z);\n        }\n    }\n\n    return oc;\n}\n\nvector<Seg> pack_segments(const vector<char>& freeCells, int L, mt19937_64& rng) {\n    const auto &segs = allSegs[L];\n    vector<int> cand;\n    cand.reserve(segs.size());\n\n    for (int i = 0; i < (int)segs.size(); i++) {\n        const auto &sg = segs[i];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!freeCells[p]) { ok = false; break; }\n        }\n        if (ok) cand.push_back(i);\n    }\n\n    shuffle(cand.begin(), cand.end(), rng);\n\n    vector<char> tmp = freeCells;\n    vector<Seg> selected;\n    selected.reserve(cand.size() / max(1, L) + 1);\n\n    for (int id : cand) {\n        const auto &sg = segs[id];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!tmp[p]) { ok = false; break; }\n        }\n        if (!ok) continue;\n\n        selected.push_back(sg);\n        p = sg.s;\n        for (int t = 0; t < L; t++, p += sg.stride) tmp[p] = 0;\n    }\n\n    return selected;\n}\n\nvector<pair<int,int>> max_domino_matching(const vector<char>& freeCells) {\n    vector<int> lid(N, -1), rid(N, -1);\n    vector<int> leftCells, rightCells;\n    leftCells.reserve(N);\n    rightCells.reserve(N);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i]) continue;\n        if (parityCell[i] == 0) {\n            lid[i] = (int)leftCells.size();\n            leftCells.push_back(i);\n        } else {\n            rid[i] = (int)rightCells.size();\n            rightCells.push_back(i);\n        }\n    }\n\n    int Ls = (int)leftCells.size();\n    int Rs = (int)rightCells.size();\n\n    vector<vector<int>> g(Ls);\n    for (int u = 0; u < Ls; u++) {\n        int cell = leftCells[u];\n        auto &adj = g[u];\n        for (int nb : neighbors[cell]) {\n            if (!freeCells[nb]) continue;\n            int v = rid[nb];\n            if (v != -1) adj.push_back(v);\n        }\n    }\n\n    vector<int> dist(Ls), matchL(Ls, -1), matchR(Rs, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(dist.begin(), dist.end(), -1);\n        bool found = false;\n\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                int u2 = matchR[v];\n                if (u2 == -1) {\n                    found = true;\n                } else if (dist[u2] == -1) {\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n            }\n        }\n        return found;\n    };\n\n    auto dfs = [&](auto&& self, int u) -> bool {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && self(self, u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) dfs(dfs, u);\n        }\n    }\n\n    vector<pair<int,int>> pairs;\n    pairs.reserve(Ls);\n    for (int u = 0; u < Ls; u++) {\n        if (matchL[u] != -1) {\n            pairs.push_back({leftCells[u], rightCells[matchL[u]]});\n        }\n    }\n    return pairs;\n}\n\nSolution make_solution(const Occupancy& o1, const Occupancy& o2, mt19937_64& rng) {\n    vector<char> free1 = o1.occ;\n    vector<char> free2 = o2.occ;\n\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int id = 0;\n    int sharedVol = 0;\n    double sharedTerm = 0.0;\n\n    for (int L = maxLen; L >= 3; L--) {\n        auto segs1 = pack_segments(free1, L, rng);\n        auto segs2 = pack_segments(free2, L, rng);\n\n        int s = min((int)segs1.size(), (int)segs2.size());\n        if (s == 0) continue;\n\n        if ((int)segs1.size() > s) {\n            shuffle(segs1.begin(), segs1.end(), rng);\n            segs1.resize(s);\n        }\n        if ((int)segs2.size() > s) {\n            shuffle(segs2.begin(), segs2.end(), rng);\n            segs2.resize(s);\n        }\n\n        for (int i = 0; i < s; i++) {\n            ++id;\n            int p = segs1[i].s;\n            for (int t = 0; t < L; t++, p += segs1[i].stride) {\n                b1[p] = id;\n                free1[p] = 0;\n            }\n            p = segs2[i].s;\n            for (int t = 0; t < L; t++, p += segs2[i].stride) {\n                b2[p] = id;\n                free2[p] = 0;\n            }\n\n            sharedVol += L;\n            sharedTerm += 1.0 / (double)L;\n        }\n    }\n\n    auto dom1 = max_domino_matching(free1);\n    auto dom2 = max_domino_matching(free2);\n    int sd = min((int)dom1.size(), (int)dom2.size());\n\n    if (sd > 0) {\n        if ((int)dom1.size() > sd) {\n            shuffle(dom1.begin(), dom1.end(), rng);\n            dom1.resize(sd);\n        }\n        if ((int)dom2.size() > sd) {\n            shuffle(dom2.begin(), dom2.end(), rng);\n            dom2.resize(sd);\n        }\n\n        for (int i = 0; i < sd; i++) {\n            ++id;\n\n            auto [a, b] = dom1[i];\n            b1[a] = id; b1[b] = id;\n            free1[a] = 0; free1[b] = 0;\n\n            auto [c, d] = dom2[i];\n            b2[c] = id; b2[d] = id;\n            free2[c] = 0; free2[d] = 0;\n\n            sharedVol += 2;\n            sharedTerm += 0.5;\n        }\n    }\n\n    vector<int> rem1, rem2;\n    rem1.reserve(o1.vol - sharedVol);\n    rem2.reserve(o2.vol - sharedVol);\n\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) rem1.push_back(i);\n        if (free2[i]) rem2.push_back(i);\n    }\n\n    shuffle(rem1.begin(), rem1.end(), rng);\n    shuffle(rem2.begin(), rem2.end(), rng);\n\n    int sm = min((int)rem1.size(), (int)rem2.size());\n    for (int i = 0; i < sm; i++) {\n        ++id;\n        b1[rem1[i]] = id;\n        b2[rem2[i]] = id;\n\n        sharedVol += 1;\n        sharedTerm += 1.0;\n    }\n    for (int i = sm; i < (int)rem1.size(); i++) {\n        ++id;\n        b1[rem1[i]] = id;\n    }\n    for (int i = sm; i < (int)rem2.size(); i++) {\n        ++id;\n        b2[rem2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = (double)(o1.vol + o2.vol - 2 * sharedVol) + sharedTerm;\n    return sol;\n}\n\nbool check_silhouette_one(const vector<int>& b, int obj) {\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) {\n            bool seen = false;\n            for (int y = 0; y < D; y++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (F[obj][z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; y++) {\n            bool seen = false;\n            for (int x = 0; x < D; x++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (Rv[obj][z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nbool check_silhouette(const Solution& sol) {\n    if ((int)sol.b1.size() != N || (int)sol.b2.size() != N) return false;\n    return check_silhouette_one(sol.b1, 0) && check_silhouette_one(sol.b2, 1);\n}\n\nSolution fallback_simple() {\n    vector<int> b1(N, 0), b2(N, 0);\n    vector<int> c1, c2;\n    c1.reserve(N);\n    c2.reserve(N);\n\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (F[0][z][x] == '1' && Rv[0][z][y] == '1') c1.push_back(idx3(x, y, z));\n        if (F[1][z][x] == '1' && Rv[1][z][y] == '1') c2.push_back(idx3(x, y, z));\n    }\n\n    int id = 0;\n    int m = min((int)c1.size(), (int)c2.size());\n    for (int i = 0; i < m; i++) {\n        ++id;\n        b1[c1[i]] = id;\n        b2[c2[i]] = id;\n    }\n    for (int i = m; i < (int)c1.size(); i++) {\n        ++id;\n        b1[c1[i]] = id;\n    }\n    for (int i = m; i < (int)c2.size(); i++) {\n        ++id;\n        b2[c2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = 1e99;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        Rv[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> Rv[i][z];\n    }\n\n    precompute();\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count()\n        ^ (uint64_t)D * 1000003ULL\n    );\n\n    Solution best;\n\n    const double TL = 5.4;\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    vector<pair<int,int>> presets = {\n        {0,0}, {1,1}, {2,2}, {3,3}, {4,4},\n        {0,1}, {1,2}, {0,3}, {3,4}\n    };\n    size_t presetIdx = 0;\n    int iter = 0;\n\n    auto pick_mode = [&]() -> int {\n        int r = (int)(rng() % 100);\n        if (r < 30) return 0;\n        if (r < 55) return 1;\n        if (r < 75) return 2;\n        if (r < 90) return 3;\n        return 4;\n    };\n\n    while (elapsed() < TL) {\n        int m1, m2;\n        int reps = 1;\n\n        if (presetIdx < presets.size()) {\n            m1 = presets[presetIdx].first;\n            m2 = presets[presetIdx].second;\n            presetIdx++;\n            reps = 3;\n        } else {\n            if ((rng() % 100) < 60) {\n                int m = pick_mode();\n                m1 = m2 = m;\n            } else {\n                m1 = pick_mode();\n                m2 = pick_mode();\n            }\n            if (iter < 20) reps = 2;\n        }\n\n        Occupancy o1 = build_occ(0, m1, rng);\n        Occupancy o2 = build_occ(1, m2, rng);\n\n        for (int t = 0; t < reps; t++) {\n            Solution cur = make_solution(o1, o2, rng);\n            if (cur.score < best.score) best = move(cur);\n            if (elapsed() >= TL) break;\n        }\n        iter++;\n    }\n\n    if (best.n == 0 || !check_silhouette(best)) {\n        best = fallback_simple();\n    }\n\n    cout << best.n << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b2[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(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr long long INF = (1LL << 62);\n    static constexpr int MAXN = 105;\n    static constexpr int MAXM = 305;\n\n    int N, M, K;\n    struct Edge {\n        int u, v, w;\n    };\n\n    vector<int> x, y;\n    vector<Edge> edges;\n    vector<int> a, b;\n\n    vector<vector<pair<int, int>>> g; // (to, edge_id)\n    vector<vector<int>> incident;      // edge ids incident to vertex\n    vector<int> edgeOrder;             // edge ids sorted by weight\n\n    // dist station-resident\n    vector<vector<uint16_t>> distSR; // [N][K]\n    // for each resident: candidate stations within 5000, sorted by distance\n    vector<vector<pair<uint16_t, int>>> cand; // [K] -> (dist, station)\n\n    // all-pairs shortest path on station graph\n    vector<vector<long long>> spDist; // [N][N]\n    vector<vector<int>> prevNode;     // [src][v]\n    vector<vector<int>> prevEdge;     // [src][v]\n\n    chrono::steady_clock::time_point startTime;\n\n    struct Solution {\n        bool feasible = false;\n        long long cost = INF;\n        vector<int> P;\n        vector<char> B;\n    };\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    int ceilDist(int x1, int y1, int x2, int y2) {\n        long long dx = 1LL * x1 - x2;\n        long long dy = 1LL * y1 - y2;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)std::sqrt((double)sq);\n        while (1LL * d * d < sq) ++d;\n        while (d > 0 && 1LL * (d - 1) * (d - 1) >= sq) --d;\n        return d;\n    }\n\n    void readInput() {\n        cin >> N >> M >> K;\n        x.resize(N);\n        y.resize(N);\n        for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(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            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        }\n\n        a.resize(K);\n        b.resize(K);\n        for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n        edgeOrder.resize(M);\n        iota(edgeOrder.begin(), edgeOrder.end(), 0);\n        sort(edgeOrder.begin(), edgeOrder.end(),\n             [&](int e1, int e2) { return edges[e1].w < edges[e2].w; });\n    }\n\n    void precomputeDistances() {\n        distSR.assign(N, vector<uint16_t>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                int d = ceilDist(x[i], y[i], a[k], b[k]);\n                if (d > 65535) d = 65535;\n                distSR[i][k] = (uint16_t)d;\n            }\n        }\n\n        cand.assign(K, {});\n        for (int k = 0; k < K; k++) {\n            auto &vec = cand[k];\n            vec.reserve(N);\n            for (int i = 0; i < N; i++) {\n                int d = distSR[i][k];\n                if (d <= 5000) vec.push_back({(uint16_t)d, i});\n            }\n            sort(vec.begin(), vec.end(), [](auto &l, auto &r) {\n                if (l.first != r.first) return l.first < r.first;\n                return l.second < r.second;\n            });\n\n            // \u4fdd\u967a\uff08\u672c\u6765 generator \u4fdd\u8a3c\u3067\u7a7a\u306b\u306a\u3089\u306a\u3044\uff09\n            if (vec.empty()) {\n                int bestI = 0, bestD = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    int d = distSR[i][k];\n                    if (d < bestD) bestD = d, bestI = i;\n                }\n                vec.push_back({(uint16_t)bestD, bestI});\n            }\n        }\n    }\n\n    void precomputeShortestPaths() {\n        spDist.assign(N, vector<long long>(N, INF));\n        prevNode.assign(N, vector<int>(N, -1));\n        prevEdge.assign(N, vector<int>(N, -1));\n\n        for (int s = 0; s < N; s++) {\n            vector<long long> d(N, INF);\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            d[s] = 0;\n            prevNode[s][s] = s;\n            prevEdge[s][s] = -1;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n                if (cd != d[v]) continue;\n\n                for (auto [to, eid] : g[v]) {\n                    long long nd = cd + edges[eid].w;\n                    if (nd < d[to]) {\n                        d[to] = nd;\n                        prevNode[s][to] = v;\n                        prevEdge[s][to] = eid;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            spDist[s] = std::move(d);\n        }\n    }\n\n    long long steinerCostRaw(const int terminals[], int t, vector<char>* outB) {\n        if (outB) outB->assign(M, 0);\n        if (t <= 1) return 0;\n\n        // Prim on metric closure\n        long long minD[MAXN];\n        int parentIdx[MAXN];\n        bool used[MAXN];\n        for (int i = 0; i < t; i++) {\n            minD[i] = INF;\n            parentIdx[i] = -1;\n            used[i] = false;\n        }\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 (!used[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            if (v == -1) return INF;\n            used[v] = true;\n\n            int tv = terminals[v];\n            for (int j = 0; j < t; j++) {\n                if (used[j]) continue;\n                long long nd = spDist[tv][terminals[j]];\n                if (nd < minD[j]) {\n                    minD[j] = nd;\n                    parentIdx[j] = v;\n                }\n            }\n        }\n\n        char marked[MAXM];\n        char alive[MAXM];\n        for (int i = 0; i < M; i++) marked[i] = alive[i] = 0;\n\n        // Expand MST edges by shortest paths\n        for (int i = 1; i < t; i++) {\n            int s = terminals[parentIdx[i]];\n            int cur = terminals[i];\n            while (cur != s) {\n                int eid = prevEdge[s][cur];\n                if (eid < 0) return INF; // safety\n                marked[eid] = 1;\n                cur = prevNode[s][cur];\n            }\n        }\n\n        // Kruskal on selected edges\n        DSU dsu(N);\n        long long cost = 0;\n        for (int eid : edgeOrder) {\n            if (!marked[eid]) continue;\n            auto &e = edges[eid];\n            if (dsu.merge(e.u, e.v)) {\n                alive[eid] = 1;\n                cost += e.w;\n            }\n        }\n\n        // prune non-terminal leaves\n        int deg[MAXN];\n        char isTerm[MAXN];\n        for (int i = 0; i < N; i++) {\n            deg[i] = 0;\n            isTerm[i] = 0;\n        }\n        for (int i = 0; i < t; i++) isTerm[terminals[i]] = 1;\n\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        if (outB) {\n            outB->assign(M, 0);\n            for (int i = 0; i < M; i++) (*outB)[i] = alive[i];\n        }\n        return cost;\n    }\n\n    long long evaluateCostApprox(const vector<char>& active) {\n        int P[MAXN];\n        for (int i = 0; i < N; i++) P[i] = 0;\n\n        // nearest active station assignment\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            int d = 0;\n            for (auto &pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return INF; // uncovered\n            if (d > P[chosen]) P[chosen] = d;\n        }\n\n        long long power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0; // root always terminal in network\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        long long edgeCost = steinerCostRaw(terminals, t, nullptr);\n        if (edgeCost >= INF / 2) return INF;\n        return power + edgeCost;\n    }\n\n    bool checkCoverage(const vector<int>& P) {\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                if (P[st] >= d) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    }\n\n    void shrinkP(vector<int>& P) {\n        vector<int> cnt(K, 0);\n\n        // coverage counts\n        for (int i = 0; i < N; i++) {\n            int pi = P[i];\n            if (pi <= 0) continue;\n            for (int k = 0; k < K; k++) {\n                if (distSR[i][k] <= pi) cnt[k]++;\n            }\n        }\n\n        // sequentially reduce each station while preserving coverage\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int i = 0; i < N; i++) {\n                int old = P[i];\n                if (old <= 0) continue;\n\n                int req = 0;\n                for (int k = 0; k < K; k++) {\n                    int d = distSR[i][k];\n                    if (d <= old && cnt[k] == 1) {\n                        if (d > req) req = d;\n                    }\n                }\n\n                if (req < old) {\n                    for (int k = 0; k < K; k++) {\n                        int d = distSR[i][k];\n                        if (d <= old && d > req) cnt[k]--;\n                    }\n                    P[i] = req;\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    Solution buildSolution(const vector<char>& active, bool doShrink, bool withEdges) {\n        Solution sol;\n        sol.P.assign(N, 0);\n\n        // nearest active assignment\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            int d = 0;\n            for (auto &pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return sol; // infeasible\n            if (d > sol.P[chosen]) sol.P[chosen] = d;\n        }\n\n        if (doShrink) {\n            vector<int> backup = sol.P;\n            shrinkP(sol.P);\n            if (!checkCoverage(sol.P)) {\n                sol.P.swap(backup); // safety fallback\n            }\n        }\n\n        long long power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * sol.P[i] * sol.P[i];\n            if (i != 0 && sol.P[i] > 0) terminals[t++] = i;\n        }\n\n        vector<char> B;\n        long long edgeCost = steinerCostRaw(terminals, t, withEdges ? &B : nullptr);\n        if (edgeCost >= INF / 2) return sol;\n\n        sol.feasible = true;\n        sol.cost = power + edgeCost;\n        if (withEdges) sol.B = std::move(B);\n        return sol;\n    }\n\n    pair<vector<char>, long long> hillClimbApprox(vector<char> active, int maxSteps, double endTime) {\n        long long cur = evaluateCostApprox(active);\n\n        for (int step = 0; step < maxSteps && elapsed() < endTime; step++) {\n            long long best = cur;\n            int bestFlip = -1;\n\n            for (int i = 1; i < N; i++) { // do not flip root\n                active[i] ^= 1;\n                long long c = evaluateCostApprox(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n\n            if (bestFlip == -1) break;\n            active[bestFlip] ^= 1;\n            cur = best;\n        }\n\n        return {active, cur};\n    }\n\n    void solve() {\n        readInput();\n        startTime = chrono::steady_clock::now();\n\n        precomputeDistances();\n        precomputeShortestPaths();\n\n        vector<char> allOn(N, 1);\n        allOn[0] = 1; // root always active in our search\n\n        // Main approximate search\n        const double searchEnd = 1.45;\n        auto base = hillClimbApprox(allOn, 80, searchEnd);\n        vector<char> bestActive = base.first;\n        long long bestCost = base.second;\n\n        mt19937 rng(123456789);\n\n        // random kicks + short hill climb\n        if (N > 1) {\n            while (elapsed() < searchEnd) {\n                vector<char> trial = bestActive;\n                int flips = 2 + (rng() & 1); // 2 or 3\n                for (int t = 0; t < flips; t++) {\n                    int idx = 1 + (rng() % (N - 1));\n                    trial[idx] ^= 1;\n                }\n\n                auto res = hillClimbApprox(trial, 20, searchEnd);\n                if (res.second < bestCost) {\n                    bestCost = res.second;\n                    bestActive = std::move(res.first);\n                }\n            }\n        }\n\n        // Build exact-ish solution and do remove-only refinement\n        auto curSol = buildSolution(bestActive, true, false);\n        if (!curSol.feasible) {\n            bestActive = allOn;\n            curSol = buildSolution(bestActive, true, false);\n        }\n        long long curCost = curSol.feasible ? curSol.cost : INF;\n\n        const double exactEnd = 1.85;\n        for (int pass = 0; pass < 3 && elapsed() < exactEnd; pass++) {\n            bool changed = false;\n            for (int i = 1; i < N && elapsed() < exactEnd; i++) {\n                if (!bestActive[i]) continue;\n                bestActive[i] = 0;\n                auto candSol = buildSolution(bestActive, true, false);\n                if (candSol.feasible && candSol.cost < curCost) {\n                    curCost = candSol.cost;\n                    changed = true;\n                } else {\n                    bestActive[i] = 1;\n                }\n            }\n            if (!changed) break;\n        }\n\n        auto ans = buildSolution(bestActive, true, true);\n        if (!ans.feasible) {\n            ans = buildSolution(allOn, true, true);\n        }\n        if (ans.B.empty()) ans.B.assign(M, 0);\n\n        // Output\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n\n        for (int j = 0; j < M; j++) {\n            if (j) cout << ' ';\n            cout << int(ans.B[j]);\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}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nstruct Result {\n    vector<Move> ops;\n    int E = (int)1e9;\n\n    long long score() const {\n        if (E == 0) return 100000LL - 5LL * (long long)ops.size();\n        return 50000LL - 50LL * (long long)E;\n    }\n};\n\nusing Board = array<array<int, N>, N>;\n\nstatic bool same_unordered(const Move& a, const Move& b) {\n    return (a.x1 == b.x1 && a.y1 == b.y1 && a.x2 == b.x2 && a.y2 == b.y2) ||\n           (a.x1 == b.x2 && a.y1 == b.y2 && a.x2 == b.x1 && a.y2 == b.y1);\n}\n\nstatic vector<Move> compress_ops(const vector<Move>& ops) {\n    vector<Move> st;\n    st.reserve(ops.size());\n    for (const auto& mv : ops) {\n        if (!st.empty() && same_unordered(st.back(), mv)) {\n            st.pop_back();\n        } else {\n            st.push_back(mv);\n        }\n    }\n    return st;\n}\n\n// mode:\n// 0: \u4e21\u65b9\u9078\u3079\u308b\u306a\u3089\u4e0a\u5de6\u512a\u5148\n// 1: \u4e21\u65b9\u9078\u3079\u308b\u306a\u3089\u4e0a\u53f3\u512a\u5148\n// 2: \u4e21\u65b9\u9078\u3079\u308b\u306a\u3089\u300c\u89aa\u5024\u304c\u5927\u304d\u3044\u65b9\u300d\u3092\u4e0b\u306b\u843d\u3068\u3059\n// 3: \u4e21\u65b9\u9078\u3079\u308b\u306a\u3089\u300c\u89aa\u5024\u304c\u5c0f\u3055\u3044\u65b9\u300d\u3092\u4e0b\u306b\u843d\u3068\u3059\nstatic Result run_variant(const Board& init, bool mirror, int mode) {\n    Board a{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            a[x][y] = mirror ? init[x][x - y] : init[x][y];\n        }\n    }\n\n    vector<Move> ops;\n    ops.reserve(5000);\n\n    auto 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    // \u4e0a\u304b\u3089\u9806\u306b\u78ba\u5b9a\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            // \u30b3\u30fc\u30f3 C(x,y) \u306e\u6700\u5c0f\u5024\u3092\u63a2\u3059\n            int best_val = INT_MAX;\n            int sx = x, sy = y;\n            for (int r = x; r < N; ++r) {\n                int cmax = y + (r - x);\n                for (int c = y; c <= cmax; ++c) {\n                    int v = a[r][c];\n                    if (v < best_val) {\n                        best_val = v;\n                        sx = r;\n                        sy = c;\n                    }\n                }\n            }\n\n            // (sx,sy) -> (x,y) \u306b\u4e0a\u65b9\u5411\u3067\u5f15\u304d\u4e0a\u3052\u308b\n            int cx = sx, cy = sy;\n            while (cx > x) {\n                int rem = cx - x;   // \u6b8b\u308a\u6bb5\u6570\n                int delta = cy - y; // \u5de6\u3078\u4f55\u56de\u5bc4\u305b\u308b\u5fc5\u8981\u304c\u3042\u308b\u304b\n\n                bool canL = (delta > 0);      // \u4e0a\u5de6\u3078\u884c\u3051\u308b\uff08\u884c\u304f\u5fc5\u8981\u3042\u308a\uff09\n                bool canR = (delta < rem);    // \u4e0a\u53f3\u3078\u884c\u3063\u3066\u3082\u307e\u3060\u9593\u306b\u5408\u3046\n\n                bool goL;\n                if (canL && !canR) goL = true;\n                else if (!canL && canR) goL = false;\n                else {\n                    // \u4e21\u65b9\u9078\u3079\u308b\n                    if (mode == 0) goL = true;\n                    else if (mode == 1) goL = false;\n                    else {\n                        int vL = a[cx - 1][cy - 1];\n                        int vR = a[cx - 1][cy];\n                        if (mode == 2) goL = (vL > vR);\n                        else goL = (vL < vR); // mode == 3\n                    }\n                }\n\n                if (goL) {\n                    do_swap(cx, cy, cx - 1, cy - 1);\n                    --cx; --cy;\n                } else {\n                    do_swap(cx, cy, cx - 1, cy);\n                    --cx;\n                }\n            }\n        }\n    }\n\n    // \u53cd\u8ee2\u64cd\u4f5c\u306e\u6253\u3061\u6d88\u3057\u5727\u7e2e\uff08\u9023\u7d9a\u540c\u4e00\u8fbaswap\u306e\u9664\u53bb\uff09\n    ops = compress_ops(ops);\n\n    // E\u8a08\u7b97\uff08\u76e4\u9762\u306f\u5727\u7e2e\u3057\u3066\u3082\u540c\u3058\u6700\u7d42\u72b6\u614b\uff09\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v = a[x][y];\n            if (v > a[x + 1][y]) ++E;\n            if (v > a[x + 1][y + 1]) ++E;\n        }\n    }\n\n    // \u53cd\u8ee2\u7248\u3092\u5143\u5ea7\u6a19\u7cfb\u3078\u623b\u3059\n    if (mirror) {\n        for (auto& mv : ops) {\n            mv.y1 = mv.x1 - mv.y1;\n            mv.y2 = mv.x2 - mv.y2;\n        }\n    }\n\n    Result res;\n    res.ops = std::move(ops);\n    res.E = E;\n    return res;\n}\n\nstatic bool better(const Result& a, const Result& b) {\n    if (a.score() != b.score()) return a.score() > b.score();\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\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    Result best;\n    bool has_best = false;\n\n    for (int mir = 0; mir < 2; ++mir) {\n        for (int mode = 0; mode < 4; ++mode) {\n            Result cur = run_variant(init, (bool)mir, mode);\n            if (!has_best || better(cur, best)) {\n                best = std::move(cur);\n                has_best = true;\n            }\n        }\n    }\n\n    // \u5b89\u5168\u4e0a\u3053\u306e\u5b9f\u88c5\u3067\u306f\u5e38\u306b\u5341\u5206\u5c0f\u3055\u3044\u306f\u305a\n    if ((int)best.ops.size() > 10000) {\n        // \u7406\u8ad6\u4e0a\u3053\u3053\u306b\u306f\u6765\u306a\u3044\n        best.ops.resize(10000);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& mv : best.ops) {\n        cout << mv.x1 << ' ' << mv.y1 << ' ' << mv.x2 << ' ' << mv.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int r, c;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    if (!(cin >> D >> N)) return 0;\n\n    const int er = 0;\n    const int ec = (D - 1) / 2;\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    auto inb = [&](int r, int c) -> bool {\n        return (0 <= r && r < D && 0 <= c && c < D);\n    };\n\n    // Build free-cell list (excluding entrance and obstacles)\n    vector<vector<int>> id(D, vector<int>(D, -1));\n    vector<Pos> cells;\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            if (i == er && j == ec) continue;\n            if (obstacle[i][j]) continue;\n            id[i][j] = (int)cells.size();\n            cells.push_back({i, j});\n        }\n    }\n\n    const int M = (int)cells.size(); // number of containers\n    const int ENT = M;               // entrance node id\n\n    // Graph: free cells + entrance\n    vector<vector<int>> adj(M + 1);\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = cells[i];\n        for (int d = 0; d < 4; d++) {\n            int nr = r + dr[d], nc = c + dc[d];\n            if (!inb(nr, nc) || obstacle[nr][nc]) continue;\n            if (nr == er && nc == ec) {\n                adj[i].push_back(ENT);\n                adj[ENT].push_back(i);\n            } else {\n                int j = id[nr][nc];\n                if (j >= 0) adj[i].push_back(j);\n            }\n        }\n    }\n\n    // Count reachable free nodes from entrance in induced graph of alive nodes excluding ban.\n    auto reachable_count = [&](const vector<char>& alive, int ban) -> int {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        int cnt = 0;\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (v == ENT) continue;\n                if (v == ban || !alive[v] || vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    // BFS distance from entrance in induced alive graph.\n    auto compute_dist = [&](const vector<char>& alive) -> vector<int> {\n        vector<int> dist(M, -1);\n        queue<int> q;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            int du = (u == ENT ? 0 : dist[u]);\n\n            for (int v : adj[u]) {\n                if (v == ENT) continue;\n                if (!alive[v]) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du + 1;\n                q.push(v);\n            }\n        }\n        return dist;\n    };\n\n    // ---------- Precompute structural priorities by reverse peeling ----------\n    vector<char> alive(M, 1);\n    vector<int> peel_step(M, -1);\n\n    for (int step = 0; step < M; step++) {\n        int rem = M - step;\n        auto dist = compute_dist(alive);\n\n        int best = -1;\n        int bestD = -1;\n        int bestTie = -1;\n\n        for (int i = 0; i < M; i++) {\n            if (!alive[i]) continue;\n            // Must keep remaining empties connected to entrance.\n            if (reachable_count(alive, i) != rem - 1) continue;\n\n            int d = dist[i];\n            int tie = abs(cells[i].r - er) + abs(cells[i].c - ec); // farther first\n            if (best == -1 ||\n                d > bestD ||\n                (d == bestD && tie > bestTie) ||\n                (d == bestD && tie == bestTie &&\n                 (cells[i].r > cells[best].r ||\n                  (cells[i].r == cells[best].r && cells[i].c > cells[best].c)))) {\n                best = i;\n                bestD = d;\n                bestTie = tie;\n            }\n        }\n\n        if (best == -1) {\n            // Fallback (should not happen)\n            for (int i = 0; i < M; i++) {\n                if (alive[i]) {\n                    best = i;\n                    break;\n                }\n            }\n        }\n\n        peel_step[best] = step;\n        alive[best] = 0;\n    }\n\n    vector<int> prio(M);\n    for (int i = 0; i < M; i++) {\n        prio[i] = M - 1 - peel_step[i]; // smaller = earlier desired unloading\n    }\n\n    vector<char> allAlive(M, 1);\n    vector<int> distStatic = compute_dist(allAlive);\n\n    // ---------- Online insertion ----------\n    vector<char> inU(M, 1);       // still empty (not occupied yet)\n    vector<char> unseen(M, 1);    // unseen labels\n    vector<int> labelAt(M, -1);   // label placed at each cell\n    vector<int> assigned;\n    assigned.reserve(M);\n\n    for (int d = 0; d < M; d++) {\n        int t;\n        if (!(cin >> t)) return 0;\n\n        int rem = M - d;\n\n        // Rank of current label among remaining labels\n        int qrank = 0;\n        for (int x = 0; x < t; x++) {\n            if (unseen[x]) qrank++;\n        }\n\n        // Legal candidates: deleting this empty vertex keeps remaining empties connected\n        vector<int> safe;\n        safe.reserve(rem);\n        for (int i = 0; i < M; i++) {\n            if (!inU[i]) continue;\n            if (reachable_count(inU, i) == rem - 1) safe.push_back(i);\n        }\n\n        bool low = (2 * qrank < rem);\n\n        auto better_tie = [&](int a, int b) -> bool {\n            if (b == -1) return true;\n            if (low) {\n                if (prio[a] != prio[b]) return prio[a] < prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] < distStatic[b];\n            } else {\n                if (prio[a] != prio[b]) return prio[a] > prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] > distStatic[b];\n            }\n            if (cells[a].r != cells[b].r) return cells[a].r < cells[b].r;\n            return cells[a].c < cells[b].c;\n        };\n\n        int best = -1;\n        long long bestScore = (1LL << 60);\n\n        for (int c : safe) {\n            int p = prio[c];\n\n            // Rank of this priority among remaining priorities\n            int rrank = 0;\n            for (int j = 0; j < M; j++) {\n                if (inU[j] && prio[j] < p) rrank++;\n            }\n\n            // Exact inversions with already assigned containers\n            int invPast = 0;\n            for (int a : assigned) {\n                int pa = prio[a];\n                int la = labelAt[a];\n                if (pa < p && la > t) invPast++;\n                if (pa > p && la < t) invPast++;\n            }\n\n            // Proxy objective: past exact + future quantile mismatch\n            long long score = (long long)invPast + llabs((long long)rrank - qrank);\n\n            if (best == -1 || score < bestScore || (score == bestScore && better_tie(c, best))) {\n                best = c;\n                bestScore = score;\n            }\n        }\n\n        if (best == -1) {\n            // Fallback (should not happen)\n            for (int i = 0; i < M; i++) {\n                if (inU[i]) {\n                    best = i;\n                    break;\n                }\n            }\n        }\n\n        inU[best] = 0;\n        unseen[t] = 0;\n        labelAt[best] = t;\n        assigned.push_back(best);\n\n        cout << cells[best].r << ' ' << cells[best].c << '\\n' << flush;\n    }\n\n    // ---------- Offline unloading: beam search ----------\n    struct Node {\n        uint64_t lo, hi;   // removed cell mask\n        uint64_t llo, lhi; // removed label mask\n        int cost;          // inversion count accumulated\n        int parent;        // parent node index\n        int mv;            // removed cell at this step\n    };\n\n    auto getbit = [&](uint64_t lo, uint64_t hi, int b) -> bool {\n        if (b < 64) return ((lo >> b) & 1ULL) != 0ULL;\n        return ((hi >> (b - 64)) & 1ULL) != 0ULL;\n    };\n    auto setbit = [&](uint64_t& lo, uint64_t& hi, int b) {\n        if (b < 64) lo |= (1ULL << b);\n        else hi |= (1ULL << (b - 64));\n    };\n    auto popBelow = [&](uint64_t lo, uint64_t hi, int k) -> int {\n        if (k <= 0) return 0;\n        if (k < 64) {\n            uint64_t mask = (1ULL << k) - 1ULL;\n            return __builtin_popcountll(lo & mask);\n        } else if (k == 64) {\n            return __builtin_popcountll(lo);\n        } else {\n            int kk = k - 64; // <= 16\n            uint64_t mask = (1ULL << kk) - 1ULL;\n            return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n        }\n    };\n\n    auto accessible_from_mask = [&](uint64_t lo, uint64_t hi) -> vector<int> {\n        vector<int> cand;\n        cand.reserve(16);\n\n        vector<char> vis(M + 1, 0), inCand(M, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n\n            for (int v : adj[u]) {\n                if (v == ENT) continue;\n                if (getbit(lo, hi, v)) {\n                    if (!vis[v]) {\n                        vis[v] = 1;\n                        q.push(v);\n                    }\n                } else {\n                    if (!inCand[v]) {\n                        inCand[v] = 1;\n                        cand.push_back(v);\n                    }\n                }\n            }\n        }\n        return cand;\n    };\n\n    const int BEAM_WIDTH = 300;\n\n    vector<Node> nodes;\n    nodes.reserve(1 + BEAM_WIDTH * (M + 1));\n    nodes.push_back({0ULL, 0ULL, 0ULL, 0ULL, 0, -1, -1});\n\n    vector<int> beam = {0};\n\n    for (int depth = 0; depth < M; depth++) {\n        vector<Node> next;\n        next.reserve((int)beam.size() * 12);\n\n        for (int sid : beam) {\n            const Node& st = nodes[sid];\n            auto cand = accessible_from_mask(st.lo, st.hi);\n\n            for (int c : cand) {\n                Node nx = st;\n                setbit(nx.lo, nx.hi, c);\n\n                int lab = labelAt[c];\n                int removedSmaller = popBelow(st.llo, st.lhi, lab);\n                nx.cost = st.cost + (lab - removedSmaller);\n\n                setbit(nx.llo, nx.lhi, lab);\n                nx.parent = sid;\n                nx.mv = c;\n                next.push_back(nx);\n            }\n        }\n\n        if (next.empty()) break;\n\n        // Deduplicate by removed-cell mask: keep minimum cost\n        sort(next.begin(), next.end(), [](const Node& a, const Node& b) {\n            if (a.lo != b.lo) return a.lo < b.lo;\n            if (a.hi != b.hi) return a.hi < b.hi;\n            return a.cost < b.cost;\n        });\n\n        vector<Node> uniq;\n        uniq.reserve(next.size());\n        for (const auto& nd : next) {\n            if (uniq.empty() || nd.lo != uniq.back().lo || nd.hi != uniq.back().hi) {\n                uniq.push_back(nd);\n            }\n        }\n\n        if ((int)uniq.size() > BEAM_WIDTH) {\n            nth_element(uniq.begin(), uniq.begin() + BEAM_WIDTH, uniq.end(),\n                        [](const Node& a, const Node& b) { return a.cost < b.cost; });\n            uniq.resize(BEAM_WIDTH);\n        }\n\n        sort(uniq.begin(), uniq.end(), [](const Node& a, const Node& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.lo != b.lo) return a.lo < b.lo;\n            return a.hi < b.hi;\n        });\n\n        beam.clear();\n        beam.reserve(uniq.size());\n        for (const auto& nd : uniq) {\n            nodes.push_back(nd);\n            beam.push_back((int)nodes.size() - 1);\n        }\n    }\n\n    vector<int> order;\n    if (!beam.empty()) {\n        int bestState = beam[0];\n        for (int sid : beam) {\n            if (nodes[sid].cost < nodes[bestState].cost) bestState = sid;\n        }\n\n        while (bestState != -1 && nodes[bestState].parent != -1) {\n            order.push_back(nodes[bestState].mv);\n            bestState = nodes[bestState].parent;\n        }\n        reverse(order.begin(), order.end());\n    }\n\n    // Fallback (just in case beam ended abnormally)\n    if ((int)order.size() != M) {\n        order.clear();\n        order.reserve(M);\n        uint64_t lo = 0ULL, hi = 0ULL;\n\n        for (int step = 0; step < M; step++) {\n            auto cand = accessible_from_mask(lo, hi);\n            int best = -1;\n            for (int c : cand) {\n                if (best == -1 || labelAt[c] < labelAt[best]) best = c;\n            }\n            if (best == -1) {\n                for (int i = 0; i < M; i++) {\n                    if (!getbit(lo, hi, i)) {\n                        best = i;\n                        break;\n                    }\n                }\n            }\n            setbit(lo, hi, best);\n            order.push_back(best);\n        }\n    }\n\n    for (int c : order) {\n        cout << cells[c].r << ' ' << cells[c].c << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nconstexpr int NMAX = 50;\nconstexpr int CMAX = 101;\nconstexpr int INF = 1e9;\n\nstruct Problem {\n    int n = 0, m = 0;\n    array<array<int, NMAX>, NMAX> initGrid{};\n    array<int, CMAX> initCnt{};\n    array<array<int, CMAX>, CMAX> initEdgeCnt{};\n    array<array<bool, CMAX>, CMAX> targetAdj{};\n    array<bool, CMAX> canZero{};\n    array<int, CMAX> depth{};\n};\n\nstruct State {\n    const Problem* pb = nullptr;\n\n    array<array<int, NMAX>, NMAX> g{};\n    array<int, CMAX> cnt{};\n    array<array<int, CMAX>, CMAX> edgeCnt{};\n    int zeroCount = 0;\n\n    array<array<int, NMAX>, NMAX> vis{};\n    int visToken = 1;\n\n    State() = default;\n    explicit State(const Problem* p) { init(p); }\n\n    void init(const Problem* p) {\n        pb = p;\n        g = pb->initGrid;\n        cnt = pb->initCnt;\n        edgeCnt = pb->initEdgeCnt;\n        zeroCount = cnt[0];\n        for (auto& row : vis) row.fill(0);\n        visToken = 1;\n    }\n\n    inline bool in(int x, int y) const {\n        return (0 <= x && x < pb->n && 0 <= y && y < pb->n);\n    }\n\n    bool connected_after_remove(int ri, int rj, int color, int si, int sj) {\n        int need = cnt[color] - 1;\n        if (need <= 0) return false;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        vis[si][sj] = visToken;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != color) continue;\n                if (vis[nx][ny] == visToken) continue;\n\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n                if (reached == need) return true;\n            }\n        }\n        return reached == need;\n    }\n\n    bool try_change(int i, int j, int b) {\n        int a = g[i][j];\n        if (a == 0 || a == b) return false;\n\n        // Keep all non-zero colors non-empty.\n        if (cnt[a] <= 1) return false;\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // New color connectivity local check.\n        if (b == 0) {\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary) {\n                bool adj0 = false;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == 0) {\n                        adj0 = true;\n                        break;\n                    }\n                }\n                if (!adj0) return false;\n            }\n        } else {\n            if (cnt[b] > 0) {\n                bool adjb = false;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == b) {\n                        adjb = true;\n                        break;\n                    }\n                }\n                if (!adjb) return false;\n            }\n        }\n\n        // Edge count delta around (i,j).\n        int pu[8], pv[8], pd[8], psz = 0;\n\n        auto add_delta = [&](int x, int y, int d) {\n            if (x == y) return;\n            if (x > y) swap(x, y);\n            for (int t = 0; t < psz; t++) {\n                if (pu[t] == x && pv[t] == y) {\n                    pd[t] += d;\n                    return;\n                }\n            }\n            pu[psz] = x;\n            pv[psz] = y;\n            pd[psz] = d;\n            ++psz;\n        };\n\n        for (int dir = 0; dir < 4; dir++) {\n            int ni = i + dx[dir], nj = j + dy[dir];\n            int x = in(ni, nj) ? g[ni][nj] : 0;\n            add_delta(a, x, -1);\n            add_delta(b, x, +1);\n        }\n\n        // Adjacency graph must match target exactly.\n        for (int t = 0; t < psz; t++) {\n            int u = pu[t], v = pv[t];\n            int nc = edgeCnt[u][v] + pd[t];\n            if (nc < 0) return false;\n            bool present = (nc > 0);\n            if (present != pb->targetAdj[u][v]) return false;\n        }\n\n        // Old color connectivity check after removal.\n        int same = 0, si = -1, sj = -1;\n        for (int dir = 0; dir < 4; dir++) {\n            int ni = i + dx[dir], nj = j + dy[dir];\n            if (in(ni, nj) && g[ni][nj] == a) {\n                ++same;\n                if (si == -1) {\n                    si = ni;\n                    sj = nj;\n                }\n            }\n        }\n        if (same == 0) return false; // should not happen if connected and cnt[a] > 1\n        if (same >= 2) {\n            if (!connected_after_remove(i, j, a, si, sj)) return false;\n        }\n\n        // Apply.\n        g[i][j] = b;\n        --cnt[a];\n        ++cnt[b];\n        if (b == 0) ++zeroCount;\n\n        for (int t = 0; t < psz; t++) {\n            edgeCnt[pu[t]][pv[t]] += pd[t];\n        }\n        return true;\n    }\n\n    // value[c] defines allowed direction: recolor only to lower value.\n    void optimize(const vector<int>& value, mt19937& rng, Clock::time_point deadline) {\n        vector<int> order(pb->n * pb->n);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < 250; pass++) {\n            bool changed = false;\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int t = 0; t < (int)order.size(); t++) {\n                if ((t & 127) == 0 && Clock::now() >= deadline) return;\n\n                int idx = order[t];\n                int i = idx / pb->n;\n                int j = idx % pb->n;\n                int a = g[i][j];\n                if (a == 0) continue;\n\n                // First priority: delete to 0 if possible.\n                if (pb->canZero[a]) {\n                    if (try_change(i, j, 0)) {\n                        changed = true;\n                        continue;\n                    }\n                }\n\n                // Second: recolor to neighboring non-zero color with lower value.\n                int cand[4], k = 0;\n                static const int dx[4] = {-1, 1, 0, 0};\n                static const int dy[4] = {0, 0, -1, 1};\n\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b <= 0 || b == a) continue;\n                    if (value[b] >= value[a]) continue;\n\n                    bool dup = false;\n                    for (int q = 0; q < k; q++) {\n                        if (cand[q] == b) {\n                            dup = true;\n                            break;\n                        }\n                    }\n                    if (!dup) cand[k++] = b;\n                }\n                if (k == 0) continue;\n\n                // Randomize ties, then sort by value ascending.\n                for (int x = 0; x < k; x++) {\n                    int r = x + (int)(rng() % (k - x));\n                    swap(cand[x], cand[r]);\n                }\n                for (int x = 1; x < k; x++) {\n                    int key = cand[x];\n                    int y = x - 1;\n                    while (y >= 0 && value[cand[y]] > value[key]) {\n                        cand[y + 1] = cand[y];\n                        --y;\n                    }\n                    cand[y + 1] = key;\n                }\n\n                for (int q = 0; q < k; q++) {\n                    if (try_change(i, j, cand[q])) {\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n            if (Clock::now() >= deadline) return;\n        }\n    }\n};\n\nbool validate_solution(const State& st) {\n    const Problem& pb = *st.pb;\n    int n = pb.n, m = pb.m;\n\n    // Recompute color counts\n    array<int, CMAX> realCnt{};\n    realCnt.fill(0);\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (c < 0 || c > m) return false;\n            ++realCnt[c];\n        }\n    }\n    if (realCnt != st.cnt) return false;\n\n    // Adjacency check\n    array<array<bool, CMAX>, CMAX> adj{};\n    for (auto& row : adj) row.fill(false);\n\n    auto add_adj = [&](int a, int b) {\n        if (a == b) return;\n        adj[a][b] = adj[b][a] = true;\n    };\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (i + 1 < n) add_adj(c, st.g[i + 1][j]);\n            if (j + 1 < n) add_adj(c, st.g[i][j + 1]);\n            if (i == 0) add_adj(0, c);\n            if (i == n - 1) add_adj(0, c);\n            if (j == 0) add_adj(0, c);\n            if (j == n - 1) add_adj(0, c);\n        }\n    }\n\n    for (int u = 0; u <= m; u++) {\n        for (int v = u + 1; v <= m; v++) {\n            if (adj[u][v] != pb.targetAdj[u][v]) return false;\n        }\n    }\n\n    static const int dx[4] = {-1, 1, 0, 0};\n    static const int dy[4] = {0, 0, -1, 1};\n    auto in = [&](int x, int y) {\n        return (0 <= x && x < n && 0 <= y && y < n);\n    };\n\n    array<array<int, NMAX>, NMAX> vis{};\n    for (auto& row : vis) row.fill(0);\n    int token = 1;\n\n    // Connectivity for colors 1..m\n    for (int color = 1; color <= m; color++) {\n        int si = -1, sj = -1;\n        for (int i = 0; i < n && si == -1; i++) {\n            for (int j = 0; j < n; j++) {\n                if (st.g[i][j] == color) {\n                    si = i;\n                    sj = j;\n                    break;\n                }\n            }\n        }\n        if (si == -1) return false;\n\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        vis[si][sj] = token;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != color) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[color]) return false;\n    }\n\n    // Connectivity for color 0 through outside:\n    // every 0-cell must belong to a component touching boundary.\n    if (realCnt[0] > 0) {\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                if (i != 0 && i != n - 1 && j != 0 && j != n - 1) continue;\n                if (st.g[i][j] != 0) continue;\n                if (vis[i][j] == token) continue;\n                vis[i][j] = token;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n            }\n        }\n        if (tail == 0) return false; // zero cells exist, but none touches boundary\n\n        int reached = tail;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != 0) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem pb;\n    cin >> pb.n >> pb.m;\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            cin >> pb.initGrid[i][j];\n        }\n    }\n\n    pb.initCnt.fill(0);\n    for (auto& row : pb.initEdgeCnt) row.fill(0);\n    for (auto& row : pb.targetAdj) row.fill(false);\n    pb.canZero.fill(false);\n    pb.depth.fill(INF);\n\n    auto add_edge_count = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        pb.initEdgeCnt[a][b]++;\n    };\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            int c = pb.initGrid[i][j];\n            ++pb.initCnt[c];\n\n            if (i + 1 < pb.n) add_edge_count(c, pb.initGrid[i + 1][j]);\n            if (j + 1 < pb.n) add_edge_count(c, pb.initGrid[i][j + 1]);\n\n            if (i == 0) add_edge_count(0, c);\n            if (i == pb.n - 1) add_edge_count(0, c);\n            if (j == 0) add_edge_count(0, c);\n            if (j == pb.n - 1) add_edge_count(0, c);\n        }\n    }\n\n    for (int u = 0; u <= pb.m; u++) {\n        for (int v = u + 1; v <= pb.m; v++) {\n            if (pb.initEdgeCnt[u][v] > 0) {\n                pb.targetAdj[u][v] = pb.targetAdj[v][u] = true;\n            }\n        }\n    }\n    for (int c = 1; c <= pb.m; c++) {\n        pb.canZero[c] = pb.targetAdj[0][c];\n    }\n\n    // BFS distance from 0 in target adjacency graph.\n    queue<int> q;\n    pb.depth[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (int to = 0; to <= pb.m; to++) {\n            if (!pb.targetAdj[v][to]) continue;\n            if (pb.depth[to] != INF) continue;\n            pb.depth[to] = pb.depth[v] + 1;\n            q.push(to);\n        }\n    }\n    for (int c = 0; c <= pb.m; c++) {\n        if (pb.depth[c] == INF) pb.depth[c] = 1000;\n    }\n\n    auto globalDeadline = Clock::now() + chrono::milliseconds(1850);\n    mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    State best(&pb);\n    int bestScore = best.zeroCount;\n\n    int trial = 0;\n    while (Clock::now() < globalDeadline) {\n        State st(&pb);\n\n        vector<int> value(pb.m + 1, 0);\n        if (trial == 0) {\n            // Baseline: strict depth descent only.\n            for (int c = 1; c <= pb.m; c++) {\n                value[c] = pb.depth[c] * 1000;\n            }\n        } else {\n            // Random tie-breaking among same-depth colors (still acyclic).\n            vector<int> cols(pb.m);\n            iota(cols.begin(), cols.end(), 1);\n            shuffle(cols.begin(), cols.end(), rng);\n            vector<int> prio(pb.m + 1, 0);\n            for (int i = 0; i < pb.m; i++) prio[cols[i]] = i;\n            for (int c = 1; c <= pb.m; c++) {\n                value[c] = pb.depth[c] * 1000 + prio[c];\n            }\n        }\n\n        st.optimize(value, rng, globalDeadline);\n\n        if (st.zeroCount > bestScore) {\n            bestScore = st.zeroCount;\n            best = st;\n        }\n        ++trial;\n    }\n\n    // Safety check\n    if (!validate_solution(best)) {\n        best.init(&pb);\n    }\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            if (j) cout << ' ';\n            cout << best.g[i][j];\n        }\n        cout << '\\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    mt19937 rng;\n\n    vector<int> assign;              // item -> bin\n    vector<vector<int>> bins;        // bin -> items\n    vector<double> w_est;            // estimated item weights\n    vector<double> bin_sum_est;      // estimated bin sums\n    vector<int> rank_pos;            // estimated rank: 0=heaviest\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    static int ceil_log2_int(int x) {\n        int p = 1, c = 0;\n        while (p < x) p <<= 1, ++c;\n        return c;\n    }\n\n    static int insertion_cost(int n) {\n        int c = 0;\n        for (int m = 1; m < n; ++m) c += ceil_log2_int(m + 1);\n        return c;\n    }\n\n    char ask(const vector<int>& L, const vector<int>& R) {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n';\n        cout.flush();\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        if (s == \"-1\") exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char ask_single(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask(L, R);\n    }\n\n    // Full ranking by binary insertion sort (descending: heavy first).\n    vector<int> full_sort_items() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        shuffle(items.begin(), items.end(), rng);\n\n        vector<int> ord;\n        ord.reserve(N);\n        ord.push_back(items[0]);\n\n        for (int idx = 1; idx < N; ++idx) {\n            int x = items[idx];\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                char c = ask_single(x, ord[mid]);\n                if (c == '>') {\n                    hi = mid;        // x heavier -> left side\n                } else if (c == '<') {\n                    lo = mid + 1;    // x lighter -> right side\n                } else {\n                    lo = mid;\n                    hi = mid;\n                    break;\n                }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    // Budgeted coarse ranking for low-Q cases.\n    vector<int> partial_rank_budget(int budget) {\n        vector<int> score(N, 0);\n        vector<vector<int>> seen(N, vector<int>(N, 0));\n\n        auto cmp_and_update = [&](int a, int b) -> char {\n            char c = ask_single(a, b);\n            int x = min(a, b), y = max(a, b);\n            seen[x][y] = 1;\n            if (c == '>') {\n                score[a]++; score[b]--;\n            } else if (c == '<') {\n                score[a]--; score[b]++;\n            }\n            return c;\n        };\n\n        // Groups are kept in coarse descending order.\n        vector<vector<int>> groups(1, vector<int>(N));\n        iota(groups[0].begin(), groups[0].end(), 0);\n        shuffle(groups[0].begin(), groups[0].end(), rng);\n\n        // Split largest splittable group.\n        while (used < budget) {\n            int rem = budget - used;\n            int idx = -1, best = 0;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m >= 2 && m - 1 <= rem && m > best) {\n                    best = m;\n                    idx = g;\n                }\n            }\n            if (idx == -1) break;\n\n            vector<int> cur = groups[idx];\n            int m = (int)cur.size();\n            int pv = cur[uniform_int_distribution<int>(0, m - 1)(rng)];\n\n            vector<int> heavy, equalv, light;\n            equalv.push_back(pv);\n\n            for (int v : cur) {\n                if (v == pv) continue;\n                char c = cmp_and_update(v, pv);\n                if (c == '>') heavy.push_back(v);\n                else if (c == '<') light.push_back(v);\n                else equalv.push_back(v);\n            }\n\n            vector<vector<int>> repl;\n            if (!heavy.empty()) repl.push_back(move(heavy));\n            if (!equalv.empty()) repl.push_back(move(equalv));\n            if (!light.empty()) repl.push_back(move(light));\n\n            groups.erase(groups.begin() + idx);\n            groups.insert(groups.begin() + idx, repl.begin(), repl.end());\n        }\n\n        // Remaining budget: random comparisons, mainly within largest unresolved group.\n        while (used < budget) {\n            int idx = -1, best = 1;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m > best) best = m, idx = g;\n            }\n\n            int a, b;\n            if (idx != -1) {\n                auto& grp = groups[idx];\n                uniform_int_distribution<int> dist(0, (int)grp.size() - 1);\n\n                bool found_unseen = false;\n                for (int t = 0; t < 40; ++t) {\n                    a = grp[dist(rng)];\n                    do b = grp[dist(rng)]; while (b == a);\n                    int x = min(a, b), y = max(a, b);\n                    if (!seen[x][y]) {\n                        found_unseen = true;\n                        break;\n                    }\n                }\n                if (!found_unseen) {\n                    a = grp[dist(rng)];\n                    do b = grp[dist(rng)]; while (b == a);\n                }\n            } else {\n                uniform_int_distribution<int> dist(0, N - 1);\n                a = dist(rng);\n                do b = dist(rng); while (b == a);\n            }\n\n            cmp_and_update(a, b);\n        }\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto& grp : groups) {\n            sort(grp.begin(), grp.end(), [&](int x, int y) {\n                if (score[x] != score[y]) return score[x] > score[y];\n                return x < y;\n            });\n            for (int x : grp) ord.push_back(x);\n        }\n        return ord;\n    }\n\n    void build_est_weight_from_order(const vector<int>& order) {\n        vector<double> H(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0 / i;\n\n        w_est.assign(N, 0.0);\n        rank_pos.assign(N, N - 1);\n\n        for (int pos = 0; pos < N; ++pos) {\n            int id = order[pos];\n            rank_pos[id] = pos;\n            // Exponential order-stat expectation shape\n            w_est[id] = H[N] - H[pos];\n        }\n    }\n\n    void init_partition_lpt(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        for (int id : order) {\n            int best = 0;\n            for (int b = 1; b < D; ++b) {\n                if (bin_sum_est[b] < bin_sum_est[best]) best = b;\n            }\n            assign[id] = best;\n            bins[best].push_back(id);\n            bin_sum_est[best] += w_est[id];\n        }\n    }\n\n    void move_item(int item, int to) {\n        int from = assign[item];\n        if (from == to) return;\n\n        auto& vf = bins[from];\n        for (int k = 0; k < (int)vf.size(); ++k) {\n            if (vf[k] == item) {\n                vf[k] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        assign[item] = to;\n\n        bin_sum_est[from] -= w_est[item];\n        bin_sum_est[to] += w_est[item];\n    }\n\n    void swap_items(int i, int j) {\n        int a = assign[i], b = assign[j];\n        if (a == b) return;\n\n        auto& va = bins[a];\n        auto& vb = bins[b];\n        for (int& x : va) if (x == i) { x = j; break; }\n        for (int& x : vb) if (x == j) { x = i; break; }\n\n        assign[i] = b;\n        assign[j] = a;\n\n        double wi = w_est[i], wj = w_est[j];\n        bin_sum_est[a] += wj - wi;\n        bin_sum_est[b] += wi - wj;\n    }\n\n    inline double sq(double x) const { return x * x; }\n\n    void estimated_local_search() {\n        double total = 0.0;\n        for (double w : w_est) total += w;\n        double mean = total / D;\n\n        for (int iter = 0; iter < 300; ++iter) {\n            double best_delta = -1e-12;\n            int best_type = 0;\n            int bi = -1, bj = -1, bb = -1;\n\n            // Move\n            for (int i = 0; i < N; ++i) {\n                int a = assign[i];\n                if ((int)bins[a].size() <= 1) continue; // keep bins non-empty\n                double wi = w_est[i];\n                for (int b = 0; b < D; ++b) {\n                    if (b == a) continue;\n                    double delta =\n                        sq(bin_sum_est[a] - wi - mean) +\n                        sq(bin_sum_est[b] + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        best_type = 1;\n                        bi = i;\n                        bb = b;\n                    }\n                }\n            }\n\n            // Swap\n            for (int i = 0; i < N; ++i) {\n                for (int j = i + 1; j < N; ++j) {\n                    int a = assign[i], b = assign[j];\n                    if (a == b) continue;\n                    double wi = w_est[i], wj = w_est[j];\n                    double delta =\n                        sq(bin_sum_est[a] - wi + wj - mean) +\n                        sq(bin_sum_est[b] - wj + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        best_type = 2;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (best_type == 0) break;\n            if (best_type == 1) move_item(bi, bb);\n            else swap_items(bi, bj);\n        }\n    }\n\n    char cmp_bins(int a, int b) {\n        return ask(bins[a], bins[b]);\n    }\n\n    char cmp_after_move(int h, int l, int x) {\n        vector<int> L;\n        L.reserve(max(0, (int)bins[h].size() - 1));\n        for (int v : bins[h]) if (v != x) L.push_back(v);\n        vector<int> R = bins[l];\n        R.push_back(x);\n        return ask(L, R);\n    }\n\n    void reinsert_bin(vector<int>& ord, int b) {\n        int lo = 0, hi = (int)ord.size();\n        while (lo < hi && used < Q) {\n            int mid = (lo + hi) / 2;\n            char c = cmp_bins(b, ord[mid]);\n            if (c == '>') hi = mid;     // b heavier\n            else lo = mid + 1;\n        }\n        ord.insert(ord.begin() + lo, b);\n    }\n\n    void refine_with_queries() {\n        int rem = Q - used;\n        int sort_cost_bins = insertion_cost(D);\n        if (rem < sort_cost_bins + 18) return;\n\n        // Actual bin order (descending).\n        vector<int> ord;\n        ord.reserve(D);\n        for (int b = 0; b < D; ++b) {\n            reinsert_bin(ord, b);\n            if (used >= Q) return;\n        }\n\n        int guard = 0;\n        while (used < Q && guard < 10000) {\n            ++guard;\n\n            int h = -1;\n            for (int id : ord) {\n                if ((int)bins[id].size() > 1) { h = id; break; }\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int i = (int)ord.size() - 1; i >= 0; --i) {\n                if (ord[i] != h) { l = ord[i]; break; }\n            }\n            if (l == -1) break;\n\n            if (used >= Q) break;\n            char base = cmp_bins(h, l);\n            if (base == '=') break;\n            if (base == '<') swap(h, l); // ensure h heavier\n\n            // Candidate items in h: light -> heavy\n            vector<int> cand = bins[h];\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (rank_pos[a] != rank_pos[b]) return rank_pos[a] > rank_pos[b];\n                return a < b;\n            });\n\n            int m = (int)cand.size();\n            int lo = -1, hi = m; // lo: too light ('>'), hi: heavy enough ('<'/'=')\n            while (hi - lo > 1 && used < Q) {\n                int mid = (lo + hi) / 2;\n                int x = cand[mid];\n                char c = cmp_after_move(h, l, x);\n                if (c == '>') lo = mid;\n                else hi = mid;\n            }\n\n            if (lo == -1 && hi == m) break;\n            int chosen = (lo >= 0 ? cand[lo] : cand[hi]); // safe preference\n\n            move_item(chosen, l);\n\n            auto it = find(ord.begin(), ord.end(), h);\n            if (it != ord.end()) ord.erase(it);\n            it = find(ord.begin(), ord.end(), l);\n            if (it != ord.end()) ord.erase(it);\n\n            reinsert_bin(ord, h);\n            if (used >= Q) break;\n            reinsert_bin(ord, l);\n        }\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_single(0, 1);\n        }\n    }\n\n    void solve() {\n        if (!(cin >> N >> D >> Q)) return;\n\n        int full_cost = insertion_cost(N);\n        vector<int> order;\n\n        if (Q >= full_cost) order = full_sort_items();\n        else order = partial_rank_budget(Q);\n\n        if ((int)order.size() != N) {\n            vector<int> seen(N, 0);\n            for (int x : order) if (0 <= x && x < N) seen[x] = 1;\n            for (int i = 0; i < N; ++i) if (!seen[i]) order.push_back(i);\n        }\n\n        build_est_weight_from_order(order);\n        init_partition_lpt(order);\n        estimated_local_search();\n\n        if (Q >= full_cost) refine_with_queries();\n\n        fill_dummy_queries();\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << assign[i];\n        }\n        cout << '\\n';\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 200;\nconstexpr int MAXM = 10;\nconstexpr long long INF64 = (1LL << 60);\n\nstruct Params {\n    int w_cross;\n    int w_near;\n    int near_th;\n    int w_height;\n    int w_top;\n    int w_empty;\n    int w_boundary;\n    int horizon;\n};\n\nstruct State {\n    int len[MAXM];\n    int box[MAXM][MAXN]; // bottom -> top\n};\n\nstruct SegmentStats {\n    int total;\n    int segBottom;\n    int pref[MAXN + 1];\n};\n\nstruct Result {\n    long long energy = INF64;\n    vector<pair<int, int>> ops;\n    Params param{};\n};\n\ninline pair<int, int> find_box(const State& st, int m, int target) {\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < st.len[i]; ++j) {\n            if (st.box[i][j] == target) return {i, j};\n        }\n    }\n    return {-1, -1};\n}\n\ninline void move_segment(State& st, int src, int start, int dst) {\n    int k = st.len[src] - start;\n    for (int t = 0; t < k; ++t) {\n        st.box[dst][st.len[dst] + t] = st.box[src][start + t];\n    }\n    st.len[dst] += k;\n    st.len[src] = start;\n}\n\ninline SegmentStats build_segment_stats(const State& st, int n, int src, int start) {\n    SegmentStats ss{};\n    ss.total = st.len[src] - start;\n    ss.segBottom = st.box[src][start];\n\n    int freq[MAXN + 1];\n    fill(freq, freq + MAXN + 1, 0);\n    for (int i = start; i < st.len[src]; ++i) {\n        ++freq[st.box[src][i]];\n    }\n\n    ss.pref[0] = 0;\n    for (int v = 1; v <= n; ++v) ss.pref[v] = ss.pref[v - 1] + freq[v];\n    return ss;\n}\n\ninline long long heuristic_dest_score(\n    const State& st, int dst, int x,\n    const Params& p, const SegmentStats& ss\n) {\n    long long cross = 0;\n    long long near = 0;\n\n    for (int j = 0; j < st.len[dst]; ++j) {\n        int z = st.box[dst][j];\n        int cnt = ss.total - ss.pref[z]; // #moved boxes > z\n        if (cnt <= 0) continue;\n        cross += cnt;\n        int delta = z - x;\n        if (delta <= p.near_th) {\n            near += 1LL * cnt * (p.near_th + 1 - delta);\n        }\n    }\n\n    long long score = 0;\n    score += 1LL * p.w_cross * cross;\n    score += 1LL * p.w_near * near;\n    score += 1LL * p.w_height * st.len[dst];\n\n    if (st.len[dst] == 0) {\n        score -= p.w_empty;\n    } else {\n        int top = st.box[dst][st.len[dst] - 1];\n        score -= 1LL * p.w_top * top;\n        if (ss.segBottom > top) {\n            score += 1LL * p.w_boundary * (ss.segBottom - top);\n        }\n    }\n    return score;\n}\n\ninline int choose_dest(\n    const State& st, int n, int m,\n    int src, int start, int x, const Params& p\n) {\n    SegmentStats ss = build_segment_stats(st, n, src, start);\n\n    long long bestScore = INF64;\n    int bestD = -1;\n    for (int d = 0; d < m; ++d) {\n        if (d == src) continue;\n        long long sc = heuristic_dest_score(st, d, x, p, ss);\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestD = d;\n        } else if (sc == bestScore) {\n            if (bestD == -1 || st.len[d] < st.len[bestD] || (st.len[d] == st.len[bestD] && d < bestD)) {\n                bestD = d;\n            }\n        }\n    }\n    return bestD;\n}\n\nlong long rollout_energy(\n    State st, int n, int m,\n    int nextBox, int steps, const Params& p\n) {\n    long long energy = 0;\n\n    for (int t = 0; t < steps && nextBox <= n; ++t, ++nextBox) {\n        auto [s, pos] = find_box(st, m, nextBox);\n        if (s < 0) break; // should not happen\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int d = choose_dest(st, n, m, s, start, nextBox, p);\n            move_segment(st, s, start, d);\n            energy += k + 1;\n        }\n        st.len[s]--; // pop nextBox\n    }\n    return energy;\n}\n\nResult solve_with_params(const State& init, int n, int m, const Params& p) {\n    State st = init;\n\n    Result res;\n    res.energy = 0;\n    res.ops.reserve(600);\n    res.param = p;\n\n    for (int x = 1; x <= n; ++x) {\n        auto [s, pos] = find_box(st, m, x);\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int bestDest = -1;\n\n            if (p.horizon <= 1) {\n                bestDest = choose_dest(st, n, m, s, start, x, p);\n            } else {\n                SegmentStats ss = build_segment_stats(st, n, s, start);\n                long long bestEst = INF64;\n                long long bestHScore = INF64;\n\n                for (int d = 0; d < m; ++d) {\n                    if (d == s) continue;\n\n                    State tmp = st;\n                    move_segment(tmp, s, start, d);\n                    tmp.len[s]--; // pop x\n                    int steps = min(p.horizon - 1, n - x);\n                    long long est = 1LL * (k + 1) + rollout_energy(tmp, n, m, x + 1, steps, p);\n\n                    long long hscore = heuristic_dest_score(st, d, x, p, ss);\n\n                    if (est < bestEst ||\n                        (est == bestEst && hscore < bestHScore) ||\n                        (est == bestEst && hscore == bestHScore && d < bestDest)) {\n                        bestEst = est;\n                        bestHScore = hscore;\n                        bestDest = d;\n                    }\n                }\n            }\n\n            int v = st.box[s][start];\n            move_segment(st, s, start, bestDest);\n            res.energy += k + 1;\n            res.ops.push_back({v, bestDest + 1});\n        }\n\n        st.len[s]--; // pop x\n        res.ops.push_back({x, 0});\n    }\n\n    return res;\n}\n\nParams mutate_params(const Params& base, const vector<Params>& presets, mt19937& rng) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    Params p = base;\n\n    if (rnd(0, 4) == 0) {\n        p = presets[rnd(0, (int)presets.size() - 1)];\n    }\n\n    if (rnd(0, 9) == 0) {\n        p.w_cross    = rnd(500, 2000);\n        p.w_near     = rnd(0, 100);\n        p.near_th    = rnd(8, 55);\n        p.w_height   = rnd(-3, 15);\n        p.w_top      = rnd(0, 12);\n        p.w_empty    = rnd(200, 3500);\n        p.w_boundary = rnd(0, 80);\n        p.horizon    = rnd(1, 24);\n        return p;\n    }\n\n    p.w_cross    = clamp(p.w_cross + rnd(-250, 250), 400, 2200);\n    p.w_near     = clamp(p.w_near + rnd(-20, 20), 0, 120);\n    p.near_th    = clamp(p.near_th + rnd(-8, 8), 5, 70);\n    p.w_height   = clamp(p.w_height + rnd(-3, 3), -5, 20);\n    p.w_top      = clamp(p.w_top + rnd(-3, 3), 0, 20);\n    p.w_empty    = clamp(p.w_empty + rnd(-400, 400), 0, 5000);\n    p.w_boundary = clamp(p.w_boundary + rnd(-12, 12), 0, 120);\n    p.horizon    = clamp(p.horizon + rnd(-3, 3), 1, 24);\n\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n\n    State init{};\n    for (int i = 0; i < MAXM; ++i) init.len[i] = 0;\n\n    int h = n / m;\n    uint64_t seed = 1469598103934665603ULL;\n\n    for (int i = 0; i < m; ++i) {\n        init.len[i] = h;\n        for (int j = 0; j < h; ++j) {\n            cin >> init.box[i][j];\n            seed ^= (uint64_t)init.box[i][j] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    vector<Params> presets = {\n        {1000, 10, 20, 1, 1,  800, 10,  1},\n        {1000, 20, 24, 2, 1, 1200, 15,  8},\n        {1050, 30, 28, 2, 2, 1500, 20, 12},\n        {1100, 35, 32, 3, 2, 1700, 25, 16},\n        { 900, 45, 20, 1, 3, 1300, 15, 16},\n        {1200, 25, 40, 4, 1, 2000, 30, 20},\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    Result best;\n    best.energy = INF64;\n\n    // Deterministic presets\n    for (const auto& p : presets) {\n        Result r = solve_with_params(init, n, m, p);\n        if (r.energy < best.energy || (r.energy == best.energy && r.ops.size() < best.ops.size())) {\n            best = move(r);\n        }\n    }\n\n    // Small random parameter search under safe budget\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n    const double TIME_BUDGET = 1.65; // keep margin for 2.0 sec limit\n\n    while (elapsed() < TIME_BUDGET) {\n        Params cand = mutate_params(best.param, presets, rng);\n        Result r = solve_with_params(init, n, m, cand);\n        if (r.energy < best.energy || (r.energy == best.energy && r.ops.size() < best.ops.size())) {\n            best = move(r);\n        }\n    }\n\n    for (auto [v, i] : best.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Metric {\n    long long total = 0;\n    int L = 0;\n    bool valid = false;\n};\n\nclass Solver {\npublic:\n    void read_input() {\n        cin >> N;\n        hWall.resize(N - 1);\n        for (int i = 0; i < N - 1; i++) cin >> hWall[i];\n        vWall.resize(N);\n        for (int i = 0; i < N; i++) cin >> vWall[i];\n\n        V = N * N;\n        dirt.resize(V);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int x; cin >> x;\n                dirt[i * N + j] = x;\n            }\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n        build_graph();\n        precompute_apsp();\n\n        logd.assign(V, 0.0);\n        for (int i = 0; i < V; i++) logd[i] = log(1.0 + (double)dirt[i]);\n\n        firstVisit.assign(V, -1);\n        prevVisit.assign(V, -1);\n        tri.assign(V, 0);\n\n        string dfsRoute = build_dfs_route();\n        Metric bestM = evaluate(dfsRoute);\n        string bestRoute = dfsRoute;\n\n        const double T1 = 0.35;\n        const double T2 = 1.25;\n        const double TEND = 1.85;\n\n        int trial = 0;\n        while (elapsed() < T1) {\n            double a, b, g;\n            switch (trial % 6) {\n                case 0: a = 0.0; b = 1.6; g = 0.0; break;\n                case 1: a = 0.7; b = 1.2; g = 0.1; break;\n                case 2: a = 1.4; b = 0.8; g = 0.2; break;\n                default:\n                    a = rnd01() * 2.0;\n                    b = rnd01() * 2.0;\n                    g = rnd01() * 0.8;\n                    break;\n            }\n            string r = build_random_route(a, b, g);\n            Metric m = evaluate(r);\n            if (better(m, bestM)) {\n                bestM = m;\n                bestRoute = std::move(r);\n            }\n            trial++;\n        }\n\n        vector<int> ids(V);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int x, int y) {\n            if (dirt[x] != dirt[y]) return dirt[x] > dirt[y];\n            return x < y;\n        });\n        int K = min(V, 200);\n        vector<int> targets(ids.begin(), ids.begin() + K);\n\n        string curRoute = bestRoute;\n        Metric curM = bestM;\n        vector<int> pos = decode_positions(curRoute);\n        if (pos.empty()) {\n            curRoute = dfsRoute;\n            curM = evaluate(curRoute);\n            pos = decode_positions(curRoute);\n        }\n\n        const int MAXLEN = 30000;\n        const int MAXDIST = 12;\n\n        // Greedy targeted insertion: split largest interval of high-d cells.\n        while (elapsed() < T2) {\n            int L = (int)curRoute.size();\n            if (L <= 0) break;\n\n            vector<int> tid(V, -1);\n            for (int i = 0; i < K; i++) tid[targets[i]] = i;\n\n            vector<vector<int>> times(K);\n            for (int t = 1; t <= L; t++) {\n                int idx = tid[pos[t]];\n                if (idx >= 0) times[idx].push_back(t);\n            }\n\n            bool improved = false;\n            string bestCandRoute;\n            Metric bestCandM = curM;\n\n            for (int k = 0; k < K && elapsed() < T2; k++) {\n                const auto &tv = times[k];\n                if (tv.empty()) continue;\n\n                int start = tv.back();\n                int delta = tv.front() + L - tv.back();\n                for (int i = 0; i + 1 < (int)tv.size(); i++) {\n                    int d = tv[i + 1] - tv[i];\n                    if (d > delta) {\n                        delta = d;\n                        start = tv[i];\n                    }\n                }\n                if (delta <= 2) continue;\n\n                int target = targets[k];\n\n                int bestT = -1;\n                int bestD = 1e9;\n\n                for (int f = 1; f <= 3; f++) {\n                    int t = (int)((start + (long long)delta * f / 4) % L);\n                    int a = pos[t];\n                    int dd = (int)distMat[a][target];\n\n                    if (dd <= 0) {\n                        int t2 = (t + 1) % L;\n                        int dd2 = (int)distMat[pos[t2]][target];\n                        if (dd2 <= 0) continue;\n                        t = t2;\n                        dd = dd2;\n                    }\n\n                    if (dd < bestD) {\n                        bestD = dd;\n                        bestT = t;\n                    }\n                }\n\n                if (bestT < 0 || bestD > MAXDIST) continue;\n                if (L + 2 * bestD > MAXLEN) continue;\n\n                string det = build_detour(pos[bestT], target);\n                if (det.empty()) continue;\n\n                string cand = insert_detour(curRoute, bestT, det);\n                Metric m = evaluate(cand);\n                if (better(m, bestCandM)) {\n                    bestCandM = m;\n                    bestCandRoute = std::move(cand);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            curRoute = std::move(bestCandRoute);\n            curM = bestCandM;\n            pos = decode_positions(curRoute);\n            if (pos.empty()) break;\n        }\n\n        // Precompute high-d cells near each cell (for random insertion phase).\n        const int RAND_MAXDIST = 8;\n        vector<vector<int>> nearTargets(V);\n        for (int a = 0; a < V; a++) {\n            for (int x : targets) {\n                int dd = (int)distMat[a][x];\n                if (dd > 0 && dd <= RAND_MAXDIST) nearTargets[a].push_back(x);\n            }\n        }\n\n        // Random hill-climb: insert/remove small loops.\n        while (elapsed() < TEND) {\n            int L = (int)curRoute.size();\n            bool doInsert = ((int)(rng() % 100) < 75);\n            if (L >= MAXLEN) doInsert = false;\n\n            string cand;\n\n            if (doInsert) {\n                int t = (int)(rng() % (L + 1));\n                int a = pos[t];\n                auto &lst = nearTargets[a];\n                if (lst.empty()) continue;\n\n                int sample = min(10, (int)lst.size());\n                int chosen = -1;\n                double bestVal = -1.0;\n\n                for (int s = 0; s < sample; s++) {\n                    int x = lst[(int)(rng() % lst.size())];\n                    int dd = (int)distMat[a][x];\n                    if (dd <= 0) continue;\n                    if (L + 2 * dd > MAXLEN) continue;\n                    double v = (double)dirt[x] / dd;\n                    if (v > bestVal) {\n                        bestVal = v;\n                        chosen = x;\n                    }\n                }\n\n                if (chosen < 0) continue;\n                string det = build_detour(a, chosen);\n                if (det.empty()) continue;\n                cand = insert_detour(curRoute, t, det);\n            } else {\n                if (L < 4) continue;\n                int i = (int)(rng() % L);\n                int q = 2 * (1 + (int)(rng() % 12)); // 2..24\n                if (i + q > L) continue;\n                if (pos[i] != pos[i + q]) continue;\n                cand = remove_segment(curRoute, i, q);\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, curM)) {\n                curRoute = std::move(cand);\n                curM = m;\n                pos = decode_positions(curRoute);\n                if (pos.empty()) break;\n            }\n        }\n\n        Metric fin = evaluate(curRoute);\n        if (!fin.valid || (int)curRoute.size() > 100000) {\n            curRoute = dfsRoute; // guaranteed-valid fallback\n        }\n\n        cout << curRoute << '\\n';\n    }\n\nprivate:\n    int N = 0, V = 0;\n    vector<string> hWall, vWall;\n    vector<int> dirt;\n    vector<int> row, col;\n    vector<vector<int>> adj;\n    vector<array<int,4>> nxtMove; // U,D,L,R\n    vector<vector<int16_t>> distMat, nextHop;\n    vector<double> logd;\n\n    vector<int> firstVisit, prevVisit;\n    vector<long long> tri;\n\n    int dirMap[256]{};\n    mt19937_64 rng{ (uint64_t)chrono::steady_clock::now().time_since_epoch().count() };\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    double rnd01() {\n        return (rng() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    char dir_between(int u, int v) const {\n        if (row[v] == row[u] - 1) return 'U';\n        if (row[v] == row[u] + 1) return 'D';\n        if (col[v] == col[u] - 1) return 'L';\n        return 'R';\n    }\n\n    char opposite(char c) const {\n        if (c == 'U') return 'D';\n        if (c == 'D') return 'U';\n        if (c == 'L') return 'R';\n        return 'L';\n    }\n\n    void build_graph() {\n        fill(begin(dirMap), end(dirMap), -1);\n        dirMap[(unsigned char)'U'] = 0;\n        dirMap[(unsigned char)'D'] = 1;\n        dirMap[(unsigned char)'L'] = 2;\n        dirMap[(unsigned char)'R'] = 3;\n\n        row.resize(V);\n        col.resize(V);\n        adj.assign(V, {});\n        nxtMove.assign(V, array<int,4>{-1, -1, -1, -1});\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                row[id] = i;\n                col[id] = j;\n\n                if (i > 0 && hWall[i - 1][j] == '0') {\n                    int to = (i - 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][0] = to;\n                }\n                if (i + 1 < N && hWall[i][j] == '0') {\n                    int to = (i + 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][1] = to;\n                }\n                if (j > 0 && vWall[i][j - 1] == '0') {\n                    int to = i * N + (j - 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][2] = to;\n                }\n                if (j + 1 < N && vWall[i][j] == '0') {\n                    int to = i * N + (j + 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][3] = to;\n                }\n            }\n        }\n    }\n\n    void precompute_apsp() {\n        const int16_t INF = 30000;\n        distMat.assign(V, vector<int16_t>(V, INF));\n        nextHop.assign(V, vector<int16_t>(V, -1));\n\n        vector<int> q(V);\n\n        for (int s = 0; s < V; s++) {\n            auto &ds = distMat[s];\n            auto &ns = nextHop[s];\n            fill(ds.begin(), ds.end(), INF);\n            fill(ns.begin(), ns.end(), -1);\n\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            ds[s] = 0;\n            ns[s] = s;\n\n            while (head < tail) {\n                int u = q[head++];\n                for (int v : adj[u]) {\n                    if (ds[v] != INF) continue;\n                    ds[v] = ds[u] + 1;\n                    ns[v] = (u == s ? v : ns[u]);\n                    q[tail++] = v;\n                }\n            }\n        }\n    }\n\n    Metric evaluate(const string &route) {\n        int L = (int)route.size();\n        if (L <= 0 || L > 100000) return Metric{0, L, false};\n\n        fill(firstVisit.begin(), firstVisit.end(), -1);\n        fill(prevVisit.begin(), prevVisit.end(), -1);\n        fill(tri.begin(), tri.end(), 0LL);\n\n        int cur = 0;\n        for (int t = 1; t <= L; t++) {\n            unsigned char c = (unsigned char)route[t - 1];\n            int dir = dirMap[c];\n            if (dir < 0) return Metric{0, L, false};\n\n            int nx = nxtMove[cur][dir];\n            if (nx < 0) return Metric{0, L, false};\n\n            cur = nx;\n\n            if (prevVisit[cur] != -1) {\n                long long delta = t - prevVisit[cur];\n                tri[cur] += delta * (delta - 1) / 2;\n            } else {\n                firstVisit[cur] = t;\n            }\n            prevVisit[cur] = t;\n        }\n\n        if (cur != 0) return Metric{0, L, false};\n\n        long long total = 0;\n        for (int v = 0; v < V; v++) {\n            if (prevVisit[v] == -1) return Metric{0, L, false};\n            long long delta = (long long)firstVisit[v] + L - prevVisit[v];\n            tri[v] += delta * (delta - 1) / 2;\n            total += tri[v] * (long long)dirt[v];\n        }\n\n        return Metric{total, L, true};\n    }\n\n    bool better(const Metric &a, const Metric &b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        __int128 lhs = (__int128)a.total * b.L;\n        __int128 rhs = (__int128)b.total * a.L;\n        if (lhs != rhs) return lhs < rhs;\n        return a.L < b.L;\n    }\n\n    vector<int> decode_positions(const string &route) const {\n        vector<int> pos(route.size() + 1);\n        int cur = 0;\n        pos[0] = 0;\n        for (int i = 0; i < (int)route.size(); i++) {\n            int dir = dirMap[(unsigned char)route[i]];\n            if (dir < 0) return {};\n            int nx = nxtMove[cur][dir];\n            if (nx < 0) return {};\n            cur = nx;\n            pos[i + 1] = cur;\n        }\n        return pos;\n    }\n\n    string build_detour(int a, int target) const {\n        if (a == target) return \"\";\n\n        string fwd;\n        int u = a;\n        while (u != target) {\n            int v = nextHop[u][target];\n            if (v < 0) return \"\";\n            fwd.push_back(dir_between(u, v));\n            u = v;\n        }\n\n        string det = fwd;\n        for (int i = (int)fwd.size() - 1; i >= 0; i--) {\n            det.push_back(opposite(fwd[i]));\n        }\n        return det;\n    }\n\n    string insert_detour(const string &route, int t, const string &det) const {\n        string out;\n        out.reserve(route.size() + det.size());\n        out.append(route, 0, t);\n        out += det;\n        out.append(route, t, route.size() - t);\n        return out;\n    }\n\n    string remove_segment(const string &route, int l, int len) const {\n        string out;\n        out.reserve(route.size() - len);\n        out.append(route, 0, l);\n        out.append(route, l + len, route.size() - (l + len));\n        return out;\n    }\n\n    string build_dfs_route() {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            vector<int> nbs = adj[u];\n            sort(nbs.begin(), nbs.end(), [&](int x, int y) {\n                if (dirt[x] != dirt[y]) return dirt[x] > dirt[y];\n                return x < y;\n            });\n            for (int v : nbs) {\n                if (vis[v]) continue;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_random_route(double alpha, double beta, double gamma) {\n        vector<char> vis(V, 0);\n        vis[0] = 1;\n        int rem = V - 1;\n\n        int cur = 0;\n        string route;\n        route.reserve(V * 3);\n\n        while (rem > 0) {\n            if ((int)route.size() > 90000) return \"\";\n\n            int bestN = -1;\n            double bestS = -1e100;\n\n            for (int nb : adj[cur]) {\n                if (vis[nb]) continue;\n                int onward = 0;\n                for (int nb2 : adj[nb]) if (!vis[nb2]) onward++;\n                double sc = alpha * logd[nb] - beta * onward + rnd01() * 0.01;\n                if (sc > bestS) {\n                    bestS = sc;\n                    bestN = nb;\n                }\n            }\n\n            if (bestN != -1) {\n                route.push_back(dir_between(cur, bestN));\n                cur = bestN;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                continue;\n            }\n\n            int target = -1;\n            double bestVal = 1e100;\n            for (int v = 0; v < V; v++) {\n                if (vis[v]) continue;\n                int dd = (int)distMat[cur][v];\n                double val = (double)dd - gamma * logd[v] + rnd01() * 0.01;\n                if (val < bestVal) {\n                    bestVal = val;\n                    target = v;\n                }\n            }\n\n            if (target < 0) return \"\";\n\n            while (cur != target) {\n                int nx = nextHop[cur][target];\n                if (nx < 0) return \"\";\n                route.push_back(dir_between(cur, nx));\n                cur = nx;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                if ((int)route.size() > 90000) return \"\";\n            }\n        }\n\n        while (cur != 0) {\n            int nx = nextHop[cur][0];\n            if (nx < 0) return \"\";\n            route.push_back(dir_between(cur, nx));\n            cur = nx;\n            if ((int)route.size() > 90000) return \"\";\n        }\n\n        return route;\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}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % (uint64_t)n); }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstruct Solver {\n    int N{}, M{}, V{};\n    int si{}, sj{}, startId{};\n    vector<string> board;\n    vector<string> words;\n\n    array<vector<int>, 26> occ;\n    int distMat[225][225]{};\n\n    vector<vector<int>> ov;         // overlap length\n    vector<int> startCost;          // approximate cost from initial finger to type whole word\n    vector<vector<int>> edgeCost;   // approximate incremental cost i -> j\n\n    chrono::steady_clock::time_point t0;\n    XorShift64 rng;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n        words.resize(M);\n        for (int i = 0; i < M; i++) cin >> words[i];\n\n        V = N * N;\n        startId = si * N + sj;\n    }\n\n    // Minimal typing cost to type w[begin..] when current finger is any cell in \"starts\".\n    int costFromStarts(const vector<int>& starts, const string& w, int begin) const {\n        const int INF = 1e9;\n        int L = (int)w.size();\n        if (begin >= L) return 0;\n\n        vector<int> prevCells = occ[w[begin] - 'A'];\n        vector<int> prevCost(prevCells.size(), INF);\n\n        for (int qi = 0; qi < (int)prevCells.size(); qi++) {\n            int q = prevCells[qi];\n            int best = INF;\n            for (int s : starts) {\n                int v = distMat[s][q] + 1;\n                if (v < best) best = v;\n            }\n            prevCost[qi] = best;\n        }\n\n        for (int pos = begin + 1; pos < L; pos++) {\n            const vector<int>& nextCells = occ[w[pos] - 'A'];\n            vector<int> nextCost(nextCells.size(), INF);\n\n            for (int ni = 0; ni < (int)nextCells.size(); ni++) {\n                int q = nextCells[ni];\n                int best = INF;\n                for (int pi = 0; pi < (int)prevCells.size(); pi++) {\n                    int p = prevCells[pi];\n                    int cand = prevCost[pi] + distMat[p][q] + 1;\n                    if (cand < best) best = cand;\n                }\n                nextCost[ni] = best;\n            }\n\n            prevCells = nextCells;\n            prevCost.swap(nextCost);\n        }\n\n        return *min_element(prevCost.begin(), prevCost.end());\n    }\n\n    void preprocess() {\n        for (auto& v : occ) v.clear();\n\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\n        for (int a = 0; a < V; a++) {\n            int ra = a / N, ca = a % N;\n            for (int b = 0; b < V; b++) {\n                int rb = b / N, cb = b % N;\n                distMat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int best = 0;\n                for (int k = 4; k >= 0; k--) {\n                    bool ok = true;\n                    for (int x = 0; x < k; x++) {\n                        if (words[i][5 - k + x] != words[j][x]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (ok) {\n                        best = k;\n                        break;\n                    }\n                }\n                ov[i][j] = best;\n            }\n        }\n\n        // memo[letter][word][begin]\n        vector<vector<array<int, 6>>> memo(26, vector<array<int, 6>>(M));\n        for (int c = 0; c < 26; c++) {\n            for (int j = 0; j < M; j++) {\n                for (int b = 0; b <= 5; b++) {\n                    memo[c][j][b] = (b == 5 ? 0 : costFromStarts(occ[c], words[j], b));\n                }\n            }\n        }\n\n        startCost.assign(M, 0);\n        vector<int> startVec = {startId};\n        for (int i = 0; i < M; i++) {\n            startCost[i] = costFromStarts(startVec, words[i], 0);\n        }\n\n        edgeCost.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; i++) {\n            int c = words[i][4] - 'A';\n            for (int j = 0; j < M; j++) {\n                int k = ov[i][j];\n                edgeCost[i][j] = memo[c][j][k];\n            }\n        }\n    }\n\n    long long approxCost(const vector<int>& perm) const {\n        long long c = startCost[perm[0]];\n        for (int i = 1; i < M; i++) c += edgeCost[perm[i - 1]][perm[i]];\n        return c;\n    }\n\n    static void relocateMove(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) p[k] = p[k + 1];\n            p[j] = v;\n        } else {\n            for (int k = i; k > j; k--) p[k] = p[k - 1];\n            p[j] = v;\n        }\n    }\n\n    vector<int> initialPermutation() const {\n        vector<int> bestPerm;\n        long long best = (1LL << 60);\n\n        vector<char> used(M);\n        vector<int> perm(M);\n\n        for (int s = 0; s < M; s++) {\n            fill(used.begin(), used.end(), 0);\n            perm[0] = s;\n            used[s] = 1;\n\n            for (int pos = 1; pos < M; pos++) {\n                int cur = perm[pos - 1];\n                int bj = -1;\n                int bv = 1e9;\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeCost[cur][j];\n                    if (v < bv) {\n                        bv = v;\n                        bj = j;\n                    }\n                }\n                perm[pos] = bj;\n                used[bj] = 1;\n            }\n\n            long long c = approxCost(perm);\n            if (c < best) {\n                best = c;\n                bestPerm = perm;\n            }\n        }\n        return bestPerm;\n    }\n\n    void SAApprox(vector<int>& perm, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm;\n        vector<int> bestPerm = perm;\n        long long curCost = approxCost(cur);\n        long long bestCost = curCost;\n\n        double temp = 1.0;\n        const double T0 = 30.0, T1 = 0.05;\n        double span = max(1e-9, endTime - begin);\n\n        for (int iter = 0;; iter++) {\n            if ((iter & 63) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            int i = rng.nextInt(M);\n            int j = rng.nextInt(M);\n            if (i == j) continue;\n\n            bool doSwap = (rng.nextInt(100) < 70);\n\n            if (doSwap) {\n                swap(cur[i], cur[j]);\n                long long nc = approxCost(cur);\n                long long diff = nc - curCost;\n                bool ok = (diff <= 0) || (rng.nextDouble() < exp(-double(diff) / temp));\n                if (ok) {\n                    curCost = nc;\n                    if (nc < bestCost) {\n                        bestCost = nc;\n                        bestPerm = cur;\n                    }\n                } else {\n                    swap(cur[i], cur[j]);\n                }\n            } else {\n                relocateMove(cur, i, j);\n                long long nc = approxCost(cur);\n                long long diff = nc - curCost;\n                bool ok = (diff <= 0) || (rng.nextDouble() < exp(-double(diff) / temp));\n                if (ok) {\n                    curCost = nc;\n                    if (nc < bestCost) {\n                        bestCost = nc;\n                        bestPerm = cur;\n                    }\n                } else {\n                    relocateMove(cur, j, i); // revert\n                }\n            }\n        }\n\n        perm = bestPerm;\n    }\n\n    void buildString(const vector<int>& perm, string& out) const {\n        out.clear();\n        out.reserve(5 * M);\n\n        out += words[perm[0]];\n        for (int i = 1; i < M; i++) {\n            int a = perm[i - 1];\n            int b = perm[i];\n            int k = ov[a][b];\n            for (int p = k; p < 5; p++) out.push_back(words[b][p]);\n        }\n    }\n\n    int typingCost(const string& s) const {\n        const int INF = 1e9;\n        int prev[225], cur[225];\n        for (int i = 0; i < V; i++) prev[i] = INF;\n\n        vector<int> prevCells = occ[s[0] - 'A'];\n        for (int q : prevCells) prev[q] = distMat[startId][q] + 1;\n\n        for (int idx = 1; idx < (int)s.size(); idx++) {\n            const vector<int>& nextCells = occ[s[idx] - 'A'];\n\n            for (int q : nextCells) {\n                int best = INF;\n                for (int p : prevCells) {\n                    int cand = prev[p] + distMat[p][q] + 1;\n                    if (cand < best) best = cand;\n                }\n                cur[q] = best;\n            }\n\n            for (int p : prevCells) prev[p] = INF;\n            prevCells = nextCells;\n            for (int q : prevCells) prev[q] = cur[q];\n        }\n\n        int ans = INF;\n        for (int p : prevCells) ans = min(ans, prev[p]);\n        return ans;\n    }\n\n    void SAExact(vector<int>& perm, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        string work;\n        work.reserve(5 * M);\n\n        auto eval = [&](const vector<int>& p) -> int {\n            buildString(p, work);\n            return typingCost(work);\n        };\n\n        vector<int> cur = perm;\n        vector<int> bestPerm = perm;\n        int curCost = eval(cur);\n        int bestCost = curCost;\n\n        double temp = 1.0;\n        const double T0 = 12.0, T1 = 0.02;\n        double span = max(1e-9, endTime - begin);\n\n        for (int iter = 0;; iter++) {\n            if ((iter & 31) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            int i = rng.nextInt(M);\n            int j = rng.nextInt(M);\n            if (i == j) continue;\n\n            bool doSwap = (rng.nextInt(100) < 80);\n\n            if (doSwap) {\n                swap(cur[i], cur[j]);\n                int nc = eval(cur);\n                int diff = nc - curCost;\n                bool ok = (diff <= 0) || (rng.nextDouble() < exp(-double(diff) / temp));\n                if (ok) {\n                    curCost = nc;\n                    if (nc < bestCost) {\n                        bestCost = nc;\n                        bestPerm = cur;\n                    }\n                } else {\n                    swap(cur[i], cur[j]);\n                }\n            } else {\n                relocateMove(cur, i, j);\n                int nc = eval(cur);\n                int diff = nc - curCost;\n                bool ok = (diff <= 0) || (rng.nextDouble() < exp(-double(diff) / temp));\n                if (ok) {\n                    curCost = nc;\n                    if (nc < bestCost) {\n                        bestCost = nc;\n                        bestPerm = cur;\n                    }\n                } else {\n                    relocateMove(cur, j, i); // revert\n                }\n            }\n        }\n\n        perm = bestPerm;\n    }\n\n    vector<int> bestPathForString(const string& s) const {\n        const int INF = 1e9;\n        int L = (int)s.size();\n\n        vector<vector<short>> parent(L, vector<short>(V, -1));\n        vector<int> prev(V, INF), cur(V, INF);\n\n        vector<int> prevCells = occ[s[0] - 'A'];\n        for (int q : prevCells) prev[q] = distMat[startId][q] + 1;\n\n        for (int i = 1; i < L; i++) {\n            const vector<int>& nextCells = occ[s[i] - 'A'];\n\n            for (int q : nextCells) {\n                int best = INF;\n                short bp = -1;\n                for (int p : prevCells) {\n                    int cand = prev[p] + distMat[p][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bp = (short)p;\n                    }\n                }\n                cur[q] = best;\n                parent[i][q] = bp;\n            }\n\n            for (int p : prevCells) prev[p] = INF;\n            prevCells = nextCells;\n            for (int q : prevCells) {\n                prev[q] = cur[q];\n                cur[q] = INF;\n            }\n        }\n\n        int endCell = -1;\n        int best = INF;\n        for (int p : prevCells) {\n            if (prev[p] < best) {\n                best = prev[p];\n                endCell = p;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = endCell;\n        for (int i = L - 1; i >= 1; i--) {\n            path[i - 1] = parent[i][path[i]];\n        }\n        return path;\n    }\n\n    void solve() {\n        readInput();\n        rng = XorShift64(\n            chrono::high_resolution_clock::now().time_since_epoch().count() ^\n            (uint64_t)startId * 1000003ULL\n        );\n\n        t0 = chrono::steady_clock::now();\n\n        preprocess();\n\n        vector<int> perm = initialPermutation();\n\n        SAApprox(perm, 1.00); // seconds from t0\n        SAExact(perm, 1.65);  // seconds from t0\n\n        string finalS;\n        buildString(perm, finalS);\n\n        vector<int> path = bestPathForString(finalS);\n\n        for (int id : path) {\n            cout << (id / N) << ' ' << (id % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Mask {\n    static constexpr int W = 7; // 7 * 64 = 448 >= 400\n    array<uint64_t, W> w;\n    Mask() { w.fill(0ULL); }\n    inline void set(int idx) { w[idx >> 6] |= (1ULL << (idx & 63)); }\n    inline bool test(int idx) const { return (w[idx >> 6] >> (idx & 63)) & 1ULL; }\n    inline void or_with(const Mask& other) {\n        for (int i = 0; i < W; i++) w[i] |= other.w[i];\n    }\n};\n\nstruct Placement {\n    vector<int> cells;        // covered global cell indices\n    Mask mask;                // bit representation\n    vector<uint8_t> qcov;     // coverage bits for drilled-query list\n};\n\nclass OilSolver {\npublic:\n    int N = 0, M = 0, n2 = 0;\n    double eps = 0.0;\n\n    vector<vector<pair<int,int>>> shapes;\n    vector<vector<Placement>> fieldPls; // [field][placement]\n\n    vector<int> drilledVal;   // -1 unknown, else exact v(i,j)\n    vector<int> qidOfCell;    // cell -> drilled-query index\n    vector<int> queryVals;    // observed exact values\n    vector<int> queryCells;   // queried cell index list\n\n    vector<int> priorOrder;\n    int priorPtr = 0;\n\n    mt19937 rng;\n    int ops = 0;\n    int wrongGuesses = 0;\n    int guessCooldown = 0;\n    vector<int> lastWrongGuess;\n    bool hasLastWrongGuess = false;\n\n    chrono::steady_clock::time_point globalStart;\n\n    static constexpr int MAX_WRONG_GUESSES = 8;\n\n    OilSolver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        n2 = N * N;\n        shapes.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            shapes[k].resize(d);\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                shapes[k][t] = {i, j};\n            }\n        }\n        drilledVal.assign(n2, -1);\n        qidOfCell.assign(n2, -1);\n    }\n\n    void build_placements() {\n        fieldPls.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int maxr = 0, maxc = 0;\n            for (auto [r, c] : shapes[k]) {\n                maxr = max(maxr, r);\n                maxc = max(maxc, c);\n            }\n            for (int di = 0; di + maxr < N; di++) {\n                for (int dj = 0; dj + maxc < N; dj++) {\n                    Placement pl;\n                    pl.cells.reserve(shapes[k].size());\n                    pl.qcov.reserve(n2);\n                    for (auto [r, c] : shapes[k]) {\n                        int ni = di + r;\n                        int nj = dj + c;\n                        int idx = ni * N + nj;\n                        pl.cells.push_back(idx);\n                        pl.mask.set(idx);\n                    }\n                    fieldPls[k].push_back(move(pl));\n                }\n            }\n        }\n    }\n\n    void build_prior_order() {\n        vector<vector<int>> coverCnt(M, vector<int>(n2, 0));\n        for (int k = 0; k < M; k++) {\n            for (const auto& pl : fieldPls[k]) {\n                for (int idx : pl.cells) coverCnt[k][idx]++;\n            }\n        }\n\n        vector<double> score(n2, 0.0);\n        for (int idx = 0; idx < n2; idx++) {\n            double p0 = 1.0;\n            for (int k = 0; k < M; k++) {\n                double pk = (double)coverCnt[k][idx] / (double)fieldPls[k].size();\n                p0 *= (1.0 - pk);\n            }\n            double p = 1.0 - p0;\n            score[idx] = p * (1.0 - p); // entropy proxy\n        }\n\n        priorOrder.resize(n2);\n        iota(priorOrder.begin(), priorOrder.end(), 0);\n        sort(priorOrder.begin(), priorOrder.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return a < b;\n        });\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << \" \" << (idx % N) << endl;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    int ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int idx : cells) {\n            cout << \" \" << (idx / N) << \" \" << (idx % N);\n        }\n        cout << endl;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    void add_drill(int idx, int val) {\n        if (drilledVal[idx] != -1) return;\n        drilledVal[idx] = val;\n        int qid = (int)queryVals.size();\n        qidOfCell[idx] = qid;\n        queryVals.push_back(val);\n        queryCells.push_back(idx);\n\n        for (int k = 0; k < M; k++) {\n            for (auto& pl : fieldPls[k]) {\n                pl.qcov.push_back(pl.mask.test(idx) ? 1 : 0);\n            }\n        }\n    }\n\n    int pick_prior_cell() {\n        while (priorPtr < (int)priorOrder.size() && drilledVal[priorOrder[priorPtr]] != -1) priorPtr++;\n        if (priorPtr < (int)priorOrder.size()) return priorOrder[priorPtr++];\n        return -1;\n    }\n\n    int first_unknown_cell() const {\n        for (int idx = 0; idx < n2; idx++) if (drilledVal[idx] == -1) return idx;\n        return -1;\n    }\n\n    bool propagate_domains(vector<vector<int>>& domains) {\n        int q = (int)queryVals.size();\n        domains.assign(M, {});\n\n        vector<vector<char>> active(M);\n        for (int k = 0; k < M; k++) active[k].assign(fieldPls[k].size(), 1);\n\n        int iter = 0;\n        while (true) {\n            iter++;\n\n            vector<int> domSize(M, 0);\n            vector<vector<int>> cnt1(M, vector<int>(q, 0));\n\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    domSize[k]++;\n                    const auto& qc = pls[p].qcov;\n                    for (int r = 0; r < q; r++) cnt1[k][r] += qc[r];\n                }\n            }\n            for (int k = 0; k < M; k++) if (domSize[k] == 0) return false;\n\n            vector<vector<int8_t>> minv(M, vector<int8_t>(q, 0));\n            vector<vector<int8_t>> maxv(M, vector<int8_t>(q, 0));\n            vector<int> totalMin(q, 0), totalMax(q, 0);\n\n            for (int r = 0; r < q; r++) {\n                int tmin = 0, tmax = 0;\n                for (int k = 0; k < M; k++) {\n                    bool has1 = cnt1[k][r] > 0;\n                    bool has0 = (domSize[k] - cnt1[k][r]) > 0;\n                    int mn = has0 ? 0 : 1;\n                    int mx = has1 ? 1 : 0;\n                    minv[k][r] = (int8_t)mn;\n                    maxv[k][r] = (int8_t)mx;\n                    tmin += mn;\n                    tmax += mx;\n                }\n                totalMin[r] = tmin;\n                totalMax[r] = tmax;\n                int y = queryVals[r];\n                if (y < tmin || y > tmax) return false;\n            }\n\n            bool changed = false;\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    const auto& qc = pls[p].qcov;\n                    bool ok = true;\n                    for (int r = 0; r < q; r++) {\n                        int x = qc[r];\n                        int need = queryVals[r] - x;\n                        int lo = totalMin[r] - minv[k][r];\n                        int hi = totalMax[r] - maxv[k][r];\n                        if (need < lo || need > hi) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) {\n                        active[k][p] = 0;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed || iter >= 40) {\n                for (int k = 0; k < M; k++) {\n                    for (int p = 0; p < (int)fieldPls[k].size(); p++) {\n                        if (active[k][p]) domains[k].push_back(p);\n                    }\n                    if (domains[k].empty()) return false;\n                }\n                return true;\n            }\n        }\n    }\n\n    vector<vector<int>> sample_solutions(int maxSol, long long nodeLimit, int timeMs) {\n        vector<vector<int>> domains;\n        if (!propagate_domains(domains)) return {};\n\n        int q = (int)queryVals.size();\n        vector<vector<int>> sols;\n        if (maxSol <= 0) return sols;\n\n        if (q == 0) {\n            for (int s = 0; s < maxSol; s++) {\n                vector<int> asg(M, -1);\n                for (int k = 0; k < M; k++) {\n                    auto& d = domains[k];\n                    uniform_int_distribution<int> dist(0, (int)d.size() - 1);\n                    asg[k] = d[dist(rng)];\n                }\n                sols.push_back(move(asg));\n            }\n            return sols;\n        }\n\n        vector<vector<int8_t>> varMin(M, vector<int8_t>(q, 0));\n        vector<vector<int8_t>> varMax(M, vector<int8_t>(q, 0));\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            vector<int> c1(q, 0);\n            for (int p : domains[k]) {\n                const auto& qc = fieldPls[k][p].qcov;\n                for (int r = 0; r < q; r++) c1[r] += qc[r];\n            }\n            for (int r = 0; r < q; r++) {\n                bool has1 = c1[r] > 0;\n                bool has0 = (ds - c1[r]) > 0;\n                varMin[k][r] = has0 ? 0 : 1;\n                varMax[k][r] = has1 ? 1 : 0;\n            }\n        }\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (domains[a].size() != domains[b].size()) return domains[a].size() < domains[b].size();\n            return a < b;\n        });\n\n        vector<vector<int>> sufMin(M + 1, vector<int>(q, 0));\n        vector<vector<int>> sufMax(M + 1, vector<int>(q, 0));\n        for (int d = M - 1; d >= 0; d--) {\n            int k = order[d];\n            for (int r = 0; r < q; r++) {\n                sufMin[d][r] = sufMin[d + 1][r] + varMin[k][r];\n                sufMax[d][r] = sufMax[d + 1][r] + varMax[k][r];\n            }\n        }\n        for (int r = 0; r < q; r++) {\n            if (queryVals[r] < sufMin[0][r] || queryVals[r] > sufMax[0][r]) return {};\n        }\n\n        vector<vector<int>> domOrd(M);\n        for (int k = 0; k < M; k++) {\n            domOrd[k] = domains[k];\n            shuffle(domOrd[k].begin(), domOrd[k].end(), rng);\n        }\n\n        vector<int> target = queryVals;\n        vector<int> assign(M, -1);\n\n        auto deadline = chrono::steady_clock::now() + chrono::milliseconds(timeMs);\n        bool timeout = false;\n        long long nodes = 0;\n\n        auto dfs = [&](auto&& self, int depth) -> void {\n            if (timeout || (int)sols.size() >= maxSol) return;\n            if (depth == M) {\n                for (int r = 0; r < q; r++) if (target[r] != 0) return;\n                sols.push_back(assign);\n                return;\n            }\n            int k = order[depth];\n            for (int p : domOrd[k]) {\n                nodes++;\n                if ((nodes & 2047LL) == 0) {\n                    if (nodes > nodeLimit || chrono::steady_clock::now() >= deadline) {\n                        timeout = true;\n                        return;\n                    }\n                }\n\n                const auto& qc = fieldPls[k][p].qcov;\n                bool ok = true;\n                for (int r = 0; r < q; r++) {\n                    int t = target[r] - qc[r];\n                    if (t < sufMin[depth + 1][r] || t > sufMax[depth + 1][r]) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (!ok) continue;\n\n                assign[k] = p;\n                for (int cell : fieldPls[k][p].cells) {\n                    int id = qidOfCell[cell];\n                    if (id != -1) target[id]--;\n                }\n\n                self(self, depth + 1);\n\n                for (int cell : fieldPls[k][p].cells) {\n                    int id = qidOfCell[cell];\n                    if (id != -1) target[id]++;\n                }\n\n                if (timeout || (int)sols.size() >= maxSol) return;\n            }\n            assign[k] = -1;\n        };\n\n        dfs(dfs, 0);\n\n        // fallback: randomized constructive attempts\n        if (sols.empty()) {\n            for (int attempt = 0; attempt < 120 && sols.empty(); attempt++) {\n                vector<int> t = queryVals;\n                vector<int> asg(M, -1);\n                bool okAll = true;\n\n                for (int depth = 0; depth < M; depth++) {\n                    int k = order[depth];\n                    vector<int> cand = domains[k];\n                    shuffle(cand.begin(), cand.end(), rng);\n\n                    int chosen = -1;\n                    for (int p : cand) {\n                        const auto& qc = fieldPls[k][p].qcov;\n                        bool feasible = true;\n                        for (int r = 0; r < q; r++) {\n                            int nt = t[r] - qc[r];\n                            if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                                feasible = false;\n                                break;\n                            }\n                        }\n                        if (feasible) {\n                            chosen = p;\n                            break;\n                        }\n                    }\n\n                    if (chosen == -1) {\n                        okAll = false;\n                        break;\n                    }\n\n                    asg[k] = chosen;\n                    for (int cell : fieldPls[k][chosen].cells) {\n                        int id = qidOfCell[cell];\n                        if (id != -1) t[id]--;\n                    }\n                }\n\n                if (okAll) {\n                    bool exact = true;\n                    for (int v : t) if (v != 0) { exact = false; break; }\n                    if (exact) sols.push_back(move(asg));\n                }\n            }\n        }\n\n        return sols;\n    }\n\n    vector<int> calc_freq(const vector<vector<int>>& sols) {\n        vector<int> freq(n2, 0);\n        for (const auto& asg : sols) {\n            Mask uni;\n            for (int k = 0; k < M; k++) {\n                uni.or_with(fieldPls[k][asg[k]].mask);\n            }\n            for (int wi = 0; wi < Mask::W; wi++) {\n                uint64_t bits = uni.w[wi];\n                while (bits) {\n                    int b = __builtin_ctzll(bits);\n                    int idx = wi * 64 + b;\n                    if (idx < n2) freq[idx]++;\n                    bits &= bits - 1;\n                }\n            }\n        }\n        return freq;\n    }\n\n    int choose_uncertain_cell(const vector<int>& freq, int S) {\n        if (S <= 0) return -1;\n        int best = -1;\n        double bestScore = -1.0;\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            int f = freq[idx];\n            if (f == 0 || f == S) continue;\n            double p = (double)f / (double)S;\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    vector<int> build_consensus_guess(const vector<int>& freq, int S) {\n        vector<char> used(n2, 0);\n        if (S > 0) {\n            for (int idx = 0; idx < n2; idx++) {\n                if (freq[idx] == S) used[idx] = 1;\n            }\n        }\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] > 0) used[idx] = 1;\n        }\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int idx = 0; idx < n2; idx++) if (used[idx]) ans.push_back(idx);\n        return ans;\n    }\n\n    vector<int> exact_from_drilled() const {\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] > 0) ans.push_back(idx);\n        }\n        return ans;\n    }\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - globalStart).count();\n    }\n\n    void solve() {\n        globalStart = chrono::steady_clock::now();\n        int initQueries = min(8, N);\n        int maxOps = 2 * n2;\n        int solveLimit = min(n2, 140);\n\n        while (true) {\n            int drilledCnt = (int)queryVals.size();\n\n            if (drilledCnt == n2) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    (void)res;\n                }\n                return;\n            }\n\n            bool simpleMode = (elapsed_ms() > 2500.0);\n\n            int next = -1;\n            vector<vector<int>> sols;\n            vector<int> freq;\n            bool consensus = false;\n            int S = 0;\n\n            if (!simpleMode && drilledCnt >= 3 && drilledCnt <= solveLimit) {\n                int maxSol = (drilledCnt < 12 ? 16 : 24);\n                long long nodeLim = (drilledCnt < 12 ? 40000 : 120000);\n                int timeMs = (drilledCnt < 12 ? 15 : 30);\n                sols = sample_solutions(maxSol, nodeLim, timeMs);\n                S = (int)sols.size();\n                if (S > 0) {\n                    freq = calc_freq(sols);\n                    next = choose_uncertain_cell(freq, S);\n                    consensus = (next == -1);\n                }\n            }\n\n            if (drilledCnt < initQueries && next == -1) {\n                next = pick_prior_cell();\n            }\n\n            if (next == -1) {\n                if (!simpleMode && consensus && S > 0 && guessCooldown == 0 &&\n                    wrongGuesses < MAX_WRONG_GUESSES && drilledCnt >= max(6, M / 2)) {\n                    if (S >= 4 || drilledCnt >= 20) {\n                        vector<int> guess = build_consensus_guess(freq, S);\n                        bool sameAsLastWrong = (hasLastWrongGuess && guess == lastWrongGuess);\n                        if (!sameAsLastWrong && ops < maxOps) {\n                            int res = ask_answer(guess);\n                            ops++;\n                            if (res == 1) return;\n                            wrongGuesses++;\n                            guessCooldown = 3;\n                            lastWrongGuess = move(guess);\n                            hasLastWrongGuess = true;\n                            continue;\n                        }\n                    }\n                }\n                next = pick_prior_cell();\n            }\n\n            if (next == -1) next = first_unknown_cell();\n            if (next == -1) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    if (res == 1) return;\n                }\n                return;\n            }\n\n            if (ops >= maxOps) return;\n\n            int v = ask_drill(next);\n            ops++;\n            add_drill(next, v);\n            if (guessCooldown > 0) guessCooldown--;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    OilSolver solver;\n    solver.read_input();\n    solver.build_placements();\n    solver.build_prior_order();\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seg {\n    int x, y0, y1;\n};\n\nstruct Candidate {\n    vector<array<int, 4>> rects; // [i0, j0, i1, j1] for each reservation k\n    vector<int> hlines;          // internal horizontal boundaries (y)\n    vector<Seg> vsegs;           // internal vertical boundary segments\n    long long shortage = 0;\n};\n\nstatic int min_height_segment(const vector<int>& arr, int l, int r, int W) {\n    auto ok = [&](int h) -> bool {\n        long long s = 0;\n        for (int i = l; i < r; i++) {\n            s += (arr[i] + h - 1) / h;\n            if (s > W) return false;\n        }\n        return true;\n    };\n    if (!ok(W)) return W + 1; // impossible within hall height\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (ok(mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nstatic Candidate build_candidate(\n    int W,\n    const vector<int>& dayA,                 // a[d][k], k-order\n    const vector<int>& ord,                  // position -> reservation index\n    const vector<int>& split,                // split indices in ord positions\n    const vector<vector<int>>& htab          // minimal heights for [l][r)\n) {\n    int N = (int)dayA.size();\n    Candidate cand;\n    cand.rects.assign(N, array<int, 4>{0, 0, 1, 1});\n\n    int rows = (int)split.size() - 1;\n    vector<int> heights(rows);\n    long long total_h = 0;\n    for (int g = 0; g < rows; g++) {\n        int l = split[g], r = split[g + 1];\n        heights[g] = htab[l][r];\n        total_h += heights[g];\n    }\n\n    if (total_h > W) {\n        // Safety fallback (shouldn't happen for feasible split):\n        cand.rects.assign(N, array<int, 4>{0, 0, 1, 1});\n        cand.hlines.clear();\n        cand.vsegs.clear();\n        for (int k = 0; k < N; k++) {\n            int y0 = (long long)W * k / N;\n            int y1 = (long long)W * (k + 1) / N;\n            cand.rects[k] = {y0, 0, y1, W};\n            if (k > 0) cand.hlines.push_back(y0);\n        }\n    } else {\n        // Put all extra height to the last row (keeps upper row boundaries stable).\n        heights.back() += (int)(W - total_h);\n\n        int y = 0;\n        for (int g = 0; g < rows; g++) {\n            int l = split[g], r = split[g + 1];\n            int h = heights[g];\n            int x = 0;\n\n            for (int t = l; t < r; t++) {\n                int idx = ord[t];\n                int w;\n                if (t < r - 1) {\n                    w = (dayA[idx] + h - 1) / h; // minimal width\n                } else {\n                    w = W - x; // last gets the remainder\n                }\n                cand.rects[idx] = {y, x, y + h, x + w};\n                x += w;\n\n                if (t < r - 1) {\n                    cand.vsegs.push_back({x, y, y + h});\n                }\n            }\n            y += h;\n            if (g < rows - 1) cand.hlines.push_back(y);\n        }\n    }\n\n    sort(cand.vsegs.begin(), cand.vsegs.end(), [](const Seg& a, const Seg& b) {\n        if (a.x != b.x) return a.x < b.x;\n        return a.y0 < b.y0;\n    });\n\n    long long sh = 0;\n    for (int k = 0; k < N; k++) {\n        const auto& rc = cand.rects[k];\n        long long area = 1LL * (rc[2] - rc[0]) * (rc[3] - rc[1]);\n        if (area < dayA[k]) sh += 100LL * (dayA[k] - area);\n    }\n    cand.shortage = sh;\n\n    return cand;\n}\n\nstatic vector<int> sample_rows(const vector<int>& feasible, int cap) {\n    if (feasible.empty()) return {};\n    if (cap <= 1) return {feasible.front()};\n    if ((int)feasible.size() <= cap) return feasible;\n\n    vector<int> ret;\n    ret.reserve(cap);\n    int m = (int)feasible.size();\n    int last = -1;\n\n    for (int t = 0; t < cap; t++) {\n        int idx = (long long)t * (m - 1) / (cap - 1);\n        int r = feasible[idx];\n        if (r != last) {\n            ret.push_back(r);\n            last = r;\n        }\n    }\n\n    for (int r : feasible) {\n        if ((int)ret.size() >= cap) break;\n        if (find(ret.begin(), ret.end(), r) == ret.end()) ret.push_back(r);\n    }\n    sort(ret.begin(), ret.end());\n    return ret;\n}\n\nstatic vector<Candidate> generate_candidates_one_order(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    int capRows\n) {\n    int N = (int)dayA.size();\n\n    // Reordered areas by ord-position\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    // htab[l][r] = minimal row height for segment [l, r)\n    vector<vector<int>> htab(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            htab[l][r] = min_height_segment(arr, l, r, W);\n        }\n    }\n\n    // DP by exact row count\n    const int INF = 1e9;\n    vector<vector<int>> dp(N + 1, vector<int>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int rr = 1; rr <= N; rr++) {\n        for (int i = 1; i <= N; i++) {\n            int best = INF, bestj = -1;\n            for (int j = 0; j < i; j++) {\n                if (dp[rr - 1][j] == INF) continue;\n                int h = htab[j][i];\n                if (h > W) continue;\n                int v = dp[rr - 1][j] + h;\n                // tie-break: larger j => smaller last group\n                if (v < best || (v == best && j > bestj)) {\n                    best = v;\n                    bestj = j;\n                }\n            }\n            dp[rr][i] = best;\n            par[rr][i] = bestj;\n        }\n    }\n\n    vector<int> feasible_rows;\n    for (int rr = 1; rr <= N; rr++) {\n        if (dp[rr][N] <= W) feasible_rows.push_back(rr);\n    }\n\n    vector<int> selected_rows = sample_rows(feasible_rows, capRows);\n\n    vector<Candidate> res;\n    for (int rr : selected_rows) {\n        vector<int> split(rr + 1);\n        split[rr] = N;\n\n        int i = N;\n        bool ok = true;\n        for (int r = rr; r >= 1; r--) {\n            int j = par[r][i];\n            if (j < 0) {\n                ok = false;\n                break;\n            }\n            split[r - 1] = j;\n            i = j;\n        }\n        if (!ok || split[0] != 0) continue;\n\n        Candidate cand = build_candidate(W, dayA, ord, split, htab);\n        res.push_back(move(cand));\n    }\n\n    return res;\n}\n\nstatic Candidate fallback_candidate(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    Candidate cand;\n    cand.rects.assign(N, array<int, 4>{0, 0, 1, 1});\n    cand.hlines.clear();\n    cand.vsegs.clear();\n\n    for (int k = 0; k < N; k++) {\n        int y0 = (long long)W * k / N;\n        int y1 = (long long)W * (k + 1) / N;\n        cand.rects[k] = {y0, 0, y1, W};\n        if (k > 0) cand.hlines.push_back(y0);\n    }\n\n    long long sh = 0;\n    for (int k = 0; k < N; k++) {\n        const auto& rc = cand.rects[k];\n        long long area = 1LL * (rc[2] - rc[0]) * (rc[3] - rc[1]);\n        if (area < dayA[k]) sh += 100LL * (dayA[k] - area);\n    }\n    cand.shortage = sh;\n\n    return cand;\n}\n\nstatic long long transition_cost(const Candidate& A, const Candidate& B, int W) {\n    long long cost = 0;\n\n    // Horizontal boundaries: full width lines\n    int i = 0, j = 0;\n    const auto& H1 = A.hlines;\n    const auto& H2 = B.hlines;\n    while (i < (int)H1.size() || j < (int)H2.size()) {\n        if (i == (int)H1.size()) {\n            cost += 1LL * ((int)H2.size() - j) * W;\n            break;\n        }\n        if (j == (int)H2.size()) {\n            cost += 1LL * ((int)H1.size() - i) * W;\n            break;\n        }\n        if (H1[i] == H2[j]) {\n            i++; j++;\n        } else if (H1[i] < H2[j]) {\n            cost += W;\n            i++;\n        } else {\n            cost += W;\n            j++;\n        }\n    }\n\n    // Vertical segments: symmetric difference length by x-line\n    const auto& S1 = A.vsegs;\n    const auto& S2 = B.vsegs;\n    int p = 0, q = 0;\n\n    while (p < (int)S1.size() || q < (int)S2.size()) {\n        int x;\n        if (q == (int)S2.size() || (p < (int)S1.size() && S1[p].x < S2[q].x)) {\n            x = S1[p].x;\n        } else if (p == (int)S1.size() || S2[q].x < S1[p].x) {\n            x = S2[q].x;\n        } else {\n            x = S1[p].x;\n        }\n\n        int p0 = p;\n        while (p < (int)S1.size() && S1[p].x == x) p++;\n        int q0 = q;\n        while (q < (int)S2.size() && S2[q].x == x) q++;\n\n        long long len1 = 0, len2 = 0;\n        for (int t = p0; t < p; t++) len1 += S1[t].y1 - S1[t].y0;\n        for (int t = q0; t < q; t++) len2 += S2[t].y1 - S2[t].y0;\n\n        long long inter = 0;\n        int a = p0, b = q0;\n        while (a < p && b < q) {\n            int l = max(S1[a].y0, S2[b].y0);\n            int r = min(S1[a].y1, S2[b].y1);\n            if (r > l) inter += (r - l);\n            if (S1[a].y1 < S2[b].y1) a++;\n            else b++;\n        }\n\n        cost += len1 + len2 - 2LL * inter;\n    }\n\n    return cost;\n}\n\nstatic bool same_shape(const Candidate& A, const Candidate& B) {\n    if (A.hlines != B.hlines) return false;\n    if (A.vsegs.size() != B.vsegs.size()) return false;\n    for (size_t i = 0; i < A.vsegs.size(); i++) {\n        if (A.vsegs[i].x != B.vsegs[i].x) return false;\n        if (A.vsegs[i].y0 != B.vsegs[i].y0) return false;\n        if (A.vsegs[i].y1 != B.vsegs[i].y1) return false;\n    }\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) cin >> a[d][k];\n    }\n\n    const int capRows = min(24, N);\n\n    vector<int> ordAsc(N), ordDesc(N);\n    iota(ordAsc.begin(), ordAsc.end(), 0);\n    for (int i = 0; i < N; i++) ordDesc[i] = N - 1 - i;\n\n    vector<vector<Candidate>> cands(D);\n\n    for (int d = 0; d < D; d++) {\n        vector<Candidate> day;\n\n        {\n            auto v = generate_candidates_one_order(W, a[d], ordAsc, capRows);\n            for (auto& c : v) day.push_back(move(c));\n        }\n        {\n            auto v = generate_candidates_one_order(W, a[d], ordDesc, capRows);\n            for (auto& c : v) day.push_back(move(c));\n        }\n\n        day.push_back(fallback_candidate(W, a[d]));\n\n        // Deduplicate by shape (keep smaller shortage)\n        vector<Candidate> uniq;\n        for (auto& c : day) {\n            bool merged = false;\n            for (auto& u : uniq) {\n                if (same_shape(c, u)) {\n                    if (c.shortage < u.shortage) u = c;\n                    merged = true;\n                    break;\n                }\n            }\n            if (!merged) uniq.push_back(move(c));\n        }\n\n        if (uniq.empty()) {\n            uniq.push_back(fallback_candidate(W, a[d]));\n        }\n        cands[d] = move(uniq);\n    }\n\n    const long long INF64 = (1LL << 62);\n\n    vector<vector<int>> parent(D);\n    vector<long long> dpPrev(cands[0].size(), INF64), dpCur;\n\n    for (int i = 0; i < (int)cands[0].size(); i++) {\n        dpPrev[i] = cands[0][i].shortage; // L0 = 0\n    }\n\n    for (int d = 1; d < D; d++) {\n        int P = (int)cands[d - 1].size();\n        int C = (int)cands[d].size();\n\n        dpCur.assign(C, INF64);\n        parent[d].assign(C, -1);\n\n        for (int i = 0; i < C; i++) {\n            long long add = cands[d][i].shortage;\n            long long best = INF64;\n            int bestj = -1;\n\n            for (int j = 0; j < P; j++) {\n                long long tr = transition_cost(cands[d - 1][j], cands[d][i], W);\n                long long val = dpPrev[j] + tr + add;\n                if (val < best) {\n                    best = val;\n                    bestj = j;\n                }\n            }\n\n            dpCur[i] = best;\n            parent[d][i] = (bestj < 0 ? 0 : bestj);\n        }\n\n        dpPrev.swap(dpCur);\n    }\n\n    vector<int> choice(D, 0);\n    int last = 0;\n    for (int i = 1; i < (int)dpPrev.size(); i++) {\n        if (dpPrev[i] < dpPrev[last]) last = i;\n    }\n    choice[D - 1] = last;\n\n    for (int d = D - 1; d >= 1; d--) {\n        int p = parent[d][choice[d]];\n        if (p < 0) p = 0;\n        choice[d - 1] = p;\n    }\n\n    for (int d = 0; d < D; d++) {\n        const auto& rects = cands[d][choice[d]].rects;\n        for (int k = 0; k < N; k++) {\n            const auto& r = rects[k];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\nstatic constexpr int N_CONST = 9;\nstatic constexpr int K_CONST = 81;\nstatic constexpr int CELLS = N_CONST * N_CONST;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return static_cast<int>(next_u64() % static_cast<uint64_t>(n));\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Action {\n    uint8_t cell[9];\n    uint32_t val[9];\n    uint32_t thr[9]; // MOD - val\n    long long raw = 0; // sum val\n    int m = 0, p = 0, q = 0;\n};\n\nstruct State {\n    array<uint32_t, CELLS> board{};\n    array<int, K_CONST> ops{};\n    long long score = 0;\n};\n\ninline long long gain_add(const array<uint32_t, CELLS>& board, const Action& a) {\n    int wraps = 0;\n    for (int k = 0; k < 9; k++) {\n        wraps += (board[a.cell[k]] >= a.thr[k]);\n    }\n    return a.raw - 1LL * MOD * wraps;\n}\n\ninline void apply_add(State& st, const Action& a) {\n    for (int k = 0; k < 9; k++) {\n        const int idx = a.cell[k];\n        const uint32_t oldv = st.board[idx];\n        uint32_t nv = oldv + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        st.board[idx] = nv;\n        st.score += (long long)nv - (long long)oldv;\n    }\n}\n\ninline void apply_remove(State& st, const Action& a) {\n    for (int k = 0; k < 9; k++) {\n        const int idx = a.cell[k];\n        const uint32_t oldv = st.board[idx];\n        const uint32_t v = a.val[k];\n        uint32_t nv = (oldv >= v) ? (oldv - v) : (oldv + MOD - v);\n        st.board[idx] = nv;\n        st.score += (long long)nv - (long long)oldv;\n    }\n}\n\nState make_empty_state(const array<uint32_t, CELLS>& base, int dummy_id) {\n    State st;\n    st.board = base;\n    st.ops.fill(dummy_id);\n    long long s = 0;\n    for (uint32_t v : base) s += v;\n    st.score = s;\n    return st;\n}\n\ninline void shuffle_order(array<int, K_CONST>& ord, XorShift64& rng) {\n    for (int i = K_CONST - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nbool one_sweep(State& st, const vector<Action>& actions, int dummy_id,\n               array<int, K_CONST>& order, XorShift64& rng) {\n    shuffle_order(order, rng);\n    bool changed = false;\n    const int A = dummy_id;\n\n    for (int t = 0; t < K_CONST; t++) {\n        const int pos = order[t];\n        const int old = st.ops[pos];\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int best = dummy_id;\n        long long best_gain = 0; // dummy gain\n\n        for (int id = 0; id < A; id++) {\n            const long long g = gain_add(st.board, actions[id]);\n            if (g > best_gain || (g == best_gain && id == old)) {\n                best_gain = g;\n                best = id;\n            }\n        }\n\n        if (best != dummy_id) apply_add(st, actions[best]);\n        st.ops[pos] = best;\n        if (best != old) changed = true;\n    }\n    return changed;\n}\n\nvoid local_opt(State& st, const vector<Action>& actions, int dummy_id,\n               Timer& timer, double tl, XorShift64& rng, int max_sweeps) {\n    array<int, K_CONST> order;\n    iota(order.begin(), order.end(), 0);\n\n    for (int sw = 0; sw < max_sweeps; sw++) {\n        if (timer.elapsed() >= tl) break;\n        bool changed = one_sweep(st, actions, dummy_id, order, rng);\n        if (!changed) break;\n    }\n}\n\nvoid random_perturb(State& st, const vector<Action>& actions, int dummy_id,\n                    XorShift64& rng, int cnt) {\n    const int A = dummy_id;\n    for (int t = 0; t < cnt; t++) {\n        const int pos = rng.next_int(K_CONST);\n        const int old = st.ops[pos];\n\n        int nid;\n        if (rng.next_int(8) == 0) nid = dummy_id; // allow reducing operation count\n        else nid = rng.next_int(A);\n\n        if (nid == old) continue;\n        if (old != dummy_id) apply_remove(st, actions[old]);\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n    }\n}\n\nState construct_random_greedy(const array<uint32_t, CELLS>& base,\n                              const vector<Action>& actions, int dummy_id,\n                              XorShift64& rng) {\n    constexpr int TOPR = 5;\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K_CONST; pos++) {\n        array<long long, TOPR> best_g;\n        array<int, TOPR> best_id;\n        best_g.fill(LLONG_MIN);\n        best_id.fill(-1);\n\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(st.board, actions[id]);\n            if (g <= 0) continue;\n            if (g <= best_g[TOPR - 1]) continue;\n\n            int at = TOPR - 1;\n            while (at > 0 && g > best_g[at - 1]) --at;\n            for (int t = TOPR - 1; t > at; --t) {\n                best_g[t] = best_g[t - 1];\n                best_id[t] = best_id[t - 1];\n            }\n            best_g[at] = g;\n            best_id[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < TOPR && best_id[cnt] != -1) cnt++;\n        if (cnt == 0) break;\n\n        int pick = best_id[rng.next_int(cnt)];\n        st.ops[pos] = pick;\n        apply_add(st, actions[pick]);\n    }\n    return st;\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    array<uint32_t, CELLS> base{};\n    uint64_t seed = 0x1234567890ABCDEFull;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(N); mix(M); mix(K);\n\n    for (int i = 0; i < N_CONST; i++) {\n        for (int j = 0; j < N_CONST; j++) {\n            uint32_t v;\n            cin >> v;\n            base[i * N_CONST + j] = v;\n            mix(v);\n        }\n    }\n\n    vector<array<array<uint32_t, 3>, 3>> stamp(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                uint32_t v;\n                cin >> v;\n                stamp[m][i][j] = v;\n                mix(v);\n            }\n        }\n    }\n\n    vector<Action> actions;\n    actions.reserve(M * (N_CONST - 2) * (N_CONST - 2));\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N_CONST - 3; p++) {\n            for (int q = 0; q <= N_CONST - 3; q++) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                ac.raw = 0;\n\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        uint32_t v = stamp[m][i][j];\n                        ac.val[t] = v;\n                        ac.thr[t] = MOD - v;\n                        ac.cell[t] = static_cast<uint8_t>((p + i) * N_CONST + (q + j));\n                        ac.raw += v;\n                        t++;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n\n    const int dummy_id = (int)actions.size();\n    XorShift64 rng(seed);\n    Timer timer;\n\n    const double TL = 1.85;\n\n    State best = make_empty_state(base, dummy_id);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 40);\n\n    // Diversified starts\n    for (int t = 0; t < 4; t++) {\n        if (timer.elapsed() >= TL * 0.30) break;\n        State cand = construct_random_greedy(base, actions, dummy_id, rng);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 20);\n        if (cand.score > best.score) best = cand;\n    }\n\n    int stagnation = 0;\n    while (timer.elapsed() < TL) {\n        State cand;\n        if (stagnation >= 40 && rng.next_int(4) == 0) {\n            cand = construct_random_greedy(base, actions, dummy_id, rng);\n        } else {\n            cand = best;\n            int max_pert = min(25, 2 + stagnation / 4);\n            int cnt = 1 + rng.next_int(max_pert);\n            random_perturb(cand, actions, dummy_id, rng, cnt);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 12);\n\n        if (cand.score > best.score) {\n            best = cand;\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n    }\n\n    // Final polishing (if any time remains)\n    local_opt(best, actions, dummy_id, timer, TL, rng, 50);\n\n    vector<tuple<int, int, int>> ans;\n    ans.reserve(K_CONST);\n    for (int pos = 0; pos < K_CONST; pos++) {\n        int id = best.ops[pos];\n        if (id == dummy_id) continue;\n        const auto& ac = actions[id];\n        ans.emplace_back(ac.m, ac.p, ac.q);\n    }\n\n    cout << ans.size() << '\\n';\n    for (auto [m, p, q] : ans) {\n        cout << m << ' ' << p << ' ' << q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N;\n    vector<vector<int>> A;\n\n    // Simulation state\n    vector<int> nextIn;                 // next arrival index for each receiving row\n    vector<vector<int>> grid;           // container id or -1\n    int pr = 0, pc = 0;                 // large crane position\n    int hold = -1;                      // held container id or -1\n\n    vector<int> srcRow, srcIdx;         // source row / index in A for each container\n    vector<char> dispatched;            // dispatched flag per container\n    vector<int> need;                   // smallest not-yet-dispatched id for each dispatch row\n    int dispatchedCnt = 0;\n\n    int turn = 0;\n    int revealRow = -1;                 // currently focused destination row to reveal\n\n    vector<string> out;                 // output strings for all cranes\n\n    Solver(int n, const vector<vector<int>>& a) : N(n), A(a) {\n        nextIn.assign(N, 0);\n        grid.assign(N, vector<int>(N, -1));\n        srcRow.assign(N * N, -1);\n        srcIdx.assign(N * N, -1);\n        dispatched.assign(N * N, 0);\n        need.resize(N);\n        out.assign(N, \"\");\n\n        for (int r = 0; r < N; r++) need[r] = r * N;\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n    }\n\n    inline int md(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    void spawn_step() {\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] >= N) continue;\n            if (grid[r][0] != -1) continue;\n            if (pr == r && pc == 0 && hold != -1) continue; // crane holding on gate blocks spawn\n            grid[r][0] = A[r][nextIn[r]];\n            nextIn[r]++;\n        }\n    }\n\n    void dispatch_step() {\n        int dc = N - 1;\n        for (int r = 0; r < N; r++) {\n            if (grid[r][dc] == -1) continue;\n            int v = grid[r][dc];\n            grid[r][dc] = -1;\n\n            if (!dispatched[v]) {\n                dispatched[v] = 1;\n                dispatchedCnt++;\n            }\n\n            int dr = v / N;\n            int hi = dr * N + (N - 1);\n            while (need[dr] <= hi && dispatched[need[dr]]) need[dr]++;\n        }\n    }\n\n    // One full turn: spawn -> action -> dispatch\n    void apply(char act) {\n        if (turn >= 10000) return;\n\n        spawn_step();\n\n        char real = act;\n        if (act == 'P') {\n            if (!(hold == -1 && grid[pr][pc] != -1)) real = '.';\n        } else if (act == 'Q') {\n            if (!(hold != -1 && grid[pr][pc] == -1)) real = '.';\n        } else if (act == 'U') {\n            if (pr == 0) real = '.';\n        } else if (act == 'D') {\n            if (pr == N - 1) real = '.';\n        } else if (act == 'L') {\n            if (pc == 0) real = '.';\n        } else if (act == 'R') {\n            if (pc == N - 1) real = '.';\n        } else if (act != '.') {\n            real = '.';\n        }\n\n        switch (real) {\n            case 'P':\n                hold = grid[pr][pc];\n                grid[pr][pc] = -1;\n                break;\n            case 'Q':\n                grid[pr][pc] = hold;\n                hold = -1;\n                break;\n            case 'U': pr--; break;\n            case 'D': pr++; break;\n            case 'L': pc--; break;\n            case 'R': pc++; break;\n            case '.': break;\n        }\n\n        dispatch_step();\n\n        // Output action chars\n        out[0].push_back(real);\n        if (turn == 0) {\n            // Bomb all small cranes on first turn\n            for (int i = 1; i < N; i++) out[i].push_back('B');\n        } else {\n            for (int i = 1; i < N; i++) out[i].push_back('.');\n        }\n\n        turn++;\n    }\n\n    bool find_container(int v, int &rr, int &cc) const {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == v) {\n                    rr = r; cc = c;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool has_ready_container(int &bestV, int &bestR, int &bestC) const {\n        int bestScore = INT_MAX;\n        bestV = -1; bestR = -1; bestC = -1;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue; // completed row\n\n            int x = need[dr];\n            int r, c;\n            if (!find_container(x, r, c)) continue;\n\n            int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestV = x; bestR = r; bestC = c;\n            }\n        }\n        return bestV != -1;\n    }\n\n    int choose_reveal_row() const {\n        int bestRow = -1;\n        int bestScore = INT_MAX;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue; // completed\n\n            int x = need[dr];\n            int r, c;\n            if (find_container(x, r, c)) continue; // already on board\n\n            int s = srcRow[x];\n            int frontIdx = (grid[s][0] != -1 ? nextIn[s] - 1 : nextIn[s]);\n            int depth = srcIdx[x] - frontIdx;\n            if (depth < 0) depth = 0;\n\n            int sc = depth * 100 + md(pr, pc, s, 0);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestRow = dr;\n            }\n        }\n        return bestRow;\n    }\n\n    pair<int,int> choose_storage_cell() const {\n        int bestR = -1, bestC = -1;\n        int bestScore = INT_MAX;\n        int dr = (hold == -1 ? 0 : hold / N);\n\n        // Prefer internal cells (columns 1..N-2)\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= N - 2; c++) {\n                if (grid[r][c] != -1) continue;\n                int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestR = r; bestC = c;\n                }\n            }\n        }\n\n        // Also allow exhausted receiving gates as safe storage\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] != N) continue;\n            if (grid[r][0] != -1) continue;\n            int sc = md(pr, pc, r, 0) + md(r, 0, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestR = r; bestC = 0;\n            }\n        }\n\n        return {bestR, bestC};\n    }\n\n    void move_to(int tr, int tc) {\n        while (turn < 10000 && (pr != tr || pc != tc)) {\n            char d;\n            if (pc < tc) d = 'R';\n            else if (pc > tc) d = 'L';\n            else if (pr < tr) d = 'D';\n            else d = 'U';\n            apply(d);\n        }\n    }\n\n    void dispatch_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        int dr = hold / N;\n        move_to(dr, N - 1);\n        if (turn < 10000) apply('Q');\n    }\n\n    void solve() {\n        // Turn 0: keep large crane idle, bomb all small cranes.\n        apply('.');\n\n        // Main phase (order-preserving as much as possible)\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                revealRow = -1;\n                dispatch_holding();\n                continue;\n            }\n\n            int v, r, c;\n            if (has_ready_container(v, r, c)) {\n                revealRow = -1;\n                move_to(r, c);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) dispatch_holding();\n                continue;\n            }\n\n            // No ready container on board now\n            if (revealRow != -1) {\n                int hi = revealRow * N + (N - 1);\n                if (need[revealRow] > hi) revealRow = -1;\n                else {\n                    int rr, cc;\n                    if (find_container(need[revealRow], rr, cc)) revealRow = -1;\n                }\n            }\n            if (revealRow == -1) revealRow = choose_reveal_row();\n\n            if (revealRow == -1) {\n                // Fallback: dispatch nearest container (may break order, but safe)\n                int bestR = -1, bestC = -1, bestScore = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    for (int j = 0; j < N; j++) {\n                        int val = grid[i][j];\n                        if (val == -1) continue;\n                        int dr = val / N;\n                        int sc = md(pr, pc, i, j) + md(i, j, dr, N - 1);\n                        if (sc < bestScore) {\n                            bestScore = sc;\n                            bestR = i; bestC = j;\n                        }\n                    }\n                }\n                if (bestR == -1) {\n                    apply('.');\n                    continue;\n                }\n                move_to(bestR, bestC);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) dispatch_holding();\n                revealRow = -1;\n                continue;\n            }\n\n            int x = need[revealRow];\n            int s = srcRow[x];\n\n            move_to(s, 0);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold == -1) {\n                revealRow = -1;\n                continue;\n            }\n\n            int y = hold;\n            int dr = y / N;\n            int hi = dr * N + (N - 1);\n\n            if (need[dr] <= hi && y == need[dr]) {\n                // If picked one is now ready for its own row, dispatch directly\n                revealRow = -1;\n                dispatch_holding();\n            } else {\n                auto [sr, sc] = choose_storage_cell();\n                if (sr == -1) {\n                    // Emergency fallback\n                    revealRow = -1;\n                    dispatch_holding();\n                } else {\n                    move_to(sr, sc);\n                    if (turn >= 10000) break;\n                    apply('Q');\n                    // keep revealRow to continue revealing same target\n                }\n            }\n        }\n\n        if (turn < 10000 && hold != -1) dispatch_holding();\n\n        // Safety cleanup phase\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                dispatch_holding();\n                continue;\n            }\n\n            int bestR = -1, bestC = -1, bestScore = INT_MAX;\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    int val = grid[i][j];\n                    if (val == -1) continue;\n                    int dr = val / N;\n                    int sc = md(pr, pc, i, j) + md(i, j, dr, N - 1);\n                    if (sc < bestScore) {\n                        bestScore = sc;\n                        bestR = i; bestC = j;\n                    }\n                }\n            }\n\n            if (bestR == -1) {\n                bool anyQueue = false;\n                for (int r = 0; r < N; r++) if (nextIn[r] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(bestR, bestC);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) dispatch_holding();\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> A(N, vector<int>(N));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> A[i][j];\n    }\n\n    Solver solver(N, A);\n    solver.solve();\n\n    for (int i = 0; i < N; i++) {\n        cout << solver.out[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SimResult {\n    long long cost = (1LL << 62);\n    int turns = 0;\n    bool valid = false;\n    vector<string> ops;\n};\n\nclass Solver {\n    static constexpr int MAX_TURNS = 100000;\n    static constexpr long long INF = (1LL << 62);\n\n    int N = 0;\n    int M = 0;\n    vector<int> init_h;\n    vector<int> rr, cc;\n\n    int modM(int x) const {\n        x %= M;\n        if (x < 0) x += M;\n        return x;\n    }\n\n    vector<int> build_base_cycle() const {\n        // Hamiltonian cycle representation without repeating the start at the end.\n        // N is even (20 in this task).\n        vector<int> cyc;\n        cyc.reserve(M);\n\n        // Top row: left -> right\n        for (int c = 0; c < N; c++) cyc.push_back(c);\n\n        // Rows 1..N-1, excluding column 0\n        for (int r = 1; r < N; r++) {\n            if (r % 2 == 1) {\n                for (int c = N - 1; c >= 1; c--) cyc.push_back(r * N + c);\n            } else {\n                for (int c = 1; c < N; c++) cyc.push_back(r * N + c);\n            }\n        }\n\n        // Column 0: bottom -> up (excluding row 0)\n        for (int r = N - 1; r >= 1; r--) cyc.push_back(r * N + 0);\n\n        return cyc;\n    }\n\n    vector<int> transform_cycle(const vector<int>& base, int type) const {\n        // Several geometric transforms to diversify path candidates.\n        // Then rotate so that (0,0) becomes index 0.\n        vector<int> t;\n        t.reserve(M);\n\n        for (int id : base) {\n            int r = id / N, c = id % N;\n            int nr = r, nc = c;\n\n            switch (type) {\n                case 0: // identity\n                    nr = r; nc = c;\n                    break;\n                case 1: // horizontal flip\n                    nr = r; nc = N - 1 - c;\n                    break;\n                case 2: // transpose\n                    nr = c; nc = r;\n                    break;\n                case 3: // rotate-like (transpose + horizontal flip)\n                    nr = c; nc = N - 1 - r;\n                    break;\n                default:\n                    break;\n            }\n\n            t.push_back(nr * N + nc);\n        }\n\n        auto it = find(t.begin(), t.end(), 0);\n        if (it != t.end()) rotate(t.begin(), it, t.end());\n        return t;\n    }\n\n    template <bool RECORD>\n    SimResult simulate(const vector<int>& cyc, int dir, int shift) const {\n        vector<int> h = init_h;\n        long long cost = 0;\n        long long load = 0;\n        int turns = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(20000);\n\n        int pos = 0; // current cell id\n        int idx = 0; // current index on cycle\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF;\n            r.turns = turns;\n            r.valid = false;\n            if constexpr (RECORD) r.ops = move(ops);\n            return r;\n        };\n\n        auto do_load = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto do_unload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto do_move = [&](int nxt) {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else {\n                // Should never happen if cycle/path logic is correct.\n                return false;\n            }\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        auto unload_here = [&]() {\n            if (load <= 0) return;\n            if (h[pos] < 0) {\n                int x = (int)min<long long>(load, -1LL * h[pos]);\n                if (x > 0) {\n                    do_unload(x);\n                    h[pos] += x;\n                }\n            }\n        };\n\n        // 1) initial reposition along the cycle direction (no terrain handling)\n        for (int t = 0; t < shift; t++) {\n            idx = modM(idx + dir);\n            if (!do_move(cyc[idx])) return fail();\n            if (turns > MAX_TURNS) return fail();\n        }\n\n        // 2) main pass: process each cell exactly once in this order\n        for (int t = 0; t < M; t++) {\n            int cell = cyc[idx];\n\n            int v = h[cell];\n            if (v > 0) {\n                do_load(v);\n                h[cell] = 0;\n            } else if (v < 0) {\n                int x = (int)min<long long>(load, -1LL * v);\n                if (x > 0) {\n                    do_unload(x);\n                    h[cell] += x;\n                }\n            }\n\n            if (t + 1 < M) {\n                idx = modM(idx + dir);\n                if (!do_move(cyc[idx])) return fail();\n            }\n\n            if (turns > MAX_TURNS) return fail();\n        }\n\n        // 3) cleanup: remaining load must be unloaded to remaining negative cells\n        while (load > 0) {\n            unload_here();\n            if (load == 0) break;\n\n            int best = -1;\n            int bestDist = INT_MAX;\n            int bestDef = -1;\n            int pr = rr[pos], pc = cc[pos];\n\n            for (int id = 0; id < M; id++) {\n                if (h[id] < 0) {\n                    int d = abs(pr - rr[id]) + abs(pc - cc[id]);\n                    int def = -h[id];\n                    if (d < bestDist || (d == bestDist && def > bestDef)) {\n                        bestDist = d;\n                        bestDef = def;\n                        best = id;\n                    }\n                }\n            }\n\n            if (best == -1) break; // invalid situation (shouldn't happen)\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!do_move(nxt)) return fail();\n                unload_here();\n\n                if (turns > MAX_TURNS) return fail();\n            }\n        }\n\n        bool valid = true;\n        if (turns > MAX_TURNS) valid = false;\n        if (load != 0) valid = false;\n        for (int id = 0; id < M; id++) {\n            if (h[id] != 0) {\n                valid = false;\n                break;\n            }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) res.ops = move(ops);\n        return res;\n    }\n\npublic:\n    void solve() {\n        cin >> N;\n        M = N * N;\n\n        init_h.assign(M, 0);\n        rr.assign(M, 0);\n        cc.assign(M, 0);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int x;\n                cin >> x;\n                int id = r * N + c;\n                init_h[id] = x;\n                rr[id] = r;\n                cc[id] = c;\n            }\n        }\n\n        vector<int> base = build_base_cycle();\n\n        // Build candidate cycles\n        vector<vector<int>> cycles;\n        for (int tp = 0; tp < 4; tp++) {\n            vector<int> cyc = transform_cycle(base, tp);\n            if ((int)cyc.size() != M) continue;\n            if (cyc[0] != 0) continue;\n\n            bool dup = false;\n            for (auto &v : cycles) {\n                if (v == cyc) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) cycles.push_back(move(cyc));\n        }\n        if (cycles.empty()) cycles.push_back(base);\n\n        // Search best (cycle, direction, shift)\n        long long bestCost = INF;\n        int bestCycle = 0;\n        int bestDir = 1;\n        int bestShift = 0;\n\n        for (int ci = 0; ci < (int)cycles.size(); ci++) {\n            for (int dir : {1, -1}) {\n                for (int shift = 0; shift < M; shift++) {\n                    SimResult cur = simulate<false>(cycles[ci], dir, shift);\n                    if (cur.valid && cur.cost < bestCost) {\n                        bestCost = cur.cost;\n                        bestCycle = ci;\n                        bestDir = dir;\n                        bestShift = shift;\n                    }\n                }\n            }\n        }\n\n        SimResult ans = simulate<true>(cycles[bestCycle], bestDir, bestShift);\n        if (!ans.valid) {\n            // very unlikely fallback\n            ans = simulate<true>(cycles[0], 1, 0);\n        }\n\n        for (const string &s : ans.ops) {\n            cout << s << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // 2^53\n    }\n};\n\nclass Solver {\n    static constexpr int MAXS = 60;\n    static constexpr int MAXM = 15;\n\n    int N{}, M{}, T{};\n    int S{}, P{}; // S=seed count, P=cell count\n    int X[MAXS][MAXM]{}; // seed vectors\n    int V[MAXS]{};       // seed value sums\n    double PS[MAXS][MAXS]{}; // pair scores\n\n    vector<pair<int, int>> edges;   // grid edges (size S)\n    vector<vector<int>> nbr;        // neighbors per position\n    XorShift64 rng;\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    bool read_state() {\n        for (int i = 0; i < S; ++i) {\n            for (int l = 0; l < M; ++l) {\n                if (!(cin >> X[i][l])) return false;\n                if (X[i][l] < 0) exit(0); // interactive error signal safeguard\n            }\n            for (int l = M; l < MAXM; ++l) X[i][l] = 0;\n        }\n        return true;\n    }\n\n    void build_graph() {\n        edges.clear();\n        nbr.assign(P, {});\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p = i * N + j;\n                if (j + 1 < N) {\n                    int q = p + 1;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n                if (i + 1 < N) {\n                    int q = p + N;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n            }\n        }\n    }\n\n    void compute_values() {\n        for (int i = 0; i < S; ++i) {\n            int s = 0;\n            for (int l = 0; l < M; ++l) s += X[i][l];\n            V[i] = s;\n        }\n    }\n\n    void build_pair_scores(double cSigma) {\n        for (int i = 0; i < S; ++i) {\n            PS[i][i] = (double)V[i];\n            for (int j = i + 1; j < S; ++j) {\n                long long d2 = 0;\n                for (int l = 0; l < M; ++l) {\n                    int d = X[i][l] - X[j][l];\n                    d2 += 1LL * d * d;\n                }\n                double mu = 0.5 * (V[i] + V[j]);\n                double sigma = 0.5 * sqrt((double)d2);\n                double sc = mu + cSigma * sigma;\n                PS[i][j] = PS[j][i] = sc;\n            }\n        }\n    }\n\n    double evaluate(const vector<int>& a,\n                    double wSum, double wMax,\n                    double beta1, double beta2) const {\n        double edgeSum = 0.0;\n        double edgeBest = -1e100;\n        for (const auto& e : edges) {\n            double s = PS[a[e.first]][a[e.second]];\n            edgeSum += s;\n            if (s > edgeBest) edgeBest = s;\n        }\n\n        double cov1 = 0.0, cov2 = 0.0;\n        if (beta1 > 0.0 || beta2 > 0.0) {\n            for (int l = 0; l < M; ++l) {\n                int m1 = -1, m2 = -1;\n                for (int p = 0; p < P; ++p) {\n                    int val = X[a[p]][l];\n                    if (val > m1) {\n                        m2 = m1;\n                        m1 = val;\n                    } else if (val > m2) {\n                        m2 = val;\n                    }\n                }\n                if (m2 < 0) m2 = 0;\n                cov1 += m1;\n                cov2 += m2;\n            }\n        }\n\n        return wSum * edgeSum + wMax * edgeBest + beta1 * cov1 + beta2 * cov2;\n    }\n\n    vector<int> initial_assignment() {\n        vector<int> coordMax(M, 0);\n        for (int l = 0; l < M; ++l) {\n            int mx = 0;\n            for (int i = 0; i < S; ++i) mx = max(mx, X[i][l]);\n            coordMax[l] = mx;\n        }\n\n        vector<double> base(S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            int rare = 0, near = 0;\n            for (int l = 0; l < M; ++l) {\n                if (X[i][l] == coordMax[l]) rare++;\n                if (X[i][l] >= coordMax[l] - 2) near++;\n            }\n            base[i] = V[i] + 15.0 * rare + 2.5 * near;\n        }\n\n        vector<int> ordV(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<int> cand;\n        cand.reserve(S);\n        vector<char> used(S, 0);\n        auto add = [&](int id) {\n            if (!used[id]) {\n                used[id] = 1;\n                cand.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < min(S, 24); ++i) add(ordV[i]);\n\n        for (int l = 0; l < M; ++l) {\n            vector<int> ord(S);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                return V[a] > V[b];\n            });\n            for (int k = 0; k < min(S, 3); ++k) add(ord[k]);\n        }\n\n        auto cmp_base = [&](int a, int b) {\n            if (base[a] != base[b]) return base[a] > base[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        };\n\n        if ((int)cand.size() > P) {\n            sort(cand.begin(), cand.end(), cmp_base);\n            cand.resize(P);\n        }\n\n        used.assign(S, 0);\n        for (int id : cand) used[id] = 1;\n\n        vector<int> ordB(S);\n        iota(ordB.begin(), ordB.end(), 0);\n        sort(ordB.begin(), ordB.end(), cmp_base);\n        for (int id : ordB) {\n            if ((int)cand.size() >= P) break;\n            if (!used[id]) {\n                used[id] = 1;\n                cand.push_back(id);\n            }\n        }\n\n        vector<int> posOrd(P);\n        iota(posOrd.begin(), posOrd.end(), 0);\n        sort(posOrd.begin(), posOrd.end(), [&](int a, int b) {\n            int da = (int)nbr[a].size();\n            int db = (int)nbr[b].size();\n            if (da != db) return da > db;\n            return a < b;\n        });\n\n        sort(cand.begin(), cand.end(), cmp_base);\n\n        vector<int> assign(P, -1);\n        for (int k = 0; k < P; ++k) assign[posOrd[k]] = cand[k];\n        return assign;\n    }\n\n    vector<int> decide_layout(int turn) {\n        compute_values();\n\n        double progress = (T <= 1 ? 1.0 : (double)turn / (double)(T - 1));\n\n        // Tunable schedule (early: diversity, late: peak-hunting)\n        double cSigma = 0.9;\n        double wSum  = 1.0 - 0.7 * progress;\n        double wMax  = 18.0 * progress;\n        double beta1 = 10.0 * (1.0 - progress);\n        double beta2 = 4.0 * (1.0 - progress);\n\n        build_pair_scores(cSigma);\n\n        vector<int> assign = initial_assignment();\n        vector<int> seedPos(S, -1);\n        for (int p = 0; p < P; ++p) seedPos[assign[p]] = p;\n\n        auto eval_now = [&](const vector<int>& a) {\n            return evaluate(a, wSum, wMax, beta1, beta2);\n        };\n\n        double cur = eval_now(assign);\n        double best = cur;\n        vector<int> bestAssign = assign;\n\n        int ITER = 15000 + 1000 * turn;\n        double temp0 = 120.0, temp1 = 0.5;\n\n        for (int it = 0; it < ITER; ++it) {\n            int p = rng.next_int(P);\n            int s = rng.next_int(S);\n            int q = seedPos[s];\n            if (q == p) continue;\n\n            int oldP = assign[p];\n            double nxt;\n\n            if (q == -1) {\n                // replacement\n                assign[p] = s;\n                seedPos[s] = p;\n                seedPos[oldP] = -1;\n\n                nxt = eval_now(assign);\n                double delta = nxt - cur;\n                double temp = temp0 + (temp1 - temp0) * (double)it / (double)ITER;\n                bool ok = (delta >= 0.0) || (exp(delta / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestAssign = assign;\n                    }\n                } else {\n                    assign[p] = oldP;\n                    seedPos[oldP] = p;\n                    seedPos[s] = -1;\n                }\n            } else {\n                // swap\n                swap(assign[p], assign[q]); // s comes to p\n                seedPos[s] = p;\n                seedPos[oldP] = q;\n\n                nxt = eval_now(assign);\n                double delta = nxt - cur;\n                double temp = temp0 + (temp1 - temp0) * (double)it / (double)ITER;\n                bool ok = (delta >= 0.0) || (exp(delta / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestAssign = assign;\n                    }\n                } else {\n                    swap(assign[p], assign[q]);\n                    seedPos[s] = q;\n                    seedPos[oldP] = p;\n                }\n            }\n        }\n\n        assign = bestAssign;\n        fill(seedPos.begin(), seedPos.end(), -1);\n        for (int p = 0; p < P; ++p) seedPos[assign[p]] = p;\n        cur = eval_now(assign);\n\n        // One greedy polishing pass\n        vector<int> plist(P);\n        iota(plist.begin(), plist.end(), 0);\n        for (int i = P - 1; i > 0; --i) {\n            int j = rng.next_int(i + 1);\n            swap(plist[i], plist[j]);\n        }\n\n        for (int p : plist) {\n            int oldP = assign[p];\n            double localBest = cur;\n            int bestS = -1;\n            int bestQ = -2; // -1 means replacement\n\n            for (int s = 0; s < S; ++s) {\n                int q = seedPos[s];\n                if (q == p) continue;\n\n                double candScore;\n\n                if (q == -1) {\n                    assign[p] = s;\n                    seedPos[s] = p;\n                    seedPos[oldP] = -1;\n\n                    candScore = eval_now(assign);\n\n                    assign[p] = oldP;\n                    seedPos[oldP] = p;\n                    seedPos[s] = -1;\n                } else {\n                    swap(assign[p], assign[q]);\n                    seedPos[s] = p;\n                    seedPos[oldP] = q;\n\n                    candScore = eval_now(assign);\n\n                    swap(assign[p], assign[q]);\n                    seedPos[s] = q;\n                    seedPos[oldP] = p;\n                }\n\n                if (candScore > localBest + 1e-9) {\n                    localBest = candScore;\n                    bestS = s;\n                    bestQ = q;\n                }\n            }\n\n            if (bestS != -1) {\n                if (bestQ == -1) {\n                    int out = assign[p];\n                    assign[p] = bestS;\n                    seedPos[bestS] = p;\n                    seedPos[out] = -1;\n                } else {\n                    int out = assign[p];\n                    int q = bestQ;\n                    swap(assign[p], assign[q]); // bestS -> p\n                    seedPos[bestS] = p;\n                    seedPos[out] = q;\n                }\n                cur = localBest;\n            }\n        }\n\n        return assign;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> T)) return;\n        S = 2 * N * (N - 1);\n        P = N * N;\n\n        build_graph();\n        if (!read_state()) return;\n\n        for (int turn = 0; turn < T; ++turn) {\n            vector<int> assign = decide_layout(turn);\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 (!read_state()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, V;\n    vector<string> S, T;\n\n    int C;      // N*N\n    int SCount; // C*4 states\n\n    // dir: 0=R,1=D,2=L,3=U\n    const int DX[4] = {0, 1, 0, -1};\n    const int DY[4] = {1, 0, -1, 0};\n\n    int rotDist[4][4];\n\n    vector<int> board;              // current occupancy\n    vector<int> srcCells, dstCells; // s=1,t=0 and s=0,t=1\n\n    // approach[cell][dir] = state id where leaf(dir) is exactly on 'cell'\n    // (state = root position + dir)\n    vector<array<int, 4>> approach;\n\n    // decode arrays for state id\n    vector<int> sx, sy, sd;\n\n    // distSC[state * C + cell] = min move+rotate turns to make leaf touch cell\n    // (without mandatory action turn when already there)\n    vector<uint8_t> distSC;\n\n    int initX = 0, initY = 0;\n    int curX = 0, curY = 0, curDir = 0;\n\n    vector<string> ops; // each line length 4 (2*V' with V'=2)\n\n    inline int encode(int x, int y, int d) const {\n        return ((x * N + y) << 2) | d;\n    }\n\n    void buildRot() {\n        for (int a = 0; a < 4; ++a) {\n            for (int b = 0; b < 4; ++b) {\n                int d = (b - a + 4) % 4;\n                rotDist[a][b] = min(d, 4 - d);\n            }\n        }\n    }\n\n    void input() {\n        cin >> N >> M >> V;\n        S.resize(N);\n        T.resize(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        C = N * N;\n        SCount = C * 4;\n\n        board.assign(C, 0);\n        srcCells.clear();\n        dstCells.clear();\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                int c = x * N + y;\n                int sv = (S[x][y] == '1');\n                int tv = (T[x][y] == '1');\n                board[c] = sv;\n                if (sv == 1 && tv == 0) srcCells.push_back(c);\n                else if (sv == 0 && tv == 1) dstCells.push_back(c);\n            }\n        }\n    }\n\n    void precompute() {\n        buildRot();\n\n        approach.assign(C, array<int, 4>{-1, -1, -1, -1});\n\n        sx.assign(SCount, 0);\n        sy.assign(SCount, 0);\n        sd.assign(SCount, 0);\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                for (int d = 0; d < 4; ++d) {\n                    int sid = encode(x, y, d);\n                    sx[sid] = x;\n                    sy[sid] = y;\n                    sd[sid] = d;\n                }\n            }\n        }\n\n        for (int c = 0; c < C; ++c) {\n            int x = c / N;\n            int y = c % N;\n            for (int d = 0; d < 4; ++d) {\n                int rx = x - DX[d];\n                int ry = y - DY[d];\n                if (0 <= rx && rx < N && 0 <= ry && ry < N) {\n                    approach[c][d] = encode(rx, ry, d);\n                }\n            }\n        }\n\n        distSC.assign((size_t)SCount * C, 0);\n\n        for (int sid = 0; sid < SCount; ++sid) {\n            int x = sx[sid];\n            int y = sy[sid];\n            int d = sd[sid];\n            size_t base = (size_t)sid * C;\n\n            for (int c = 0; c < C; ++c) {\n                int best = 100;\n                for (int d2 = 0; d2 < 4; ++d2) {\n                    int sid2 = approach[c][d2];\n                    if (sid2 < 0) continue;\n                    int man = abs(x - sx[sid2]) + abs(y - sy[sid2]);\n                    int cost = max(man, rotDist[d][d2]);\n                    if (cost < best) best = cost;\n                }\n                distSC[base + c] = (uint8_t)best;\n            }\n        }\n    }\n\n    pair<int, int> chooseInitialRoot() {\n        if (srcCells.empty() && dstCells.empty()) {\n            return {N / 2, N / 2};\n        }\n\n        vector<int> allCells = srcCells;\n        allCells.insert(allCells.end(), dstCells.begin(), dstCells.end());\n\n        long long bestScore = (1LL << 60);\n        int bx = N / 2, by = N / 2;\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                int sid = encode(x, y, 0); // initial dir is Right\n                size_t base = (size_t)sid * C;\n                long long score = 0;\n                for (int c : allCells) score += (int)distSC[base + c];\n\n                int tieCur = abs(x - N / 2) + abs(y - N / 2);\n                int tieBest = abs(bx - N / 2) + abs(by - N / 2);\n\n                if (score < bestScore || (score == bestScore && tieCur < tieBest)) {\n                    bestScore = score;\n                    bx = x;\n                    by = y;\n                }\n            }\n        }\n        return {bx, by};\n    }\n\n    // Move to (tx,ty,tdir), and if doAction=true, put P on last turn.\n    // For V'=2, command string length is 4: [move][rot1][act0][act1]\n    void addMoveToState(int tx, int ty, int tdir, bool doAction) {\n        int man = abs(tx - curX) + abs(ty - curY);\n\n        int diff = (tdir - curDir + 4) % 4;\n        int rotSteps = 0;\n        int rotType = 0; // +1 => 'R', -1 => 'L'\n        if (diff == 0) {\n            rotSteps = 0;\n        } else if (diff == 1) {\n            rotSteps = 1;\n            rotType = +1;\n        } else if (diff == 3) {\n            rotSteps = 1;\n            rotType = -1;\n        } else { // diff==2\n            rotSteps = 2;\n            rotType = +1;\n        }\n\n        int moveTurns = max(man, rotSteps);\n        int turns = moveTurns;\n        if (doAction && turns == 0) turns = 1;\n\n        int vx = tx - curX;\n        int vy = ty - curY;\n        int rotRemain = rotSteps;\n\n        for (int step = 0; step < turns; ++step) {\n            char mv = '.';\n            if (vx < 0) {\n                mv = 'U';\n                ++vx;\n                --curX;\n            } else if (vx > 0) {\n                mv = 'D';\n                --vx;\n                ++curX;\n            } else if (vy < 0) {\n                mv = 'L';\n                ++vy;\n                --curY;\n            } else if (vy > 0) {\n                mv = 'R';\n                --vy;\n                ++curY;\n            }\n\n            char rt = '.';\n            if (rotRemain > 0) {\n                if (rotType == +1) {\n                    rt = 'R';\n                    curDir = (curDir + 1) & 3;\n                } else if (rotType == -1) {\n                    rt = 'L';\n                    curDir = (curDir + 3) & 3;\n                }\n                --rotRemain;\n            }\n\n            string line(4, '.');\n            line[0] = mv;\n            line[1] = rt;\n            line[2] = '.';\n            line[3] = (doAction && step == turns - 1) ? 'P' : '.';\n            ops.push_back(line);\n        }\n    }\n\n    int chooseBestDropSid(int targetCell, const vector<int>& srcAlive) {\n        int bestSid = -1;\n        int bestCost = 1e9;\n        int bestFuture = 1e9;\n\n        for (int dt = 0; dt < 4; ++dt) {\n            int sidT = approach[targetCell][dt];\n            if (sidT < 0) continue;\n\n            int move = max(abs(curX - sx[sidT]) + abs(curY - sy[sidT]),\n                           rotDist[curDir][dt]);\n            int cost = (move == 0 ? 1 : move);\n\n            int future = 0;\n            if (!srcAlive.empty()) {\n                future = 1e9;\n                size_t base = (size_t)sidT * C;\n                for (int sCell : srcAlive) {\n                    int d = (int)distSC[base + sCell];\n                    if (d < future) future = d;\n                }\n            }\n\n            if (cost < bestCost || (cost == bestCost && future < bestFuture)) {\n                bestCost = cost;\n                bestFuture = future;\n                bestSid = sidT;\n            }\n        }\n\n        if (bestSid < 0) {\n            for (int dt = 0; dt < 4; ++dt) {\n                int sidT = approach[targetCell][dt];\n                if (sidT >= 0) {\n                    bestSid = sidT;\n                    break;\n                }\n            }\n        }\n        return bestSid;\n    }\n\n    void plan() {\n        auto [rx, ry] = chooseInitialRoot();\n        initX = rx;\n        initY = ry;\n        curX = rx;\n        curY = ry;\n        curDir = 0; // Right\n\n        ops.clear();\n        ops.reserve(60000);\n\n        vector<int> srcAlive = srcCells;\n        vector<int> dstAlive = dstCells;\n\n        while (!srcAlive.empty()) {\n            int bestTotal = 1e9;\n            int bestSP = -1, bestTP = -1, bestSidS = -1;\n\n            int srcN = (int)srcAlive.size();\n            int dstN = (int)dstAlive.size();\n\n            // Greedy best pair from current state\n            for (int si = 0; si < srcN; ++si) {\n                int sCell = srcAlive[si];\n                for (int ds = 0; ds < 4; ++ds) {\n                    int sidS = approach[sCell][ds];\n                    if (sidS < 0) continue;\n\n                    int firstMove = max(abs(curX - sx[sidS]) + abs(curY - sy[sidS]),\n                                        rotDist[curDir][ds]);\n                    int firstCost = (firstMove == 0 ? 1 : firstMove);\n\n                    if (firstCost + 1 >= bestTotal) continue; // second >= 1\n\n                    size_t base = (size_t)sidS * C;\n                    for (int ti = 0; ti < dstN; ++ti) {\n                        int tCell = dstAlive[ti];\n                        int secondMove = (int)distSC[base + tCell];\n                        int secondCost = (secondMove == 0 ? 1 : secondMove);\n                        int total = firstCost + secondCost;\n\n                        if (total < bestTotal) {\n                            bestTotal = total;\n                            bestSP = si;\n                            bestTP = ti;\n                            bestSidS = sidS;\n                        }\n                    }\n                }\n            }\n\n            // Defensive fallback (shouldn't happen)\n            if (bestSP < 0) {\n                bestSP = 0;\n                bestTP = 0;\n                int sCell = srcAlive[0];\n                for (int d = 0; d < 4; ++d) {\n                    if (approach[sCell][d] >= 0) {\n                        bestSidS = approach[sCell][d];\n                        break;\n                    }\n                }\n                if (bestSidS < 0) break;\n            }\n\n            int sourceCell = srcAlive[bestSP];\n            int targetCell = dstAlive[bestTP];\n\n            // Pick\n            addMoveToState(sx[bestSidS], sy[bestSidS], sd[bestSidS], true);\n            board[sourceCell] = 0;\n\n            // Remove source\n            srcAlive[bestSP] = srcAlive.back();\n            srcAlive.pop_back();\n\n            // Drop\n            int sidT = chooseBestDropSid(targetCell, srcAlive);\n            addMoveToState(sx[sidT], sy[sidT], sd[sidT], true);\n            board[targetCell] = 1;\n\n            // Remove target\n            dstAlive[bestTP] = dstAlive.back();\n            dstAlive.pop_back();\n        }\n    }\n\n    void output() {\n        // Arm: root(0) --1--> leaf(1)\n        cout << 2 << '\\n';\n        cout << 0 << ' ' << 1 << '\\n';\n        cout << initX << ' ' << initY << '\\n';\n\n        for (const string& line : ops) {\n            cout << line << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.input();\n    solver.precompute();\n    solver.plan();\n    solver.output();\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstruct P {\n    int x, y;\n};\n\nstruct Component {\n    vector<int> cells;\n    int score = 0; // raw cell score sum\n    int perim = 0; // in cell-edge units\n};\n\nstruct Solver {\n    static constexpr int COORD_MAX = 100000;\n    static constexpr int PERIM_LIMIT = 400000;\n    static constexpr double SOFT_TIME_LIMIT = 1.90;\n\n    int N;\n    vector<P> pts;\n    vector<int> ptW; // +1 (mackerel), -1 (sardine)\n\n    int STEP = 625; // 100000 / 625 = 160\n    int W, H, C;\n    int PmaxUnits;\n\n    vector<int> raw;               // raw cell score: #mackerel - #sardine\n    vector<int> outsideSides;      // each cell: number of sides touching outside\n    vector<pair<int, int>> adjPairs; // neighboring cell pairs (right/up)\n    vector<vector<int>> pointCandCells; // for exact inside test on closed cell union\n\n    vector<int> prefix; // prefix sum over raw: (H+1)*(W+1)\n\n    int bestDiff = -1e9;\n    vector<char> bestSel; // best selected cells\n\n    chrono::steady_clock::time_point st;\n\n    inline int id(int x, int y) const { return y * W + x; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void read_input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        pts.resize(2 * N);\n        ptW.resize(2 * N);\n        for (int i = 0; i < 2 * N; i++) {\n            cin >> pts[i].x >> pts[i].y;\n            ptW[i] = (i < N ? +1 : -1);\n        }\n    }\n\n    void build_grid() {\n        W = COORD_MAX / STEP; // 160\n        H = COORD_MAX / STEP; // 160\n        C = W * H;\n        PmaxUnits = PERIM_LIMIT / STEP; // 640\n\n        raw.assign(C, 0);\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x / STEP;\n            int y = pts[i].y / STEP;\n            if (x >= W) x = W - 1; // x==100000 case\n            if (y >= H) y = H - 1; // y==100000 case\n            raw[id(x, y)] += ptW[i];\n        }\n\n        outsideSides.assign(C, 0);\n        adjPairs.clear();\n        adjPairs.reserve(C * 2);\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 out = 0;\n                if (x == 0) out++;\n                if (x == W - 1) out++;\n                if (y == 0) out++;\n                if (y == H - 1) out++;\n                outsideSides[v] = out;\n\n                if (x + 1 < W) adjPairs.push_back({v, id(x + 1, y)});\n                if (y + 1 < H) adjPairs.push_back({v, id(x, y + 1)});\n            }\n        }\n\n        // Prefix sum for box filter profits\n        prefix.assign((W + 1) * (H + 1), 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int cur = raw[id(x, y)];\n                int A = prefix[(y + 1) * (W + 1) + x];\n                int B = prefix[y * (W + 1) + (x + 1)];\n                int Cc = prefix[y * (W + 1) + x];\n                prefix[(y + 1) * (W + 1) + (x + 1)] = cur + A + B - Cc;\n            }\n        }\n\n        // Precompute exact inside-check candidate cells for each point.\n        pointCandCells.assign(2 * N, {});\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x;\n            int y = pts[i].y;\n            int qx = x / STEP;\n            int qy = y / STEP;\n\n            vector<int> xs, ys;\n\n            if (qx == W) xs = {W - 1};\n            else if (x % STEP == 0 && qx > 0) xs = {qx - 1, qx};\n            else xs = {qx};\n\n            if (qy == H) ys = {H - 1};\n            else if (y % STEP == 0 && qy > 0) ys = {qy - 1, qy};\n            else ys = {qy};\n\n            vector<int> cand;\n            cand.reserve(4);\n            for (int xx : xs) {\n                for (int yy : ys) {\n                    int v = id(xx, yy);\n                    bool dup = false;\n                    for (int t : cand) if (t == v) { dup = true; break; }\n                    if (!dup) cand.push_back(v);\n                }\n            }\n            pointCandCells[i] = move(cand);\n        }\n    }\n\n    int rect_sum(int x1, int y1, int x2, int y2) const {\n        if (x1 > x2 || y1 > y2) return 0;\n        x1 = max(x1, 0);\n        y1 = max(y1, 0);\n        x2 = min(x2, W - 1);\n        y2 = min(y2, H - 1);\n        if (x1 > x2 || y1 > y2) return 0;\n\n        int A = prefix[(y2 + 1) * (W + 1) + (x2 + 1)];\n        int B = prefix[y1 * (W + 1) + (x2 + 1)];\n        int Cc = prefix[(y2 + 1) * (W + 1) + x1];\n        int D = prefix[y1 * (W + 1) + x1];\n        return A - B - Cc + D;\n    }\n\n    vector<int> build_profit(int r) const {\n        vector<int> prof(C, 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int s = rect_sum(x - r, y - r, x + r, y + r);\n                prof[id(x, y)] = s * 10; // scale\n            }\n        }\n        return prof;\n    }\n\n    vector<char> segment_cut(const vector<int>& profit, int lambda) const {\n        vector<char> sel(C, 0);\n\n        if (lambda == 0) {\n            for (int i = 0; i < C; i++) sel[i] = (profit[i] > 0);\n            return sel;\n        }\n\n        int S = C;\n        int T = C + 1;\n        mf_graph<ll> g(C + 2);\n\n        // Unary terms: maximize profit - lambda*perimeter\n        for (int v = 0; v < C; v++) {\n            ll c1 = -(ll)profit[v] + (ll)lambda * outsideSides[v];\n            if (c1 >= 0) {\n                g.add_edge(v, T, c1);   // D(1)=c1, D(0)=0\n            } else {\n                g.add_edge(S, v, -c1);  // shift: D(0)=-c1, D(1)=0\n            }\n        }\n\n        // Pairwise Potts term: lambda * [different]\n        for (auto [u, v] : adjPairs) {\n            g.add_edge(u, v, lambda);\n            g.add_edge(v, u, lambda);\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n        for (int i = 0; i < C; i++) sel[i] = cut[i] ? 1 : 0;\n        return sel;\n    }\n\n    vector<Component> top_components(const vector<char>& sel, int K) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n        vector<Component> bests;\n        bests.reserve(K);\n\n        auto better = [](const Component& a, const Component& b) {\n            if (a.score != b.score) return a.score > b.score;\n            return a.perim < b.perim;\n        };\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n\n            vector<int> cells;\n            cells.reserve(256);\n            int sc = 0;\n            int per = 0;\n\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cells.push_back(v);\n                sc += raw[v];\n\n                int x = v % W, y = v / W;\n\n                // left\n                if (x == 0 || !sel[v - 1]) per++;\n                else if (!vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n\n                // right\n                if (x == W - 1 || !sel[v + 1]) per++;\n                else if (!vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n\n                // down\n                if (y == 0 || !sel[v - W]) per++;\n                else if (!vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n\n                // up\n                if (y == H - 1 || !sel[v + W]) per++;\n                else if (!vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (sc <= 0) continue;\n\n            Component comp;\n            comp.cells = move(cells);\n            comp.score = sc;\n            comp.perim = per;\n\n            if ((int)bests.size() < K) {\n                bests.push_back(move(comp));\n            } else {\n                int worst = 0;\n                for (int i = 1; i < K; i++) {\n                    if (better(bests[worst], bests[i])) worst = i;\n                }\n                if (better(comp, bests[worst])) {\n                    bests[worst] = move(comp);\n                }\n            }\n        }\n\n        sort(bests.begin(), bests.end(), better);\n        return bests;\n    }\n\n    int count_nb(const vector<char>& sel, int v) const {\n        int x = v % W, y = v / W;\n        int c = 0;\n        if (x > 0 && sel[v - 1]) c++;\n        if (x + 1 < W && sel[v + 1]) c++;\n        if (y > 0 && sel[v - W]) c++;\n        if (y + 1 < H && sel[v + W]) c++;\n        return c;\n    }\n\n    pair<int, int> score_perim(const vector<char>& sel) const {\n        int sc = 0, per = 0;\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            sc += raw[v];\n            int x = v % W, y = v / W;\n            if (x == 0 || !sel[v - 1]) per++;\n            if (x + 1 == W || !sel[v + 1]) per++;\n            if (y == 0 || !sel[v - W]) per++;\n            if (y + 1 == H || !sel[v + W]) per++;\n        }\n        return {sc, per};\n    }\n\n    void fill_holes(vector<char>& sel) const {\n        int minx = W, miny = H, maxx = -1, maxy = -1;\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            int x = v % W, y = v / W;\n            minx = min(minx, x);\n            miny = min(miny, y);\n            maxx = max(maxx, x);\n            maxy = max(maxy, y);\n        }\n        if (maxx < minx) return; // empty\n\n        int bw = maxx - minx + 1;\n        int bh = maxy - miny + 1;\n        int LW = bw + 2;\n        int LH = bh + 2;\n\n        vector<char> blocked(LW * LH, 0), vis(LW * LH, 0);\n\n        for (int y = miny; y <= maxy; y++) {\n            for (int x = minx; x <= maxx; x++) {\n                int gv = id(x, y);\n                if (sel[gv]) {\n                    int lx = (x - minx) + 1;\n                    int ly = (y - miny) + 1;\n                    blocked[ly * LW + lx] = 1;\n                }\n            }\n        }\n\n        queue<int> q;\n        auto push_if = [&](int lx, int ly) {\n            int t = ly * LW + lx;\n            if (!blocked[t] && !vis[t]) {\n                vis[t] = 1;\n                q.push(t);\n            }\n        };\n\n        for (int x = 0; x < LW; x++) {\n            push_if(x, 0);\n            push_if(x, LH - 1);\n        }\n        for (int y = 0; y < LH; y++) {\n            push_if(0, y);\n            push_if(LW - 1, y);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int x = v % LW, y = v / LW;\n            if (x > 0) push_if(x - 1, y);\n            if (x + 1 < LW) push_if(x + 1, y);\n            if (y > 0) push_if(x, y - 1);\n            if (y + 1 < LH) push_if(x, y + 1);\n        }\n\n        // unreachable empty cells => holes\n        for (int ly = 1; ly <= bh; ly++) {\n            for (int lx = 1; lx <= bw; lx++) {\n                int t = ly * LW + lx;\n                if (!blocked[t] && !vis[t]) {\n                    int gx = minx + (lx - 1);\n                    int gy = miny + (ly - 1);\n                    sel[id(gx, gy)] = 1;\n                }\n            }\n        }\n    }\n\n    void refine(vector<char>& sel) const {\n        auto [sc0, per0] = score_perim(sel);\n        (void)sc0;\n        int perim = per0;\n\n        // 1) remove negative leaves\n        queue<int> q;\n        for (int v = 0; v < C; v++) {\n            if (sel[v] && raw[v] < 0 && count_nb(sel, v) <= 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (!sel[v]) continue;\n\n            int deg = count_nb(sel, v);\n            if (raw[v] < 0 && deg <= 1) {\n                sel[v] = 0;\n                perim += (-4 + 2 * deg);\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && raw[v - 1] < 0 && count_nb(sel, v - 1) <= 1) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1] && raw[v + 1] < 0 && count_nb(sel, v + 1) <= 1) q.push(v + 1);\n                if (y > 0 && sel[v - W] && raw[v - W] < 0 && count_nb(sel, v - W) <= 1) q.push(v - W);\n                if (y + 1 < H && sel[v + W] && raw[v + W] < 0 && count_nb(sel, v + W) <= 1) q.push(v + W);\n            }\n        }\n\n        // 2) if perimeter too large, remove any leaf with minimal loss\n        while (perim > PmaxUnits) {\n            int best = -1;\n            int bestLoss = INT_MAX;\n            int bestDeg = 0;\n\n            for (int v = 0; v < C; v++) {\n                if (!sel[v]) continue;\n                int deg = count_nb(sel, v);\n                if (deg <= 1) {\n                    int loss = raw[v];\n                    if (loss < bestLoss) {\n                        bestLoss = loss;\n                        best = v;\n                        bestDeg = deg;\n                    }\n                }\n            }\n\n            if (best == -1) break;\n            sel[best] = 0;\n            perim += (-4 + 2 * bestDeg);\n        }\n\n        // 3) greedily add frontier positives (+ zero cells if they reduce perimeter)\n        priority_queue<pair<int, int>> pq; // (raw, idx)\n\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty()) {\n            auto [rw, v] = pq.top(); pq.pop();\n            (void)rw;\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            if (raw[v] > 0 || (raw[v] == 0 && dP < 0)) {\n                sel[v] = 1;\n                perim += dP;\n\n                int x = v % W, y = v / W;\n                if (x > 0) push_frontier(v - 1);\n                if (x + 1 < W) push_frontier(v + 1);\n                if (y > 0) push_frontier(v - W);\n                if (y + 1 < H) push_frontier(v + W);\n            }\n        }\n    }\n\n    int exact_diff(const vector<char>& sel) const {\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            bool inside = false;\n            for (int c : pointCandCells[i]) {\n                if (sel[c]) { inside = true; break; }\n            }\n            if (inside) diff += ptW[i];\n        }\n        return diff;\n    }\n\n    void consider_candidate(vector<char> sel) {\n        if (elapsed() > SOFT_TIME_LIMIT) return;\n\n        bool any = false;\n        for (char b : sel) if (b) { any = true; break; }\n        if (!any) return;\n\n        fill_holes(sel);\n        refine(sel);\n        fill_holes(sel); // ensure no hole after growth\n\n        auto [sc, per] = score_perim(sel);\n        (void)sc;\n        if (per > PmaxUnits) return;\n\n        any = false;\n        for (char b : sel) if (b) { any = true; break; }\n        if (!any) return;\n\n        int diff = exact_diff(sel);\n        if (diff > bestDiff) {\n            bestDiff = diff;\n            bestSel = move(sel);\n        }\n    }\n\n    static ll area2(const vector<P>& poly) {\n        ll s = 0;\n        int n = (int)poly.size();\n        for (int i = 0; i < n; i++) {\n            int j = (i + 1) % n;\n            s += 1LL * poly[i].x * poly[j].y - 1LL * poly[i].y * poly[j].x;\n        }\n        return s;\n    }\n\n    vector<P> cells_to_polygon(const vector<char>& sel) const {\n        const int SHIFT = 20;\n        const ll MASK = (1LL << SHIFT) - 1;\n\n        auto key = [&](int x, int y) -> ll {\n            return ((ll)x << SHIFT) | (ll)y;\n        };\n        auto decode = [&](ll k) -> P {\n            return P{(int)(k >> SHIFT), (int)(k & MASK)};\n        };\n\n        unordered_map<ll, ll> nxt;\n        nxt.reserve(4096);\n\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            int cx = v % W, cy = v / W;\n            int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n            int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n\n            // oriented CCW around cell\n            if (cy == 0 || !sel[v - W]) nxt[key(x0, y0)] = key(x1, y0); // bottom\n            if (cx == W - 1 || !sel[v + 1]) nxt[key(x1, y0)] = key(x1, y1); // right\n            if (cy == H - 1 || !sel[v + W]) nxt[key(x1, y1)] = key(x0, y1); // top\n            if (cx == 0 || !sel[v - 1]) nxt[key(x0, y1)] = key(x0, y0); // left\n        }\n\n        if (nxt.empty()) return {};\n\n        unordered_set<ll> seen;\n        seen.reserve(nxt.size() * 2);\n\n        vector<P> bestCycle;\n        ll bestAbsArea = -1;\n\n        for (auto &kv : nxt) {\n            ll start = kv.first;\n            if (seen.count(start)) continue;\n\n            unordered_set<ll> local;\n            local.reserve(nxt.size() * 2);\n            vector<P> cyc;\n            ll cur = start;\n            bool ok = true;\n\n            while (true) {\n                if (local.count(cur)) {\n                    if (cur == start) break;\n                    ok = false;\n                    break;\n                }\n                local.insert(cur);\n                seen.insert(cur);\n\n                auto it = nxt.find(cur);\n                if (it == nxt.end()) { ok = false; break; }\n\n                cyc.push_back(decode(cur));\n                cur = it->second;\n\n                if ((int)cyc.size() > (int)nxt.size() + 5) { ok = false; break; }\n            }\n\n            if (!ok || (int)cyc.size() < 4) continue;\n            ll a2 = llabs(area2(cyc));\n            if (a2 > bestAbsArea) {\n                bestAbsArea = a2;\n                bestCycle = move(cyc);\n            }\n        }\n\n        if (bestCycle.empty()) return {};\n\n        // compress collinear\n        vector<P> poly = bestCycle;\n        bool changed = true;\n        while (changed && poly.size() > 4) {\n            changed = false;\n            int n = (int)poly.size();\n            vector<P> np;\n            np.reserve(n);\n            for (int i = 0; i < n; i++) {\n                P a = poly[(i - 1 + n) % n];\n                P b = poly[i];\n                P c = poly[(i + 1) % n];\n                if ((a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y)) {\n                    changed = true;\n                    continue;\n                }\n                np.push_back(b);\n            }\n            if (np.size() < 4) break;\n            poly.swap(np);\n        }\n\n        return poly;\n    }\n\n    bool valid_poly(const vector<P>& poly) const {\n        int m = (int)poly.size();\n        if (m < 4 || m > 1000) return false;\n\n        const int SHIFT = 20;\n        unordered_set<ll> used;\n        used.reserve(m * 2);\n\n        ll per = 0;\n        for (int i = 0; i < m; i++) {\n            int x = poly[i].x, y = poly[i].y;\n            if (x < 0 || x > COORD_MAX || y < 0 || y > COORD_MAX) return false;\n\n            ll k = ((ll)x << SHIFT) | (ll)y;\n            if (used.count(k)) return false;\n            used.insert(k);\n\n            int j = (i + 1) % m;\n            int x2 = poly[j].x, y2 = poly[j].y;\n            if (x != x2 && y != y2) return false;\n            ll len = llabs((ll)x - x2) + llabs((ll)y - y2);\n            if (len <= 0) return false;\n            per += len;\n        }\n\n        if (per > PERIM_LIMIT) return false;\n        return true;\n    }\n\n    int rect_diff(int x0, int x1, int y0, int y1) const {\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x0 <= x && x <= x1 && y0 <= y && y <= y1) diff += ptW[i];\n        }\n        return diff;\n    }\n\n    vector<P> fallback_polygon() const {\n        // Tiny 1x1 square around first mackerel\n        int x = pts[0].x;\n        int y = pts[0].y;\n\n        int x0, x1, y0, y1;\n        if (x < COORD_MAX) { x0 = x; x1 = x + 1; }\n        else { x0 = x - 1; x1 = x; }\n\n        if (y < COORD_MAX) { y0 = y; y1 = y + 1; }\n        else { y0 = y - 1; y1 = y; }\n\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n        build_grid();\n\n        // Profit maps by smoothing radius\n        vector<vector<int>> profits(4);\n        for (int r = 0; r <= 3; r++) profits[r] = build_profit(r);\n\n        // Candidate: best single raw-positive cell\n        int bestCell = -1;\n        for (int i = 0; i < C; i++) {\n            if (bestCell == -1 || raw[i] > raw[bestCell]) bestCell = i;\n        }\n        if (bestCell != -1 && raw[bestCell] > 0) {\n            vector<char> sel(C, 0);\n            sel[bestCell] = 1;\n            consider_candidate(move(sel));\n        }\n\n        // (radius, lambda) trials\n        vector<pair<int, int>> params = {\n            {2, 0}, {3, 0},\n            {0, 2}, {0, 3},\n            {1, 4}, {1, 6}, {1, 8},\n            {2, 6}, {2, 8}, {2,10}, {2,12}, {2,15},\n            {3,10}, {3,14}, {3,18}\n        };\n\n        for (auto [r, lam] : params) {\n            if (elapsed() > 1.85) break;\n\n            auto sel = segment_cut(profits[r], lam);\n            auto comps = top_components(sel, 3);\n\n            for (auto &cp : comps) {\n                vector<char> compSel(C, 0);\n                for (int v : cp.cells) compSel[v] = 1;\n                consider_candidate(move(compSel));\n                if (elapsed() > SOFT_TIME_LIMIT) break;\n            }\n        }\n\n        // Fallback tiny square\n        vector<P> fb = fallback_polygon();\n        int fbDiff = rect_diff(fb[0].x, fb[1].x, fb[0].y, fb[2].y);\n\n        vector<P> ans;\n        if (!bestSel.empty()) {\n            auto poly = cells_to_polygon(bestSel);\n            if (valid_poly(poly)) ans = move(poly);\n        }\n\n        if (ans.empty() || bestDiff < fbDiff) {\n            ans = fb;\n        }\n\n        // final safety\n        if (!valid_poly(ans)) {\n            ans = {{0,0}, {1,0}, {1,1}, {0,1}};\n        }\n\n        cout << ans.size() << '\\n';\n        for (auto &p : ans) {\n            cout << p.x << ' ' << p.y << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nconstexpr int MAXN = 105;\nconstexpr ll DIM_MAX = 1000000000LL;\n\nstatic inline uint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstruct FastRNG {\n    uint64_t x;\n    bool has_spare = false;\n    double spare = 0.0;\n\n    explicit FastRNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next_u64() {\n        return splitmix64(x += 0x9e3779b97f4a7c15ULL);\n    }\n    double uniform01() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n    int randint(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double normal01() {\n        if (has_spare) {\n            has_spare = false;\n            return spare;\n        }\n        double u, v, s;\n        do {\n            u = uniform01() * 2.0 - 1.0;\n            v = uniform01() * 2.0 - 1.0;\n            s = u * u + v * v;\n        } while (s >= 1.0 || s == 0.0);\n        double m = sqrt(-2.0 * log(s) / s);\n        spare = v * m;\n        has_spare = true;\n        return u * m;\n    }\n};\n\nstruct Operation {\n    uint8_t r; // 0/1\n    uint8_t d; // 0:U, 1:L\n    int b;     // -1 or previous index\n};\n\nstruct GreedyParam {\n    double gap_w;\n    double bal_w;\n    double noise_w;\n};\n\nstruct Scenario {\n    vector<ll> w, h;\n};\n\nstruct Candidate {\n    vector<Operation> ops;\n    vector<ll> predW, predH, predS; // per scenario\n    double avg = 0.0;\n    uint64_t hash = 0;\n};\n\ninline ll clamp_dim(ll v) {\n    if (v < 1) return 1;\n    if (v > DIM_MAX) return DIM_MAX;\n    return v;\n}\ninline bool overlap(ll l1, ll r1, ll l2, ll r2) {\n    return (l1 < r2) && (l2 < r1);\n}\n\n// Lower bound of final W+H with constraints W>=curW, H>=curH, W*H>=totalA\ninline double lower_bound_wh(ll curW, ll curH, long double totalA, long double sqrtA) {\n    long double w = (long double)curW;\n    long double h = (long double)curH;\n    if (w * h >= totalA) return (double)(w + h);\n\n    long double c1 = w + max(h, totalA / w); // fix W\n    long double c2 = h + max(w, totalA / h); // fix H\n    long double c3 = 1e100L;\n    if (w <= sqrtA && h <= sqrtA) c3 = 2.0L * sqrtA;\n    long double ans = min(c1, min(c2, c3));\n    return (double)ans;\n}\n\npair<ll, ll> simulate_layout(\n    const vector<ll>& baseW, const vector<ll>& baseH, const vector<Operation>& ops\n) {\n    int N = (int)ops.size();\n    array<ll, MAXN> x{}, y{}, w{}, h{};\n    ll BW = 0, BH = 0;\n\n    for (int i = 0; i < N; i++) {\n        const auto& op = ops[i];\n        ll wi = op.r ? baseH[i] : baseW[i];\n        ll hi = op.r ? baseW[i] : baseH[i];\n\n        ll xi = 0, yi = 0;\n        if (op.d == 0) { // U\n            xi = (op.b == -1) ? 0 : (x[op.b] + w[op.b]);\n            ll xr = xi + wi;\n            yi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(xi, xr, x[j], x[j] + w[j])) {\n                    ll cand = y[j] + h[j];\n                    if (cand > yi) yi = cand;\n                }\n            }\n        } else { // L\n            yi = (op.b == -1) ? 0 : (y[op.b] + h[op.b]);\n            ll yb = yi + hi;\n            xi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(yi, yb, y[j], y[j] + h[j])) {\n                    ll cand = x[j] + w[j];\n                    if (cand > xi) xi = cand;\n                }\n            }\n        }\n\n        x[i] = xi;\n        y[i] = yi;\n        w[i] = wi;\n        h[i] = hi;\n\n        BW = max(BW, xi + wi);\n        BH = max(BH, yi + hi);\n    }\n    return {BW, BH};\n}\n\nvector<Operation> build_greedy(\n    const vector<ll>& baseW, const vector<ll>& baseH,\n    const GreedyParam& param, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n    vector<Operation> ops(N);\n\n    array<ll, MAXN> x{}, y{}, w{}, h{};\n    ll curW = 0, curH = 0;\n    long double usedA = 0.0L;\n\n    long double totalA = 0.0L;\n    for (int i = 0; i < N; i++) totalA += (long double)baseW[i] * baseH[i];\n    long double sqrtA = sqrtl(max((long double)1.0, totalA));\n    long double norm = sqrtA + 1.0L;\n\n    for (int i = 0; i < N; i++) {\n        double bestScore = 1e300;\n        ll bestPerim = (1LL << 60);\n\n        Operation bestOp{0, 0, -1};\n        ll bestX = 0, bestY = 0, bestWi = 0, bestHi = 0;\n        ll nextW = 0, nextH = 0;\n\n        for (int rot = 0; rot < 2; rot++) {\n            ll wi = rot ? baseH[i] : baseW[i];\n            ll hi = rot ? baseW[i] : baseH[i];\n\n            for (int dir = 0; dir < 2; dir++) {\n                for (int b = -1; b < i; b++) {\n                    ll xi = 0, yi = 0;\n                    if (dir == 0) { // U\n                        xi = (b == -1) ? 0 : (x[b] + w[b]);\n                        ll xr = xi + wi;\n                        yi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(xi, xr, x[j], x[j] + w[j])) {\n                                ll cand = y[j] + h[j];\n                                if (cand > yi) yi = cand;\n                            }\n                        }\n                    } else { // L\n                        yi = (b == -1) ? 0 : (y[b] + h[b]);\n                        ll yb = yi + hi;\n                        xi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(yi, yb, y[j], y[j] + h[j])) {\n                                ll cand = x[j] + w[j];\n                                if (cand > xi) xi = cand;\n                            }\n                        }\n                    }\n\n                    ll nW = max(curW, xi + wi);\n                    ll nH = max(curH, yi + hi);\n\n                    long double newA = usedA + (long double)wi * hi;\n                    double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                    long double gap = (long double)nW * nH - newA;\n                    if (gap < 0) gap = 0;\n\n                    double score = lb\n                        + param.gap_w * (double)(gap / norm)\n                        + param.bal_w * (double)llabs(nW - nH);\n                    if (param.noise_w > 0.0) score += param.noise_w * rng.uniform01();\n\n                    ll perim = nW + nH;\n                    if (score < bestScore - 1e-12 ||\n                        (fabsl(score - bestScore) <= 1e-12 && perim < bestPerim)) {\n                        bestScore = score;\n                        bestPerim = perim;\n                        bestOp = Operation{(uint8_t)rot, (uint8_t)dir, b};\n                        bestX = xi;\n                        bestY = yi;\n                        bestWi = wi;\n                        bestHi = hi;\n                        nextW = nW;\n                        nextH = nH;\n                    }\n                }\n            }\n        }\n\n        ops[i] = bestOp;\n        x[i] = bestX;\n        y[i] = bestY;\n        w[i] = bestWi;\n        h[i] = bestHi;\n        curW = nextW;\n        curH = nextH;\n        usedA += (long double)bestWi * bestHi;\n    }\n\n    return ops;\n}\n\nvector<Operation> build_linear_chain(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal, bool minimize_cross\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (minimize_cross) {\n            if (horizontal) r = (w[i] < h[i]) ? 1 : 0; // min row height\n            else r = (h[i] < w[i]) ? 1 : 0;            // min col width\n        }\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 0 : 1), (i == 0 ? -1 : i - 1)};\n    }\n    return ops;\n}\n\nvector<Operation> build_single_stack(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal\n) {\n    // horizontal row: (L, -1), vertical column: (U, -1)\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n        else r = (h[i] < w[i]) ? 1 : 0;\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 1 : 0), -1};\n    }\n    return ops;\n}\n\nuint64_t hash_ops(const vector<Operation>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (size_t i = 0; i < ops.size(); i++) {\n        uint64_t v = (uint64_t)ops[i].r;\n        v = v * 3ULL + (uint64_t)ops[i].d;\n        v = v * 1315423911ULL + (uint64_t)(ops[i].b + 2);\n        h ^= splitmix64(v + (i + 1) * 0x9e3779b97f4a7c15ULL);\n    }\n    return h;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    ll sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n\n    vector<ll> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    seed ^= splitmix64((uint64_t)N * 1000003ULL + (uint64_t)T * 10007ULL + (uint64_t)sigma * 911382323ULL);\n    for (int i = 0; i < N; i++) {\n        seed ^= splitmix64((uint64_t)obsW[i] * 1000003ULL + (uint64_t)obsH[i] + (uint64_t)(i + 1) * 19260817ULL);\n    }\n    FastRNG rng(seed);\n\n    auto start_time = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    };\n\n    int S;\n    if (sigma <= 2500) S = 12;\n    else if (sigma <= 6000) S = 18;\n    else S = 24;\n\n    vector<Scenario> scenarios(S);\n    for (int s = 0; s < S; s++) {\n        scenarios[s].w.resize(N);\n        scenarios[s].h.resize(N);\n    }\n\n    // Scenario 0: observed values\n    for (int i = 0; i < N; i++) {\n        scenarios[0].w[i] = obsW[i];\n        scenarios[0].h[i] = obsH[i];\n    }\n    // Scenario 1/2: global +-sigma shifts\n    if (S >= 2) {\n        for (int i = 0; i < N; i++) {\n            scenarios[1].w[i] = clamp_dim(obsW[i] + sigma);\n            scenarios[1].h[i] = clamp_dim(obsH[i] + sigma);\n        }\n    }\n    if (S >= 3) {\n        for (int i = 0; i < N; i++) {\n            scenarios[2].w[i] = clamp_dim(obsW[i] - sigma);\n            scenarios[2].h[i] = clamp_dim(obsH[i] - sigma);\n        }\n    }\n    // Random posterior samples\n    for (int s = 3; s < S; s++) {\n        for (int i = 0; i < N; i++) {\n            ll sw = llround((long double)obsW[i] + (long double)sigma * rng.normal01());\n            ll sh = llround((long double)obsH[i] + (long double)sigma * rng.normal01());\n            scenarios[s].w[i] = clamp_dim(sw);\n            scenarios[s].h[i] = clamp_dim(sh);\n        }\n    }\n\n    int Ptarget = min(120, max(30, T * 2));\n    if (sigma <= 2500) Ptarget = min(Ptarget, 80);\n\n    vector<Candidate> pool;\n    pool.reserve(Ptarget + 16);\n    unordered_set<uint64_t> seen;\n    seen.reserve(Ptarget * 4 + 64);\n\n    auto add_candidate = [&](vector<Operation>&& ops) {\n        uint64_t h = hash_ops(ops);\n        if (seen.insert(h).second) {\n            Candidate c;\n            c.hash = h;\n            c.ops = move(ops);\n            pool.push_back(move(c));\n        }\n    };\n\n    // Baselines\n    add_candidate(build_linear_chain(obsW, obsH, true, true));\n    add_candidate(build_linear_chain(obsW, obsH, false, true));\n    add_candidate(build_single_stack(obsW, obsH, true));\n    add_candidate(build_single_stack(obsW, obsH, false));\n\n    // Deterministic greedy on observed\n    vector<GreedyParam> baseParams = {\n        {0.35, 0.006, 0.0},\n        {0.65, 0.010, 0.0},\n        {0.15, 0.000, 0.0}\n    };\n    for (auto gp : baseParams) {\n        add_candidate(build_greedy(obsW, obsH, gp, rng));\n    }\n\n    // Deterministic greedy on some scenarios\n    int scenarioDetCnt = min(S, max(6, Ptarget / 2));\n    for (int s = 0; s < scenarioDetCnt && (int)pool.size() < Ptarget; s++) {\n        GreedyParam gp{0.45, 0.008, 0.0};\n        add_candidate(build_greedy(scenarios[s].w, scenarios[s].h, gp, rng));\n    }\n\n    // Randomized greedy\n    int attempts = 0;\n    const double genBudgetSec = 1.15;\n    const int minNeed = min(Ptarget, 70);\n\n    while ((int)pool.size() < Ptarget && attempts < Ptarget * 20) {\n        if ((int)pool.size() >= minNeed && elapsed() > genBudgetSec) break;\n\n        int sid = rng.randint(0, S - 1);\n        GreedyParam gp;\n        gp.gap_w = 0.05 + 1.10 * rng.uniform01();\n        gp.bal_w = 0.03 * rng.uniform01();\n        gp.noise_w = (double)sigma * (0.45 * rng.uniform01());\n        if (rng.uniform01() < 0.15) gp.noise_w += (double)sigma * (0.50 * rng.uniform01());\n\n        add_candidate(build_greedy(scenarios[sid].w, scenarios[sid].h, gp, rng));\n        attempts++;\n    }\n\n    if (pool.empty()) {\n        add_candidate(build_greedy(obsW, obsH, GreedyParam{0.40, 0.008, 0.0}, rng));\n    }\n\n    // Precompute each candidate on each scenario\n    for (auto& cand : pool) {\n        cand.predW.resize(S);\n        cand.predH.resize(S);\n        cand.predS.resize(S);\n\n        long double sum = 0.0L;\n        for (int s = 0; s < S; s++) {\n            auto [W, H] = simulate_layout(scenarios[s].w, scenarios[s].h, cand.ops);\n            cand.predW[s] = W;\n            cand.predH[s] = H;\n            cand.predS[s] = W + H;\n            sum += (long double)(W + H);\n        }\n        cand.avg = (double)(sum / (long double)S);\n    }\n\n    // Online planning\n    vector<ll> bestScenario(S, (1LL << 60));\n    vector<double> logWeight(S, 0.0);\n    vector<char> used(pool.size(), 0);\n    int usedCnt = 0;\n\n    const double likeSigma = max(1000.0, (double)sigma * 1.8);\n    const double inv2var = 1.0 / (2.0 * likeSigma * likeSigma);\n    const double alphaPosterior = 0.7;\n\n    vector<double> weights(S, 1.0 / S);\n\n    for (int turn = 0; turn < T; turn++) {\n        double mxLog = *max_element(logWeight.begin(), logWeight.end());\n        double sumW = 0.0;\n        for (int s = 0; s < S; s++) {\n            weights[s] = exp(logWeight[s] - mxLog);\n            sumW += weights[s];\n        }\n        if (sumW <= 0) {\n            for (int s = 0; s < S; s++) weights[s] = 1.0 / S;\n        } else {\n            for (int s = 0; s < S; s++) weights[s] /= sumW;\n        }\n        for (int s = 0; s < S; s++) {\n            weights[s] = (1.0 - alphaPosterior) / S + alphaPosterior * weights[s];\n        }\n\n        bool hasUnused = (usedCnt < (int)pool.size());\n        int chosen = -1;\n        long double bestVal = 1e300L;\n\n        for (int ci = 0; ci < (int)pool.size(); ci++) {\n            if (hasUnused && used[ci]) continue;\n\n            long double val = 0.0L;\n            for (int s = 0; s < S; s++) {\n                ll sc = pool[ci].predS[s];\n                ll cur = (bestScenario[s] < sc) ? bestScenario[s] : sc;\n                val += (long double)weights[s] * (long double)cur;\n            }\n\n            if (chosen == -1 || val < bestVal - 1e-12L ||\n                (fabsl(val - bestVal) <= 1e-12L && pool[ci].avg < pool[chosen].avg)) {\n                bestVal = val;\n                chosen = ci;\n            }\n        }\n        if (chosen == -1) chosen = 0;\n\n        if (!used[chosen]) {\n            used[chosen] = 1;\n            usedCnt++;\n        }\n\n        // Output this turn\n        cout << N << '\\n';\n        for (int i = 0; i < N; i++) {\n            const auto& op = pool[chosen].ops[i];\n            cout << i << ' ' << int(op.r) << ' ' << (op.d == 0 ? 'U' : 'L') << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        // Receive measured W', H'\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        if (Wm == -1 && Hm == -1) return 0;\n\n        // Update best per scenario\n        for (int s = 0; s < S; s++) {\n            if (pool[chosen].predS[s] < bestScenario[s]) bestScenario[s] = pool[chosen].predS[s];\n        }\n\n        // Posterior update\n        for (int s = 0; s < S; s++) {\n            double dw = (double)Wm - (double)pool[chosen].predW[s];\n            double dh = (double)Hm - (double)pool[chosen].predH[s];\n            logWeight[s] += -(dw * dw + dh * dh) * inv2var;\n        }\n\n        // Numerical stabilization\n        double mx2 = *max_element(logWeight.begin(), logWeight.end());\n        for (int s = 0; s < S; s++) logWeight[s] -= mx2;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<vector<int>> g;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point t0;\n\n    struct State {\n        vector<int> d;      // depth labels\n        vector<int> cnt;    // support count: #neighbors with depth d[v]-1 (for d[v] > 0)\n        long long extra = 0; // sum d[v] * A[v]\n    };\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        // Coordinates are not used in this solver\n        for (int i = 0; i < N; i++) {\n            int x, y;\n            cin >> x >> y;\n        }\n    }\n\n    inline bool feasible_change(const State& st, int v, int nd) const {\n        int od = st.d[v];\n        if (nd == od) return false;\n        if (nd < 0 || nd > H) return false;\n\n        // v itself must be supported if nd > 0\n        if (nd > 0) {\n            bool ok = false;\n            for (int u : g[v]) {\n                if (st.d[u] == nd - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n\n        // Neighbors depending on v must remain supported\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            int c = st.cnt[u];\n            if (od == need) --c;\n            if (nd == need) ++c;\n            if (c <= 0) return false;\n        }\n\n        return true;\n    }\n\n    inline void apply_change(State& st, int v, int nd) const {\n        int od = st.d[v];\n        if (od == nd) return;\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            if (od == need) --st.cnt[u];\n            if (nd == need) ++st.cnt[u];\n        }\n\n        st.d[v] = nd;\n        if (nd == 0) {\n            st.cnt[v] = 0;\n        } else {\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == nd - 1) ++c;\n            st.cnt[v] = c;\n        }\n\n        st.extra += 1LL * (nd - od) * A[v];\n    }\n\n    void rebuild(State& st) const {\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n        for (int v = 0; v < N; v++) st.extra += 1LL * st.d[v] * A[v];\n\n        for (int v = 0; v < N; v++) {\n            if (st.d[v] == 0) continue;\n            int need = st.d[v] - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n    }\n\n    // Safety repair (normally no-op)\n    void repair_depth(vector<int>& d) const {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int v = 0; v < N; v++) {\n                while (d[v] > 0) {\n                    int need = d[v] - 1;\n                    bool ok = false;\n                    for (int u : g[v]) {\n                        if (d[u] == need) {\n                            ok = true;\n                            break;\n                        }\n                    }\n                    if (ok) break;\n                    d[v]--;\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    bool greedy_up_pass(State& st, const vector<int>& order) {\n        bool changed = false;\n        for (int v : order) {\n            int cur = st.d[v];\n            for (int nd = H; nd > cur; --nd) {\n                if (feasible_change(st, v, nd)) {\n                    apply_change(st, v, nd);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n        return changed;\n    }\n\n    State construct_initial() {\n        State st;\n        st.d.assign(N, 0);\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n\n        vector<int> order(N), key(N);\n        iota(order.begin(), order.end(), 0);\n\n        // Mostly high A first, but randomized\n        for (int v = 0; v < N; v++) {\n            key[v] = A[v] * 1000 + rng.next_int(0, 999);\n        }\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] > key[b];\n            return a < b;\n        });\n\n        for (int pass = 0; pass < 25; pass++) {\n            bool changed = greedy_up_pass(st, order);\n            if (!changed) break;\n        }\n\n        return st;\n    }\n\n    vector<int> optimize_depths() {\n        t0 = chrono::steady_clock::now();\n\n        const double TOTAL_TIME = 1.90;\n        const double INIT_TIME = 0.22;\n        const int MAX_RESTART = 12;\n\n        State bestInit;\n        bestInit.extra = LLONG_MIN;\n\n        int restarts = 0;\n        while (restarts < MAX_RESTART && elapsed() < INIT_TIME) {\n            State st = construct_initial();\n            if (st.extra > bestInit.extra) bestInit = move(st);\n            ++restarts;\n        }\n\n        if (bestInit.extra == LLONG_MIN) {\n            bestInit.d.assign(N, 0);\n            bestInit.cnt.assign(N, 0);\n            bestInit.extra = 0;\n        }\n\n        State cur = bestInit;\n        long long bestExtra = cur.extra;\n        vector<int> bestDepth = cur.d;\n\n        vector<int> ordA(N);\n        iota(ordA.begin(), ordA.end(), 0);\n        sort(ordA.begin(), ordA.end(), [&](int a, int b) { return A[a] > A[b]; });\n\n        int topK = min(N, 300);\n\n        double saStart = elapsed();\n        double saEnd = TOTAL_TIME - 0.05;\n\n        if (saEnd > saStart + 1e-4) {\n            const double T0 = 50.0;\n            const double T1 = 0.2;\n            const double ratio = T1 / T0;\n            double temp = T0;\n\n            long long iter = 0;\n            while (true) {\n                if ((iter & 255LL) == 0) {\n                    double now = elapsed();\n                    if (now >= saEnd) break;\n                    double p = (now - saStart) / (saEnd - saStart);\n                    p = max(0.0, min(1.0, p));\n                    temp = T0 * pow(ratio, p);\n                }\n                ++iter;\n\n                int v;\n                if (rng.next_double() < 0.6) v = ordA[rng.next_int(0, topK - 1)];\n                else v = rng.next_int(0, N - 1);\n\n                bool avail[16] = {false}; // H=10 in this problem\n                avail[0] = true;\n                for (int u : g[v]) {\n                    int nd = cur.d[u] + 1;\n                    if (nd <= H) avail[nd] = true;\n                }\n\n                int cand[16];\n                int clen = 0;\n                for (int d = 0; d <= H; d++) {\n                    if (avail[d] && d != cur.d[v]) cand[clen++] = d;\n                }\n                if (clen == 0) continue;\n\n                int nd;\n                if (rng.next_double() < 0.45) nd = cand[clen - 1]; // often try deeper\n                else nd = cand[rng.next_int(0, clen - 1)];\n\n                if (!feasible_change(cur, v, nd)) continue;\n\n                int delta = (nd - cur.d[v]) * A[v];\n                bool accept = false;\n                if (delta >= 0) {\n                    accept = true;\n                } else {\n                    double x = (double)delta / temp;\n                    if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n                }\n\n                if (!accept) continue;\n\n                apply_change(cur, v, nd);\n\n                if (cur.extra > bestExtra) {\n                    bestExtra = cur.extra;\n                    bestDepth = cur.d;\n                }\n            }\n        }\n\n        State fin;\n        fin.d = bestDepth;\n        repair_depth(fin.d);\n        rebuild(fin);\n\n        // Final uphill polish\n        for (int pass = 0; pass < 8; pass++) {\n            bool changed = greedy_up_pass(fin, ordA);\n            if (!changed) break;\n        }\n\n        return fin.d;\n    }\n\n    vector<int> build_parent_from_depth(const vector<int>& d) const {\n        vector<int> p(N, -1);\n\n        for (int v = 0; v < N; v++) {\n            if (d[v] == 0) {\n                p[v] = -1;\n                continue;\n            }\n\n            int target = d[v] - 1;\n            int par = -1;\n\n            for (int u : g[v]) {\n                if (d[u] == target) {\n                    par = u;\n                    break;\n                }\n            }\n\n            // Fallback (should be rare)\n            if (par == -1) {\n                for (int u : g[v]) {\n                    if (d[u] < d[v]) {\n                        par = u;\n                        break;\n                    }\n                }\n            }\n\n            p[v] = par; // possibly -1 as last-resort root\n        }\n\n        return p;\n    }\n\n    void solve() {\n        read_input();\n        vector<int> d = optimize_depths();\n        vector<int> p = build_parent_from_depth(d);\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << p[i];\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}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Chain {\n    char dir;   // toward edge\n    char rev;   // reverse\n    int idx;    // row/col index\n    int safe;   // max safe depth\n};\n\nstruct Option {\n    int chain;\n    int req;\n};\n\nchar rev_dir(char d) {\n    if (d == 'L') return 'R';\n    if (d == 'R') return 'L';\n    if (d == 'U') return 'D';\n    return 'U';\n}\n\nvoid apply_one(vector<string>& g, char d, int p) {\n    int N = (int)g.size();\n    if (d == 'L') {\n        for (int j = 0; j + 1 < N; j++) g[p][j] = g[p][j + 1];\n        g[p][N - 1] = '.';\n    } else if (d == 'R') {\n        for (int j = N - 1; j >= 1; j--) g[p][j] = g[p][j - 1];\n        g[p][0] = '.';\n    } else if (d == 'U') {\n        for (int i = 0; i + 1 < N; i++) g[i][p] = g[i + 1][p];\n        g[N - 1][p] = '.';\n    } else { // 'D'\n        for (int i = N - 1; i >= 1; i--) g[i][p] = g[i - 1][p];\n        g[0][p] = '.';\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<string> board(N);\n    for (int i = 0; i < N; i++) cin >> board[i];\n\n    vector<pair<int,int>> oni_pos;\n    int initialFuku = 0;\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n        if (board[i][j] == 'x') oni_pos.push_back({i, j});\n        if (board[i][j] == 'o') initialFuku++;\n    }\n\n    int M = (int)oni_pos.size();   // usually 40\n    int Cn = 4 * N;                // 80 when N=20\n\n    // Safe depths from each side (based only on Fuku positions).\n    vector<int> upSafe(N, N), downSafe(N, N), leftSafe(N, N), rightSafe(N, N);\n\n    for (int j = 0; j < N; j++) {\n        for (int i = 0; i < N; i++) if (board[i][j] == 'o') { upSafe[j] = i; break; }\n        for (int i = N - 1; i >= 0; i--) if (board[i][j] == 'o') { downSafe[j] = N - 1 - i; break; }\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) if (board[i][j] == 'o') { leftSafe[i] = j; break; }\n        for (int j = N - 1; j >= 0; j--) if (board[i][j] == 'o') { rightSafe[i] = N - 1 - j; break; }\n    }\n\n    auto idUp = [&](int j) { return j; };\n    auto idDown = [&](int j) { return N + j; };\n    auto idLeft = [&](int i) { return 2 * N + i; };\n    auto idRight = [&](int i) { return 3 * N + i; };\n\n    vector<Chain> chains(Cn);\n    for (int j = 0; j < N; j++) {\n        chains[idUp(j)]   = {'U', 'D', j, upSafe[j]};\n        chains[idDown(j)] = {'D', 'U', j, downSafe[j]};\n    }\n    for (int i = 0; i < N; i++) {\n        chains[idLeft(i)]  = {'L', 'R', i, leftSafe[i]};\n        chains[idRight(i)] = {'R', 'L', i, rightSafe[i]};\n    }\n\n    // Options for each Oni\n    vector<vector<Option>> opts(M);\n    for (int m = 0; m < M; m++) {\n        auto [r, c] = oni_pos[m];\n\n        int reqU = r + 1;\n        int reqD = N - r;\n        int reqL = c + 1;\n        int reqR = N - c;\n\n        if (reqU <= upSafe[c])   opts[m].push_back({idUp(c), reqU});\n        if (reqD <= downSafe[c]) opts[m].push_back({idDown(c), reqD});\n        if (reqL <= leftSafe[r]) opts[m].push_back({idLeft(r), reqL});\n        if (reqR <= rightSafe[r])opts[m].push_back({idRight(r), reqR});\n\n        if (opts[m].empty()) {\n            // Should not happen due guarantee.\n            // But keep one dummy to avoid crash.\n            opts[m].push_back({idUp(c), min(reqU, N)});\n        }\n    }\n\n    // Coverage masks: cov[c][k] = Oni removed if chain c depth=k\n    vector<array<uint64_t, 21>> cov(Cn);\n    for (int c = 0; c < Cn; c++) for (int k = 0; k <= 20; k++) cov[c][k] = 0ULL;\n\n    for (int m = 0; m < M; m++) {\n        for (auto op : opts[m]) {\n            for (int k = op.req; k <= N; k++) cov[op.chain][k] |= (1ULL << m);\n        }\n    }\n\n    uint64_t allMask = (M == 64 ? ~0ULL : ((1ULL << M) - 1ULL));\n\n    auto covered_all = [&](const vector<int>& depth) -> bool {\n        uint64_t mask = 0ULL;\n        for (int c = 0; c < Cn; c++) mask |= cov[c][depth[c]];\n        return (mask & allMask) == allMask;\n    };\n\n    auto depth_cost = [&](const vector<int>& depth) -> int {\n        int s = 0;\n        for (int x : depth) s += 2 * x;\n        return s;\n    };\n\n    auto reduce_depth = [&](vector<int>& depth) {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int c = 0; c < Cn; c++) {\n                while (depth[c] > 0) {\n                    depth[c]--;\n                    if (covered_all(depth)) {\n                        changed = true;\n                    } else {\n                        depth[c]++;\n                        break;\n                    }\n                }\n            }\n        }\n    };\n\n    auto make_ops = [&](const vector<int>& depth) {\n        vector<pair<char,int>> ops;\n        ops.reserve(depth_cost(depth));\n        for (int c = 0; c < Cn; c++) {\n            int k = depth[c];\n            if (k <= 0) continue;\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].rev, chains[c].idx});\n        }\n        return ops;\n    };\n\n    auto evaluate = [&](const vector<pair<char,int>>& ops) -> pair<int,int> {\n        vector<string> g = board;\n        for (auto [d, p] : ops) apply_one(g, d, p);\n\n        int xRem = 0, oRem = 0;\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            if (g[i][j] == 'x') xRem++;\n            else if (g[i][j] == 'o') oRem++;\n        }\n        int yRemoved = initialFuku - oRem;\n        return {xRem, yRemoved};\n    };\n\n    auto good = [&](const vector<pair<char,int>>& ops) -> bool {\n        if ((int)ops.size() > 4 * N * N) return false;\n        auto [x, y] = evaluate(ops);\n        return x == 0 && y == 0;\n    };\n\n    // Baseline: each Oni chooses min req option.\n    vector<int> bestDepth(Cn, 0);\n    for (int m = 0; m < M; m++) {\n        int bi = 0;\n        for (int i = 1; i < (int)opts[m].size(); i++) {\n            if (opts[m][i].req < opts[m][bi].req) bi = i;\n        }\n        auto op = opts[m][bi];\n        bestDepth[op.chain] = max(bestDepth[op.chain], op.req);\n    }\n    reduce_depth(bestDepth);\n    int bestCost = depth_cost(bestDepth);\n\n    // Multi-start randomized search + local improvement\n    mt19937 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n    auto st = chrono::steady_clock::now();\n    const double TL = 1.45;\n\n    vector<int> order(M), ids(M);\n    iota(ids.begin(), ids.end(), 0);\n\n    while (chrono::duration<double>(chrono::steady_clock::now() - st).count() < TL) {\n        array<array<uint8_t, 21>, 80> cnt{};\n        array<uint8_t, 80> maxd{};\n        int curCost = 0;\n        vector<int> assign(M, 0);\n\n        auto add = [&](int c, int req) {\n            int old = maxd[c];\n            cnt[c][req]++;\n            if (req > old) {\n                maxd[c] = (uint8_t)req;\n                curCost += 2 * (req - old);\n            }\n        };\n        auto rem = [&](int c, int req) {\n            int old = maxd[c];\n            cnt[c][req]--;\n            if (req == old && cnt[c][req] == 0) {\n                int nw = old - 1;\n                while (nw > 0 && cnt[c][nw] == 0) nw--;\n                maxd[c] = (uint8_t)nw;\n                curCost += 2 * (nw - old);\n            }\n        };\n\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), rng);\n        stable_sort(order.begin(), order.end(),\n                    [&](int a, int b) { return opts[a].size() < opts[b].size(); });\n\n        // Randomized greedy init\n        for (int id : order) {\n            int choose = 0;\n            if ((int)(rng() % 100) < 10) {\n                choose = (int)(rng() % opts[id].size());\n            } else {\n                int bestDelta = 1e9;\n                vector<int> cand;\n                for (int oi = 0; oi < (int)opts[id].size(); oi++) {\n                    auto op = opts[id][oi];\n                    int delta = max(0, op.req - (int)maxd[op.chain]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        cand.clear();\n                        cand.push_back(oi);\n                    } else if (delta == bestDelta) {\n                        cand.push_back(oi);\n                    }\n                }\n                choose = cand[(int)(rng() % cand.size())];\n            }\n\n            assign[id] = choose;\n            auto op = opts[id][choose];\n            add(op.chain, op.req);\n        }\n\n        // 1-opt local search\n        bool improved = true;\n        int pass = 0;\n        while (improved && pass < 25) {\n            improved = false;\n            pass++;\n            shuffle(ids.begin(), ids.end(), rng);\n\n            for (int id : ids) {\n                int cur = assign[id];\n                auto oc = opts[id][cur];\n\n                rem(oc.chain, oc.req);\n\n                int bestOpt = cur;\n\n                // evaluate current option first\n                add(oc.chain, oc.req);\n                int bestLocal = curCost;\n                rem(oc.chain, oc.req);\n\n                for (int oi = 0; oi < (int)opts[id].size(); oi++) {\n                    if (oi == cur) continue;\n                    auto op = opts[id][oi];\n                    add(op.chain, op.req);\n                    if (curCost < bestLocal) {\n                        bestLocal = curCost;\n                        bestOpt = oi;\n                    }\n                    rem(op.chain, op.req);\n                }\n\n                auto ob = opts[id][bestOpt];\n                add(ob.chain, ob.req);\n                if (bestOpt != cur) {\n                    assign[id] = bestOpt;\n                    improved = true;\n                }\n            }\n        }\n\n        if (curCost <= bestCost + 100) {\n            vector<int> depth(Cn, 0);\n            for (int c = 0; c < Cn; c++) depth[c] = maxd[c];\n            reduce_depth(depth);\n            int cst = depth_cost(depth);\n            if (cst < bestCost) {\n                bestCost = cst;\n                bestDepth.swap(depth);\n            }\n        }\n    }\n\n    vector<pair<char,int>> ans = make_ops(bestDepth);\n\n    // Safety check; fallback if needed.\n    if (!good(ans)) {\n        // Fallback 1: dynamic guaranteed macro by current Oni\n        vector<string> g = board;\n        vector<pair<char,int>> fb;\n\n        auto doop = [&](char d, int p) {\n            fb.push_back({d, p});\n            apply_one(g, d, p);\n        };\n\n        while (true) {\n            int r = -1, c = -1;\n            for (int i = 0; i < N && r == -1; i++) {\n                for (int j = 0; j < N; j++) {\n                    if (g[i][j] == 'x') {\n                        r = i; c = j; break;\n                    }\n                }\n            }\n            if (r == -1) break;\n\n            vector<tuple<int,char,int>> cand;\n            if (r + 1 <= upSafe[c])    cand.push_back({r + 1, 'U', c});\n            if (N - r <= downSafe[c])  cand.push_back({N - r, 'D', c});\n            if (c + 1 <= leftSafe[r])  cand.push_back({c + 1, 'L', r});\n            if (N - c <= rightSafe[r]) cand.push_back({N - c, 'R', r});\n\n            if (cand.empty()) break;\n            auto [k, d, p] = *min_element(cand.begin(), cand.end());\n            char rv = rev_dir(d);\n\n            for (int t = 0; t < k; t++) doop(d, p);\n            for (int t = 0; t < k; t++) doop(rv, p);\n\n            if ((int)fb.size() > 4 * N * N) break;\n        }\n\n        if (good(fb)) ans.swap(fb);\n    }\n\n    if (!good(ans)) {\n        // Fallback 2: guaranteed static per-Oni (safe upper bound <= 1600)\n        ans.clear();\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            const Chain &ch = chains[op.chain];\n            for (int t = 0; t < op.req; t++) ans.push_back({ch.dir, ch.idx});\n            for (int t = 0; t < op.req; t++) ans.push_back({ch.rev, ch.idx});\n        }\n    }\n\n    for (auto [d, p] : ans) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solution {\n    array<int, MAXN> a{}, b{}, cnt{}, useB{}, order{};\n    long long err = (1LL << 60);\n};\n\nstatic inline long long simulate(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N, int L,\n    const array<int, MAXN>& T,\n    array<int, MAXN>& cnt,\n    array<int, MAXN>& useB\n) {\n    for (int i = 0; i < N; i++) {\n        cnt[i] = 0;\n        useB[i] = 0;\n    }\n    int cur = 0;\n    cnt[0] = 1;\n\n    for (int w = 1; w < L; w++) {\n        int src = cur;\n        int c = cnt[src];\n        if (c & 1) {\n            cur = a[src];\n        } else {\n            cur = b[src];\n            useB[src]++;\n        }\n        cnt[cur]++;\n    }\n\n    long long e = 0;\n    for (int i = 0; i < N; i++) e += llabs((long long)cnt[i] - T[i]);\n    return e;\n}\n\nstatic inline void shuffle_order(array<int, MAXN>& ord, int N, RNG& rng) {\n    for (int i = N - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nstatic inline int sample_weighted(const array<uint64_t, MAXN>& w, int N, RNG& rng) {\n    uint64_t sum = 0;\n    for (int i = 0; i < N; i++) sum += w[i];\n    if (sum == 0) return rng.nextInt(N);\n    uint64_t r = rng.nextU64() % sum;\n    uint64_t acc = 0;\n    for (int i = 0; i < N; i++) {\n        acc += w[i];\n        if (r < acc) return i;\n    }\n    return N - 1;\n}\n\nstatic inline void build_candidate_from_order(\n    const array<int, MAXN>& order,\n    int N,\n    const array<int, MAXN>& T,\n    const array<int, MAXN>& srcDesc,\n    RNG& rng,\n    array<int, MAXN>& a,\n    array<int, MAXN>& b\n) {\n    array<int, MAXN> pred{};\n    for (int k = 0; k < N; k++) {\n        int u = order[k];\n        int v = order[(k + 1) % N];\n        a[u] = v;\n        pred[v] = u;\n    }\n\n    // Linearized target:\n    // 2*T[i] ~ T[pred(i)] + sum_{j: b[j]=i} T[j]\n    array<long long, MAXN> rem{};\n    for (int i = 0; i < N; i++) {\n        rem[i] = 2LL * T[i] - T[pred[i]];\n    }\n\n    // Greedy assignment for b\n    for (int idx = 0; idx < N; idx++) {\n        int j = srcDesc[idx];\n        long long w = T[j];\n        int best = 0;\n        long long bestVal = llabs(rem[0] - w);\n        for (int i = 1; i < N; i++) {\n            long long v = llabs(rem[i] - w);\n            if (v < bestVal) {\n                bestVal = v;\n                best = i;\n            }\n        }\n        b[j] = best;\n        rem[best] -= w;\n    }\n\n    // Local improvements in linearized model\n    array<int, MAXN> srcOrder = srcDesc;\n    for (int pass = 0; pass < 5; pass++) {\n        bool improved = false;\n        shuffle_order(srcOrder, N, rng);\n        for (int t = 0; t < N; t++) {\n            int j = srcOrder[t];\n            long long w = T[j];\n            if (w == 0) continue;\n\n            int cur = b[j];\n            long long curRem = rem[cur];\n            long long absCur = llabs(curRem);\n\n            int best = cur;\n            long long bestDelta = 0;\n\n            for (int i = 0; i < N; i++) {\n                if (i == cur) continue;\n                long long delta =\n                    llabs(curRem + w) + llabs(rem[i] - w) - absCur - llabs(rem[i]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = i;\n                }\n            }\n\n            if (best != cur) {\n                rem[cur] += w;\n                rem[best] -= w;\n                b[j] = best;\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    array<int, MAXN> T{};\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    for (int i = 0; i < N; i++) {\n        seed ^= (uint64_t)(T[i] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));\n    }\n    RNG rng(seed);\n\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    const double TIME_LIMIT = 1.85;\n    const double INIT_LIMIT = 0.50;\n\n    // Prepare base orders\n    array<int, MAXN> ordNatural{}, ordAsc{}, ordDesc{}, ordMountain{}, ordMountainRev{};\n    for (int i = 0; i < N; i++) ordNatural[i] = i;\n\n    vector<int> idx(N);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return T[a] < T[b];\n        return a < b;\n    });\n    for (int i = 0; i < N; i++) ordAsc[i] = idx[i];\n    for (int i = 0; i < N; i++) ordDesc[i] = idx[N - 1 - i];\n\n    int mid = (N - 1) / 2;\n    int p = 0;\n    for (int i = 0; i <= mid; i++) ordMountain[p++] = ordAsc[i];\n    for (int i = N - 1; i > mid; i--) ordMountain[p++] = ordAsc[i];\n    for (int i = 0; i < N; i++) ordMountainRev[i] = ordMountain[N - 1 - i];\n\n    array<int, MAXN> srcDesc = ordDesc; // sorted by descending T\n\n    Solution best;\n    array<int, MAXN> candA{}, candB{}, candCnt{}, candUseB{};\n\n    auto evaluate_order = [&](const array<int, MAXN>& ord) {\n        build_candidate_from_order(ord, N, T, srcDesc, rng, candA, candB);\n        long long e = simulate(candA, candB, N, L, T, candCnt, candUseB);\n        if (e < best.err) {\n            best.err = e;\n            best.a = candA;\n            best.b = candB;\n            best.cnt = candCnt;\n            best.useB = candUseB;\n            best.order = ord;\n        }\n    };\n\n    // Deterministic seeds\n    evaluate_order(ordNatural);\n    evaluate_order(ordAsc);\n    evaluate_order(ordDesc);\n    evaluate_order(ordMountain);\n    evaluate_order(ordMountainRev);\n\n    // Randomized order search\n    while (elapsed() < INIT_LIMIT) {\n        array<int, MAXN> ord{};\n        int mode = rng.nextInt(7);\n        if (mode == 0) ord = ordAsc;\n        else if (mode == 1) ord = ordDesc;\n        else if (mode == 2) ord = ordMountain;\n        else if (mode == 3) ord = ordNatural;\n        else if (mode == 4) ord = ordMountainRev;\n        else if (mode == 5) ord = best.order;\n        else {\n            ord = ordAsc;\n            shuffle_order(ord, N, rng);\n        }\n\n        if (mode == 3 && rng.nextDouble() < 0.45) {\n            shuffle_order(ord, N, rng);\n        } else {\n            int swaps = 1 + rng.nextInt(20);\n            for (int s = 0; s < swaps; s++) {\n                int i = rng.nextInt(N);\n                int j = rng.nextInt(N);\n                swap(ord[i], ord[j]);\n            }\n        }\n\n        if (rng.nextDouble() < 0.20) {\n            int l = rng.nextInt(N), r = rng.nextInt(N);\n            if (l > r) swap(l, r);\n            reverse(ord.begin() + l, ord.begin() + r + 1);\n        }\n\n        evaluate_order(ord);\n    }\n\n    // Local search / SA on b (a fixed)\n    Solution cur = best;\n    array<int, MAXN> tmpCnt{}, tmpUseB{};\n    array<uint64_t, MAXN> w{};\n    double saStart = elapsed();\n    long long iter = 0;\n\n    while (elapsed() < TIME_LIMIT) {\n        iter++;\n        double moveType = rng.nextDouble();\n\n        bool changed = false;\n        int j = -1, oldDst = -1, newDst = -1;\n        int j1 = -1, j2 = -1;\n\n        if (moveType < 0.75) {\n            // Guided single-edge move\n            for (int x = 0; x < N; x++) {\n                int dst = cur.b[x];\n                int over = cur.cnt[dst] - T[dst];\n                if (over < 0) over = 0;\n                w[x] = (uint64_t)(cur.useB[x] + 1) * (uint64_t)(over + 1);\n            }\n            j = sample_weighted(w, N, rng);\n            oldDst = cur.b[j];\n\n            int u = cur.useB[j];\n            if (u <= 0) u = 1;\n\n            long long bestPred = (1LL << 60);\n            newDst = oldDst;\n\n            long long baseOld = llabs((long long)cur.cnt[oldDst] - T[oldDst]);\n\n            for (int q = 0; q < N; q++) {\n                if (q == oldDst) continue;\n                long long pred =\n                    llabs((long long)cur.cnt[oldDst] - u - T[oldDst]) +\n                    llabs((long long)cur.cnt[q] + u - T[q]) -\n                    baseOld -\n                    llabs((long long)cur.cnt[q] - T[q]);\n                if (pred < bestPred) {\n                    bestPred = pred;\n                    newDst = q;\n                }\n            }\n\n            if (newDst == oldDst) continue;\n            if (bestPred >= 0 && rng.nextDouble() < 0.65) continue;\n\n            cur.b[j] = newDst;\n            changed = true;\n        } else if (moveType < 0.90) {\n            // Random single-edge move\n            j = rng.nextInt(N);\n            oldDst = cur.b[j];\n\n            for (int i = 0; i < N; i++) {\n                int under = T[i] - cur.cnt[i];\n                if (under < 0) under = 0;\n                w[i] = (uint64_t)(under + 1);\n            }\n            newDst = sample_weighted(w, N, rng);\n            if (newDst == oldDst) continue;\n\n            cur.b[j] = newDst;\n            changed = true;\n        } else {\n            // Swap two b edges\n            j1 = rng.nextInt(N);\n            j2 = rng.nextInt(N - 1);\n            if (j2 >= j1) j2++;\n            if (cur.b[j1] == cur.b[j2]) continue;\n\n            swap(cur.b[j1], cur.b[j2]);\n            changed = true;\n        }\n\n        if (!changed) continue;\n\n        long long newErr = simulate(cur.a, cur.b, N, L, T, tmpCnt, tmpUseB);\n\n        double now = elapsed();\n        double prog = (now - saStart) / max(1e-9, TIME_LIMIT - saStart);\n        prog = max(0.0, min(1.0, prog));\n        double temp = 2500.0 * (1.0 - prog) + 5.0;\n\n        bool accept = false;\n        if (newErr <= cur.err) {\n            accept = true;\n        } else {\n            double prob = exp((double)(cur.err - newErr) / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.err = newErr;\n            cur.cnt = tmpCnt;\n            cur.useB = tmpUseB;\n            if (cur.err < best.err) best = cur;\n        } else {\n            if (moveType < 0.90) {\n                cur.b[j] = oldDst;\n            } else {\n                swap(cur.b[j1], cur.b[j2]);\n            }\n        }\n\n        if ((iter & 255LL) == 0) {\n            if (cur.err > best.err + 2000) cur = best;\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\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n\n    vector<int> cx2, cy2;   // twice center coordinates\n    vector<int> cx, cy;     // integer center\n    vector<uint32_t> zkey;  // morton key\n    vector<vector<int>> dmat; // proxy distances between centers (scaled by 2)\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffffu;\n        x = (x | (x << 8)) & 0x00FF00FFu;\n        x = (x | (x << 4)) & 0x0F0F0F0Fu;\n        x = (x | (x << 2)) & 0x33333333u;\n        x = (x | (x << 1)) & 0x55555555u;\n        return x;\n    }\n\n    static uint32_t morton(uint32_t x, uint32_t y) {\n        return part1by1(x) | (part1by1(y) << 1);\n    }\n\n    void input() {\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx2.resize(N); cy2.resize(N);\n        cx.resize(N); cy.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx2[i] = lx[i] + rx[i];\n            cy2[i] = ly[i] + ry[i];\n            cx[i] = cx2[i] / 2;\n            cy[i] = cy2[i] / 2;\n        }\n    }\n\n    void preprocess() {\n        zkey.resize(N);\n        for (int i = 0; i < N; i++) {\n            zkey[i] = morton((uint32_t)cx[i], (uint32_t)cy[i]);\n        }\n\n        dmat.assign(N, vector<int>(N, 0));\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                long long dx = (long long)cx2[i] - cx2[j];\n                long long dy = (long long)cy2[i] - cy2[j];\n                long long sq = dx * dx + dy * dy;\n                int d = (int)std::sqrt((double)sq); // distance on scaled coords\n                dmat[i][j] = dmat[j][i] = d;\n            }\n        }\n    }\n\n    long long prim_cost(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return 0;\n        const int INF = 1e9;\n\n        vector<int> mn(n, INF);\n        vector<char> used(n, 0);\n        mn[0] = 0;\n\n        long long cost = 0;\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            cost += mn[v];\n\n            int idv = nodes[v];\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = dmat[idv][nodes[u]];\n                if (w < mn[u]) mn[u] = w;\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int, int>> prim_tree(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        vector<pair<int, int>> edges;\n        if (n <= 1) return edges;\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            edges.push_back(p);\n            return edges;\n        }\n\n        const int INF = 1e9;\n        vector<int> mn(n, INF), parent(n, -1);\n        vector<char> used(n, 0);\n        mn[0] = 0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int idv = nodes[v];\n\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = dmat[idv][nodes[u]];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    parent[u] = v;\n                }\n            }\n        }\n\n        edges.reserve(n - 1);\n        for (int i = 1; i < n; i++) {\n            int a = nodes[i], b = nodes[parent[i]];\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        return edges;\n    }\n\n    void rec_assign(\n        vector<int> cities,\n        vector<int> gids,\n        vector<vector<int>>& out,\n        mt19937& rng,\n        bool randomized\n    ) {\n        if ((int)gids.size() == 1) {\n            out[gids[0]] = std::move(cities);\n            return;\n        }\n\n        int S = (int)cities.size();\n\n        // Axis by spread (with random flip sometimes)\n        int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;\n        for (int c : cities) {\n            minx = min(minx, cx2[c]);\n            maxx = max(maxx, cx2[c]);\n            miny = min(miny, cy2[c]);\n            maxy = max(maxy, cy2[c]);\n        }\n        int axis = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 25) axis ^= 1;\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            if (axis == 0) {\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                return a < b;\n            } else {\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                return a < b;\n            }\n        });\n\n        vector<int> pg = gids;\n        if (randomized) shuffle(pg.begin(), pg.end(), rng);\n\n        // subset-sum over group sizes to split near half\n        vector<char> dp(S + 1, 0);\n        vector<int> prv(S + 1, -1), item(S + 1, -1);\n        dp[0] = 1;\n        for (int j = 0; j < (int)pg.size(); j++) {\n            int w = G[pg[j]];\n            for (int s = S - w; s >= 0; s--) {\n                if (dp[s] && !dp[s + w]) {\n                    dp[s + w] = 1;\n                    prv[s + w] = s;\n                    item[s + w] = j;\n                }\n            }\n        }\n\n        int target = S / 2;\n        if (randomized) {\n            int r = max(1, S / 5);\n            target += uniform_int_distribution<int>(-r, r)(rng);\n            target = max(1, min(S - 1, target));\n        }\n\n        int bestDiff = INT_MAX;\n        vector<int> candS;\n        for (int s = 1; s <= S - 1; s++) {\n            if (!dp[s]) continue;\n            int diff = abs(s - target);\n            if (diff < bestDiff) {\n                bestDiff = diff;\n                candS.clear();\n                candS.push_back(s);\n            } else if (diff == bestDiff) {\n                candS.push_back(s);\n            }\n        }\n\n        int splitSize = -1;\n        if (!candS.empty()) {\n            if (randomized) {\n                splitSize = candS[uniform_int_distribution<int>(0, (int)candS.size() - 1)(rng)];\n            } else {\n                splitSize = candS[0];\n            }\n        }\n        if (splitSize <= 0 || splitSize >= S) {\n            splitSize = G[pg[0]];\n        }\n\n        vector<char> take(pg.size(), 0);\n        bool ok = true;\n        int cur = splitSize;\n        while (cur > 0) {\n            int j = item[cur];\n            if (j < 0 || take[j]) {\n                ok = false;\n                break;\n            }\n            take[j] = 1;\n            cur = prv[cur];\n        }\n\n        vector<int> gA, gB;\n        int sumA = 0;\n        if (ok) {\n            for (int j = 0; j < (int)pg.size(); j++) {\n                if (take[j]) {\n                    gA.push_back(pg[j]);\n                    sumA += G[pg[j]];\n                } else {\n                    gB.push_back(pg[j]);\n                }\n            }\n        }\n\n        // fallback if reconstruction fails\n        if (!ok || gA.empty() || gB.empty() || sumA != splitSize) {\n            gA.clear(); gB.clear();\n            gA.push_back(pg[0]);\n            splitSize = G[pg[0]];\n            for (int j = 1; j < (int)pg.size(); j++) gB.push_back(pg[j]);\n        }\n\n        vector<int> cA(cities.begin(), cities.begin() + splitSize);\n        vector<int> cB(cities.begin() + splitSize, cities.end());\n\n        rec_assign(std::move(cA), std::move(gA), out, rng, randomized);\n        rec_assign(std::move(cB), std::move(gB), out, rng, randomized);\n    }\n\n    vector<vector<int>> build_recursive_trial(mt19937& rng, bool randomized) {\n        vector<vector<int>> out(M);\n        vector<int> cities(N), gids(M);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n        rec_assign(std::move(cities), std::move(gids), out, rng, randomized);\n        return out;\n    }\n\n    vector<vector<int>> build_order_trial(\n        const vector<int>& city_order,\n        const vector<int>& group_order\n    ) const {\n        vector<vector<int>> out(M);\n        int pos = 0;\n        for (int gid : group_order) {\n            int sz = G[gid];\n            out[gid].assign(city_order.begin() + pos, city_order.begin() + pos + sz);\n            pos += sz;\n        }\n        return out;\n    }\n\n    bool validate_groups(const vector<vector<int>>& groups) const {\n        if ((int)groups.size() != M) return false;\n        vector<int> cnt(N, 0);\n        for (int i = 0; i < M; i++) {\n            if ((int)groups[i].size() != G[i]) return false;\n            for (int c : groups[i]) {\n                if (c < 0 || c >= N) return false;\n                cnt[c]++;\n            }\n        }\n        for (int i = 0; i < N; i++) if (cnt[i] != 1) return false;\n        return true;\n    }\n\n    long long eval_groups(const vector<vector<int>>& groups) const {\n        long long total = 0;\n        for (int i = 0; i < M; i++) total += prim_cost(groups[i]);\n        return total;\n    }\n\n    vector<int> make_city_order(function<bool(int,int)> comp) const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), comp);\n        return ord;\n    }\n\n    vector<vector<int>> make_grouping() {\n        vector<vector<int>> best;\n        long long bestScore = (1LL << 62);\n\n        auto consider = [&](vector<vector<int>> cand) {\n            if (!validate_groups(cand)) return;\n            long long sc = eval_groups(cand);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = std::move(cand);\n            }\n        };\n\n        vector<int> group_orig(M), group_desc(M), group_asc(M);\n        iota(group_orig.begin(), group_orig.end(), 0);\n        group_desc = group_orig;\n        group_asc = group_orig;\n\n        sort(group_desc.begin(), group_desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        sort(group_asc.begin(), group_asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        auto ord_morton = make_city_order([&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n        auto ord_x = make_city_order([&](int a, int b) {\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        auto ord_y = make_city_order([&](int a, int b) {\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ord_diag = make_city_order([&](int a, int b) {\n            int ka = cx2[a] + cy2[a];\n            int kb = cx2[b] + cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ord_anti = make_city_order([&](int a, int b) {\n            int ka = cx2[a] - cy2[a];\n            int kb = cx2[b] - cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n\n        // order-based candidates\n        consider(build_order_trial(ord_morton, group_orig));\n        consider(build_order_trial(ord_morton, group_desc));\n        consider(build_order_trial(ord_morton, group_asc));\n        consider(build_order_trial(ord_x, group_orig));\n        consider(build_order_trial(ord_y, group_orig));\n        consider(build_order_trial(ord_diag, group_orig));\n        consider(build_order_trial(ord_anti, group_orig));\n\n        // recursive candidates\n        uint64_t seed = 123456789ull;\n        for (int i = 0; i < N; i++) {\n            seed ^= (uint64_t)(cx2[i] + 10007) * 1000003ull + (uint64_t)(cy2[i] + 10009);\n        }\n        mt19937 rng((uint32_t)seed);\n\n        consider(build_recursive_trial(rng, false));\n        for (int t = 0; t < 6; t++) {\n            consider(build_recursive_trial(rng, true));\n        }\n\n        if (best.empty()) {\n            best = build_order_trial(ord_morton, group_orig);\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        cout << \"? \" << subset.size();\n        for (int c : subset) cout << \" \" << c;\n        cout << \"\\n\";\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)subset.size() - 1);\n        for (int i = 0; i < (int)subset.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            ret.emplace_back(a, b);\n        }\n        return ret;\n    }\n\n    int needed_queries(int g) const {\n        if (g <= 2) return 0;\n        return (g - 2) / (L - 1) + 1; // = ceil((g-1)/(L-1))\n    }\n\n    vector<pair<int,int>> build_edges_for_group(const vector<int>& nodes, int& q_used) {\n        int g = (int)nodes.size();\n        if (g <= 1) return {};\n        if (g == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            return {p};\n        }\n\n        int need = needed_queries(g);\n        if (q_used + need > Q) {\n            return prim_tree(nodes); // defensive fallback\n        }\n\n        vector<int> ord = nodes;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<pair<int,int>> edges;\n        edges.reserve(g - 1);\n\n        if (g <= L) {\n            auto ret = do_query(ord);\n            q_used++;\n            edges.insert(edges.end(), ret.begin(), ret.end());\n            return edges;\n        }\n\n        vector<int> subset;\n        subset.reserve(L);\n\n        // initial query with L nodes\n        for (int i = 0; i < L; i++) subset.push_back(ord[i]);\n        {\n            auto ret = do_query(subset);\n            q_used++;\n            edges.insert(edges.end(), ret.begin(), ret.end());\n        }\n\n        vector<int> connected = subset;\n        int pos = L;\n\n        // add batches with one anchor + up to (L-1) new nodes\n        while (pos < g) {\n            int t = min(L - 1, g - pos);\n            int ref = ord[pos];\n\n            int anchor = connected[0];\n            int bestd = dmat[anchor][ref];\n            for (int c : connected) {\n                int d = dmat[c][ref];\n                if (d < bestd) {\n                    bestd = d;\n                    anchor = c;\n                }\n            }\n\n            subset.clear();\n            subset.push_back(anchor);\n            for (int i = 0; i < t; i++) subset.push_back(ord[pos + i]);\n\n            auto ret = do_query(subset);\n            q_used++;\n            edges.insert(edges.end(), ret.begin(), ret.end());\n\n            for (int i = 0; i < t; i++) connected.push_back(ord[pos + i]);\n            pos += t;\n        }\n\n        if ((int)edges.size() != g - 1) {\n            return prim_tree(nodes);\n        }\n        return edges;\n    }\n\n    void solve() {\n        input();\n        preprocess();\n\n        auto groups = make_grouping();\n        if (!validate_groups(groups)) {\n            vector<int> gid(M);\n            iota(gid.begin(), gid.end(), 0);\n            auto ord_morton = make_city_order([&](int a, int b) {\n                if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                return a < b;\n            });\n            groups = build_order_trial(ord_morton, gid);\n        }\n\n        vector<vector<pair<int,int>>> edges(M);\n        int q_used = 0;\n\n        // query larger groups first (just in case of defensive fallback)\n        vector<int> gid_order(M);\n        iota(gid_order.begin(), gid_order.end(), 0);\n        sort(gid_order.begin(), gid_order.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        for (int gid : gid_order) {\n            edges[gid] = build_edges_for_group(groups[gid], q_used);\n        }\n\n        // output final answer\n        cout << \"!\" << \"\\n\";\n        for (int k = 0; k < M; k++) {\n            if ((int)edges[k].size() != (int)groups[k].size() - 1) {\n                edges[k] = prim_tree(groups[k]);\n            }\n\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            for (auto [a, b] : edges[k]) {\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int r, c; };\nstruct Action { char a, d; };\n\nclass Solver {\n    int N, M;\n    int LIMIT;\n    int n2;\n    static constexpr int MAXN = 20;\n    static constexpr int INF = 1e9;\n    static constexpr int BEAM_WIDTH = 200;\n\n    vector<Point> pts;      // pts[0]=start, pts[1..]=targets\n    vector<int> pid;        // cell id for each pts index\n\n    // U, D, L, R\n    array<int,4> dr{{-1, 1, 0, 0}};\n    array<int,4> dc{{0, 0, -1, 1}};\n    array<char,4> dch{{'U','D','L','R'}};\n    array<int,4> opp{{1,0,3,2}};\n\n    vector<int> cellR, cellC;\n    vector<array<int,4>> moveTo;\n    vector<uint32_t> bitCol;              // 1<<c for each cell id\n    array<uint32_t, MAXN> lowMask{};      // bits < i\n    array<uint32_t, MAXN> highMask{};     // bits >= i+1\n\n    void initPrecompute() {\n        n2 = N * N;\n        LIMIT = 2 * N * M;\n\n        cellR.resize(n2);\n        cellC.resize(n2);\n        moveTo.assign(n2, array<int,4>{-1,-1,-1,-1});\n        bitCol.resize(n2);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                cellR[id] = r;\n                cellC[id] = c;\n                bitCol[id] = (1u << c);\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + dr[d], nc = c + dc[d];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                        moveTo[id][d] = nr * N + nc;\n                    }\n                }\n            }\n        }\n\n        for (int i = 0; i < MAXN; i++) {\n            lowMask[i] = (i == 0 ? 0u : ((1u << i) - 1u));\n            highMask[i] = ~((1u << (i + 1)) - 1u);\n        }\n\n        pid.resize(M);\n        for (int i = 0; i < M; i++) {\n            pid[i] = pts[i].r * N + pts[i].c;\n        }\n    }\n\n    inline bool blockedId(int id, const array<uint32_t,MAXN>& row) const {\n        return (row[cellR[id]] & bitCol[id]) != 0u;\n    }\n\n    void buildMasks(uint64_t mask, array<uint32_t,MAXN>& row, array<uint32_t,MAXN>& col) const {\n        row.fill(0u);\n        col.fill(0u);\n        while (mask) {\n            int b = __builtin_ctzll(mask);\n            mask &= (mask - 1);\n            if (b >= M) continue;\n            int r = pts[b].r, c = pts[b].c;\n            row[r] |= (1u << c);\n            col[c] |= (1u << r);\n        }\n    }\n\n    int bfsDistRC(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col, int s, int g) const {\n        if (s == g) return 0;\n        int dist[400];\n        for (int i = 0; i < n2; i++) dist[i] = -1;\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            // Move\n            for (int d = 0; d < 4; d++) {\n                int v = moveTo[u][d];\n                if (v == -1) continue;\n                if (blockedId(v, row)) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du;\n                if (v == g) return du;\n                q[tail++] = v;\n            }\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n        }\n        return INF;\n    }\n\n    bool bfsPathRC(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                   int s, int g, vector<Action>& out) const {\n        out.clear();\n        if (s == g) return true;\n\n        int dist[400], parent[400];\n        uint8_t pdir[400];\n        char pact[400];\n        for (int i = 0; i < n2; i++) {\n            dist[i] = -1;\n            parent[i] = -1;\n        }\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        parent[s] = s;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            // Move\n            for (int d = 0; d < 4; d++) {\n                int v = moveTo[u][d];\n                if (v == -1) continue;\n                if (blockedId(v, row)) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du;\n                parent[v] = u;\n                pact[v] = 'M';\n                pdir[v] = (uint8_t)d;\n                q[tail++] = v;\n            }\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        parent[v] = u;\n                        pact[v] = 'S';\n                        pdir[v] = 0;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        parent[v] = u;\n                        pact[v] = 'S';\n                        pdir[v] = 1;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        parent[v] = u;\n                        pact[v] = 'S';\n                        pdir[v] = 2;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        parent[v] = u;\n                        pact[v] = 'S';\n                        pdir[v] = 3;\n                        q[tail++] = v;\n                    }\n                }\n            }\n        }\n\n        if (dist[g] == -1) return false;\n\n        vector<Action> rev;\n        int cur = g;\n        while (cur != s) {\n            rev.push_back(Action{pact[cur], dch[pdir[cur]]});\n            cur = parent[cur];\n            if (cur < 0) return false;\n        }\n        reverse(rev.begin(), rev.end());\n        out.swap(rev);\n        return true;\n    }\n\n    bool bfsPathMask(uint64_t mask, int s, int g, vector<Action>& out) const {\n        array<uint32_t,MAXN> row, col;\n        buildMasks(mask, row, col);\n        return bfsPathRC(row, col, s, g, out);\n    }\n\n    bool validate(const vector<Action>& acts) const {\n        if ((int)acts.size() > LIMIT) return false;\n        vector<vector<uint8_t>> blk(N, vector<uint8_t>(N, 0));\n        int r = pts[0].r, c = pts[0].c;\n        int nxt = 1;\n\n        auto dirId = [&](char ch)->int{\n            if (ch=='U') return 0;\n            if (ch=='D') return 1;\n            if (ch=='L') return 2;\n            if (ch=='R') return 3;\n            return -1;\n        };\n\n        for (const auto& ac : acts) {\n            int d = dirId(ac.d);\n            if (d < 0) return false;\n\n            if (ac.a == 'M') {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                if (blk[nr][nc]) return false;\n                r = nr; c = nc;\n            } else if (ac.a == 'S') {\n                int nr = r, nc = c;\n                while (true) {\n                    int tr = nr + dr[d], tc = nc + dc[d];\n                    if (!(0 <= tr && tr < N && 0 <= tc && tc < N)) break;\n                    if (blk[tr][tc]) break;\n                    nr = tr; nc = tc;\n                }\n                r = nr; c = nc;\n            } else if (ac.a == 'A') {\n                int nr = r + dr[d], nc = c + dc[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                blk[nr][nc] ^= 1;\n            } else {\n                return false;\n            }\n\n            if (nxt < M && r == pts[nxt].r && c == pts[nxt].c) nxt++;\n        }\n        return nxt == M;\n    }\n\n    vector<Action> fallbackManhattan() const {\n        vector<Action> ans;\n        int r = pts[0].r, c = pts[0].c;\n        for (int k = 1; k < M; k++) {\n            int tr = pts[k].r, tc = pts[k].c;\n            while (r < tr) { ans.push_back({'M','D'}); r++; }\n            while (r > tr) { ans.push_back({'M','U'}); r--; }\n            while (c < tc) { ans.push_back({'M','R'}); c++; }\n            while (c > tc) { ans.push_back({'M','L'}); c--; }\n        }\n        return ans;\n    }\n\n    vector<Action> fallbackNoBlock() const {\n        vector<Action> ans;\n        array<uint32_t,MAXN> row, col;\n        row.fill(0u);\n        col.fill(0u);\n\n        int cur = pid[0];\n        for (int k = 0; k < M - 1; k++) {\n            vector<Action> path;\n            if (!bfsPathRC(row, col, cur, pid[k+1], path)) {\n                return fallbackManhattan();\n            }\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = pid[k+1];\n        }\n        return ans;\n    }\n\n    vector<Action> runBeam() {\n        struct BNode {\n            uint64_t mask;\n            int cost;\n            int parent;\n            uint8_t op;   // 0: direct, 1: M dir + A opposite, then go\n            uint8_t dir;  // valid if op=1\n        };\n        struct Cand {\n            uint64_t mask;\n            int cost;\n            int parent;\n            uint8_t op;\n            uint8_t dir;\n        };\n\n        vector<vector<BNode>> layers(M);\n        layers[0].push_back(BNode{0ull, 0, -1, 0, 0});\n\n        for (int k = 0; k < M - 1; k++) {\n            int s = pid[k];\n            int g = pid[k+1];\n\n            vector<Cand> cand;\n            cand.reserve((int)layers[k].size() * 5 + 8);\n\n            for (int si = 0; si < (int)layers[k].size(); si++) {\n                const auto& st = layers[k][si];\n                uint64_t mask = st.mask;\n                int base = st.cost;\n\n                array<uint32_t,MAXN> row, col;\n                buildMasks(mask, row, col);\n\n                // Option 0: no extra alter\n                int d0 = bfsDistRC(row, col, s, g);\n                if (d0 < INF) {\n                    cand.push_back(Cand{mask, base + d0, si, 0, 0});\n                }\n\n                // Option 1: move away then block current point\n                uint64_t nmask = mask | (1ull << k);\n                array<uint32_t,MAXN> row2 = row, col2 = col;\n                int sr = pts[k].r, sc = pts[k].c;\n                row2[sr] |= (1u << sc);\n                col2[sc] |= (1u << sr);\n\n                for (int d = 0; d < 4; d++) {\n                    int n = moveTo[s][d];\n                    if (n == -1) continue;\n                    if (blockedId(n, row)) continue;\n\n                    int d1 = bfsDistRC(row2, col2, n, g);\n                    if (d1 >= INF) continue;\n                    cand.push_back(Cand{nmask, base + 2 + d1, si, 1, (uint8_t)d});\n                }\n            }\n\n            if (cand.empty()) return {};\n\n            // Dedup by mask\n            sort(cand.begin(), cand.end(), [](const Cand& a, const Cand& b) {\n                if (a.mask != b.mask) return a.mask < b.mask;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                int pa = __builtin_popcountll(a.mask);\n                int pb = __builtin_popcountll(b.mask);\n                if (pa != pb) return pa > pb;\n                return a.parent < b.parent;\n            });\n\n            vector<Cand> uniq;\n            uniq.reserve(cand.size());\n            for (const auto& c : cand) {\n                if (uniq.empty() || uniq.back().mask != c.mask) {\n                    uniq.push_back(c);\n                } else if (c.cost < uniq.back().cost) {\n                    uniq.back() = c;\n                }\n            }\n\n            // Beam prune\n            sort(uniq.begin(), uniq.end(), [](const Cand& a, const Cand& b) {\n                if (a.cost != b.cost) return a.cost < b.cost;\n                int pa = __builtin_popcountll(a.mask);\n                int pb = __builtin_popcountll(b.mask);\n                if (pa != pb) return pa > pb;\n                return a.mask < b.mask;\n            });\n\n            if ((int)uniq.size() > BEAM_WIDTH) {\n                vector<Cand> trimmed(uniq.begin(), uniq.begin() + BEAM_WIDTH);\n\n                // Keep mask=0 state if available (robust baseline path)\n                bool hasZero = false;\n                for (auto& x : trimmed) if (x.mask == 0ull) { hasZero = true; break; }\n                if (!hasZero) {\n                    auto it = find_if(uniq.begin() + BEAM_WIDTH, uniq.end(),\n                                      [](const Cand& x){ return x.mask == 0ull; });\n                    if (it != uniq.end()) {\n                        trimmed.back() = *it;\n                        sort(trimmed.begin(), trimmed.end(), [](const Cand& a, const Cand& b) {\n                            if (a.cost != b.cost) return a.cost < b.cost;\n                            int pa = __builtin_popcountll(a.mask);\n                            int pb = __builtin_popcountll(b.mask);\n                            if (pa != pb) return pa > pb;\n                            return a.mask < b.mask;\n                        });\n                    }\n                }\n                uniq.swap(trimmed);\n            }\n\n            layers[k+1].clear();\n            layers[k+1].reserve(uniq.size());\n            for (const auto& c : uniq) {\n                layers[k+1].push_back(BNode{c.mask, c.cost, c.parent, c.op, c.dir});\n            }\n\n            if (layers[k+1].empty()) return {};\n        }\n\n        if (layers[M-1].empty()) return {};\n\n        int bi = 0;\n        for (int i = 1; i < (int)layers[M-1].size(); i++) {\n            if (layers[M-1][i].cost < layers[M-1][bi].cost) bi = i;\n        }\n\n        // Backtrack decisions\n        vector<uint8_t> op(M-1, 0), dir(M-1, 0);\n        int idx = bi;\n        for (int k = M - 2; k >= 0; k--) {\n            const auto& nd = layers[k+1][idx];\n            op[k] = nd.op;\n            dir[k] = nd.dir;\n            idx = nd.parent;\n            if (idx < 0 && k > 0) return {};\n        }\n\n        // Reconstruct full action list\n        vector<Action> ans;\n        ans.reserve(layers[M-1][bi].cost + 16);\n\n        uint64_t mask = 0ull;\n        int cur = pid[0];\n\n        for (int k = 0; k < M - 1; k++) {\n            if (op[k] == 1) {\n                int d = dir[k];\n                int n = moveTo[cur][d];\n                if (n == -1) return {};\n                ans.push_back({'M', dch[d]});\n                cur = n;\n                ans.push_back({'A', dch[opp[d]]});\n                mask |= (1ull << k);\n            }\n\n            vector<Action> path;\n            if (!bfsPathMask(mask, cur, pid[k+1], path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = pid[k+1];\n        }\n\n        return ans;\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        pts.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> pts[i].r >> pts[i].c;\n        }\n\n        initPrecompute();\n\n        // Strong baseline\n        vector<Action> base = fallbackNoBlock();\n        if (base.empty() || (int)base.size() > LIMIT || !validate(base)) {\n            base = fallbackManhattan();\n        }\n\n        // Beam candidate\n        vector<Action> beam = runBeam();\n\n        vector<Action> ans = base;\n        if (!beam.empty() && (int)beam.size() <= LIMIT && validate(beam)) {\n            if ((int)beam.size() < (int)ans.size()) ans.swap(beam);\n        }\n\n        if ((int)ans.size() > LIMIT || !validate(ans)) {\n            ans = fallbackManhattan();\n        }\n\n        for (const auto& ac : ans) {\n            cout << ac.a << ' ' << ac.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}"},"2":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int BOARD = 10000;\nenum Side { LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3 };\n\nstruct Company { int x, y, r; };\nstruct Rect { int l, b, r, t; }; // [l,r) x [b,t)\n\nstruct State {\n    vector<Rect> rects;\n    vector<long long> area;\n    vector<double> p;\n    double total = 0.0;\n};\n\nint n;\nvector<Company> C;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed ? seed : 88172645463325252ull) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int l, int r) {\n        if (l >= r) return l;\n        uint64_t span = (uint64_t)(r - l + 1);\n        return l + (int)(nextU64() % span);\n    }\n};\n\ninline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\ninline long long rectArea(const Rect& rc) {\n    return 1LL * (rc.r - rc.l) * (rc.t - rc.b);\n}\n\ninline double satisfaction(long long s, long long target) {\n    if (s <= 0) return 0.0;\n    double ratio = (s < target) ? (double)s / (double)target : (double)target / (double)s;\n    double d = 1.0 - ratio;\n    return 1.0 - d * d;\n}\n\ninline int getCoord(const Rect& rc, int side) {\n    if (side == LEFT) return rc.l;\n    if (side == RIGHT) return rc.r;\n    if (side == BOTTOM) return rc.b;\n    return rc.t;\n}\n\ninline void setCoord(Rect& rc, int side, int v) {\n    if (side == LEFT) rc.l = v;\n    else if (side == RIGHT) rc.r = v;\n    else if (side == BOTTOM) rc.b = v;\n    else rc.t = v;\n}\n\ninline long long areaWithSide(const Rect& rc, int side, int v) {\n    if (side == LEFT) return 1LL * (rc.r - v) * (rc.t - rc.b);\n    if (side == RIGHT) return 1LL * (v - rc.l) * (rc.t - rc.b);\n    if (side == BOTTOM) return 1LL * (rc.r - rc.l) * (rc.t - v);\n    return 1LL * (rc.r - rc.l) * (v - rc.b);\n}\n\nState makeState(const vector<Rect>& rects) {\n    State st;\n    st.rects = rects;\n    st.area.resize(n);\n    st.p.resize(n);\n    st.total = 0.0;\n    for (int i = 0; i < n; ++i) {\n        st.area[i] = rectArea(st.rects[i]);\n        st.p[i] = satisfaction(st.area[i], C[i].r);\n        st.total += st.p[i];\n    }\n    return st;\n}\n\nvoid shuffleVec(vector<int>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.nextInt(0, i);\n        swap(v[i], v[j]);\n    }\n}\n\nbool validateRects(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = rects[i];\n        if (!(0 <= a.l && a.l < a.r && a.r <= BOARD && 0 <= a.b && a.b < a.t && a.t <= BOARD)) return false;\n        if (!(a.l <= C[i].x && C[i].x + 1 <= a.r && a.b <= C[i].y && C[i].y + 1 <= a.t)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            if (overlap1D(rects[i].l, rects[i].r, rects[j].l, rects[j].r) &&\n                overlap1D(rects[i].b, rects[i].t, rects[j].b, rects[j].t)) {\n                return false;\n            }\n        }\n    }\n    return true;\n}\n\n// side movable range, optionally ignoring one rectangle (for pair operation)\npair<int, int> sideRange(const State& st, int i, int side, int ignore = -1) {\n    const Rect& a = st.rects[i];\n\n    if (side == LEFT) {\n        int L = 0;\n        int U = min(C[i].x, a.r - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.l < a.r) {\n                L = max(L, b.r);\n            }\n        }\n        return {L, U};\n    }\n\n    if (side == RIGHT) {\n        int L = max(C[i].x + 1, a.l + 1);\n        int U = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.r > a.l) {\n                U = min(U, b.l);\n            }\n        }\n        return {L, U};\n    }\n\n    if (side == BOTTOM) {\n        int L = 0;\n        int U = min(C[i].y, a.t - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && b.b < a.t) {\n                L = max(L, b.t);\n            }\n        }\n        return {L, U};\n    }\n\n    int L = max(C[i].y + 1, a.b + 1);\n    int U = BOARD;\n    for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n        const Rect& b = st.rects[j];\n        if (overlap1D(a.l, a.r, b.l, b.r) && b.t > a.b) {\n            U = min(U, b.b);\n        }\n    }\n    return {L, U};\n}\n\npair<int, int> shiftRangeX(const State& st, int i) {\n    const Rect& a = st.rects[i];\n    int LB = -a.l;\n    int UB = BOARD - a.r;\n\n    LB = max(LB, C[i].x + 1 - a.r);\n    UB = min(UB, C[i].x - a.l);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.b, a.t, b.b, b.t)) continue;\n        if (b.r <= a.l) LB = max(LB, b.r - a.l);\n        else if (b.l >= a.r) UB = min(UB, b.l - a.r);\n        else return {1, 0}; // invalid current state\n    }\n    return {LB, UB};\n}\n\npair<int, int> shiftRangeY(const State& st, int i) {\n    const Rect& a = st.rects[i];\n    int LB = -a.b;\n    int UB = BOARD - a.t;\n\n    LB = max(LB, C[i].y + 1 - a.t);\n    UB = min(UB, C[i].y - a.b);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.l, a.r, b.l, b.r)) continue;\n        if (b.t <= a.b) LB = max(LB, b.t - a.b);\n        else if (b.b >= a.t) UB = min(UB, b.b - a.t);\n        else return {1, 0}; // invalid current state\n    }\n    return {LB, UB};\n}\n\nconstexpr int MAX_CAND = 32;\n\ninline void addCand(int arr[], int& m, int v, int L, int U) {\n    if (v < L || v > U) return;\n    for (int i = 0; i < m; ++i) if (arr[i] == v) return;\n    if (m < MAX_CAND) arr[m++] = v;\n}\n\nvoid fillCandidatesForSide(const State& st, int i, int side, int L, int U, int arr[], int& m, RNG* rng = nullptr) {\n    m = 0;\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n    addCand(arr, m, cur, L, U);\n    addCand(arr, m, L, L, U);\n    addCand(arr, m, U, L, U);\n    addCand(arr, m, (L + U) >> 1, L, U);\n\n    long long target = C[i].r;\n    if (side == LEFT || side == RIGHT) {\n        int h = a.t - a.b;\n        if (h > 0) {\n            int w0 = (int)llround((double)target / (double)h);\n            for (int dw = -2; dw <= 2; ++dw) {\n                int w = w0 + dw;\n                if (w < 1) continue;\n                int v = (side == LEFT) ? (a.r - w) : (a.l + w);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    } else {\n        int w = a.r - a.l;\n        if (w > 0) {\n            int h0 = (int)llround((double)target / (double)w);\n            for (int dh = -2; dh <= 2; ++dh) {\n                int h = h0 + dh;\n                if (h < 1) continue;\n                int v = (side == BOTTOM) ? (a.t - h) : (a.b + h);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    }\n\n    if (rng && U > L) {\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n    }\n}\n\nint bestCoordForSide(const State& st, int i, int side, int L, int U) {\n    int cands[MAX_CAND], m;\n    fillCandidatesForSide(st, i, side, L, U, cands, m, nullptr);\n\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n    int best = cur;\n    double bestP = st.p[i];\n\n    for (int k = 0; k < m; ++k) {\n        int v = cands[k];\n        long long ar = areaWithSide(a, side, v);\n        double np = satisfaction(ar, C[i].r);\n        if (np > bestP + 1e-15 || (fabs(np - bestP) <= 1e-15 && abs(v - cur) < abs(best - cur))) {\n            bestP = np;\n            best = v;\n        }\n    }\n    return best;\n}\n\ninline void applySingleSide(State& st, int i, int side, int v) {\n    st.total -= st.p[i];\n    setCoord(st.rects[i], side, v);\n    st.area[i] = rectArea(st.rects[i]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.total += st.p[i];\n}\n\nvoid greedyOptimize(State& st, RNG& rng, int maxPass) {\n    vector<int> ord(n);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        shuffleVec(ord, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < n; ++idx) {\n            int i = ord[idx];\n            double oldP = st.p[i];\n            int bestSide = -1, bestV = 0;\n            double bestDelta = 1e-12;\n\n            for (int side = 0; side < 4; ++side) {\n                auto [L, U] = sideRange(st, i, side);\n                if (L > U) continue;\n\n                int curV = getCoord(st.rects[i], side);\n                int v = bestCoordForSide(st, i, side, L, U);\n                if (v == curV) continue;\n\n                long long ar = areaWithSide(st.rects[i], side, v);\n                double np = satisfaction(ar, C[i].r);\n                double delta = np - oldP;\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSide = side;\n                    bestV = v;\n                }\n            }\n\n            if (bestSide != -1) {\n                applySingleSide(st, i, bestSide, bestV);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nstruct PairMove {\n    int i = -1, j = -1;\n    int sideI = -1, sideJ = -1;\n    int vI = 0, vJ = 0;\n    double delta = 0.0;\n    bool valid = false;\n};\n\nbool proposeHorizontal(const State& st, int left, int right, RNG& rng, bool greedy, PairMove& out) {\n    // left is left of right: rect[left].r <= rect[right].l\n    auto [L1, U1] = sideRange(st, left, RIGHT, right);\n    auto [L2, U2] = sideRange(st, right, LEFT, left);\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false; // impossible to have x <= y\n\n    int curX = st.rects[left].r;\n    int curY = st.rects[right].l;\n    double oldS = st.p[left] + st.p[right];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, left, RIGHT, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, right, LEFT, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n                long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n                double s = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n        long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n        double ns = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposeVertical(const State& st, int bottom, int top, RNG& rng, bool greedy, PairMove& out) {\n    // bottom is below top: rect[bottom].t <= rect[top].b\n    auto [L1, U1] = sideRange(st, bottom, TOP, top);\n    auto [L2, U2] = sideRange(st, top, BOTTOM, bottom);\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false; // impossible to have x <= y\n\n    int curX = st.rects[bottom].t;\n    int curY = st.rects[top].b;\n    double oldS = st.p[bottom] + st.p[top];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, bottom, TOP, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, top, BOTTOM, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n                long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n                double s = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n        long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n        double ns = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposePairMove(const State& st, int i, int j, RNG& rng, bool greedy, PairMove& out) {\n    if (i == j) return false;\n    const Rect& a = st.rects[i];\n    const Rect& b = st.rects[j];\n\n    bool found = false;\n    PairMove best;\n\n    if (overlap1D(a.b, a.t, b.b, b.t)) {\n        if (a.r <= b.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, i, j, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        } else if (b.r <= a.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, j, i, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        }\n    }\n\n    if (overlap1D(a.l, a.r, b.l, b.r)) {\n        if (a.t <= b.b) {\n            PairMove mv;\n            if (proposeVertical(st, i, j, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        } else if (b.t <= a.b) {\n            PairMove mv;\n            if (proposeVertical(st, j, i, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        }\n    }\n\n    if (!found) return false;\n    out = best;\n    return true;\n}\n\ninline void applyPairMove(State& st, const PairMove& mv) {\n    int i = mv.i, j = mv.j;\n    st.total -= st.p[i] + st.p[j];\n\n    setCoord(st.rects[i], mv.sideI, mv.vI);\n    setCoord(st.rects[j], mv.sideJ, mv.vJ);\n\n    st.area[i] = rectArea(st.rects[i]);\n    st.area[j] = rectArea(st.rects[j]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.p[j] = satisfaction(st.area[j], C[j].r);\n\n    st.total += st.p[i] + st.p[j];\n}\n\nvoid pairGreedyOptimize(State& st, RNG& rng, int maxIter) {\n    vector<int> ord(n);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int it = 0; it < maxIter; ++it) {\n        shuffleVec(ord, rng);\n        bool improved = false;\n\n        for (int ai = 0; ai < n; ++ai) {\n            int i = ord[ai];\n            for (int bj = ai + 1; bj < n; ++bj) {\n                int j = ord[bj];\n                const Rect& a = st.rects[i];\n                const Rect& b = st.rects[j];\n                if (!overlap1D(a.b, a.t, b.b, b.t) && !overlap1D(a.l, a.r, b.l, b.r)) continue;\n\n                PairMove mv;\n                if (!proposePairMove(st, i, j, rng, true, mv)) continue;\n                if (mv.delta > 1e-12) {\n                    applyPairMove(st, mv);\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\n// -------- Guillotine-like randomized initializer --------\n\nstruct SplitCand {\n    int ori; // 0: vertical, 1: horizontal\n    int k;\n    int t;\n    double cost;\n};\n\nint buildCallCount = 0;\nconstexpr int BUILD_CALL_LIMIT = 140000;\n\nbool buildPartitionRec(const vector<int>& ids, int L, int B, int R, int T, vector<Rect>& out, RNG& rng) {\n    if (++buildCallCount > BUILD_CALL_LIMIT) return false;\n\n    int m = (int)ids.size();\n    if (m == 0) return true;\n    if (L >= R || B >= T) return false;\n    if (1LL * (R - L) * (T - B) < m) return false;\n\n    if (m == 1) {\n        int id = ids[0];\n        if (!(L <= C[id].x && C[id].x + 1 <= R && B <= C[id].y && C[id].y + 1 <= T)) return false;\n        out[id] = {L, B, R, T};\n        return true;\n    }\n\n    int W = R - L, H = T - B;\n    if (W <= 0 || H <= 0) return false;\n\n    vector<int> ox = ids, oy = ids;\n    sort(ox.begin(), ox.end(), [](int a, int b) {\n        if (C[a].x != C[b].x) return C[a].x < C[b].x;\n        return C[a].y < C[b].y;\n    });\n    sort(oy.begin(), oy.end(), [](int a, int b) {\n        if (C[a].y != C[b].y) return C[a].y < C[b].y;\n        return C[a].x < C[b].x;\n    });\n\n    vector<long long> px(m + 1, 0), py(m + 1, 0);\n    for (int i = 0; i < m; ++i) {\n        px[i + 1] = px[i] + C[ox[i]].r;\n        py[i + 1] = py[i] + C[oy[i]].r;\n    }\n    long long totalR = px[m];\n\n    vector<SplitCand> cands;\n    cands.reserve(2 * (m - 1));\n\n    if (W >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int xl = C[ox[k - 1]].x;\n            int xr = C[ox[k]].x;\n            int low = max(L + 1, xl + 1);\n            int high = min(R - 1, xr);\n            if (low > high) continue;\n\n            long long leftR = px[k];\n            long long rightR = totalR - leftR;\n\n            int t = (int)llround(L + (double)leftR / (double)H);\n            t = max(low, min(high, t));\n\n            long long leftArea = 1LL * (t - L) * H;\n            long long rightArea = 1LL * (R - t) * H;\n\n            double cost = fabs((double)(leftArea - leftR)) + fabs((double)(rightArea - rightR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n            cands.push_back({0, k, t, cost});\n        }\n    }\n\n    if (H >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int yb = C[oy[k - 1]].y;\n            int yt = C[oy[k]].y;\n            int low = max(B + 1, yb + 1);\n            int high = min(T - 1, yt);\n            if (low > high) continue;\n\n            long long botR = py[k];\n            long long topR = totalR - botR;\n\n            int t = (int)llround(B + (double)botR / (double)W);\n            t = max(low, min(high, t));\n\n            long long botArea = 1LL * (t - B) * W;\n            long long topArea = 1LL * (T - t) * W;\n\n            double cost = fabs((double)(botArea - botR)) + fabs((double)(topArea - topR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n            cands.push_back({1, k, t, cost});\n        }\n    }\n\n    if (cands.empty()) return false;\n    sort(cands.begin(), cands.end(), [](const SplitCand& a, const SplitCand& b) { return a.cost < b.cost; });\n\n    int lim = min((int)cands.size(), 20);\n    for (int i = 0; i < lim; ++i) {\n        int span = min(3, lim - i - 1);\n        if (span > 0) {\n            int j = i + rng.nextInt(0, span);\n            swap(cands[i], cands[j]);\n        }\n    }\n\n    for (int idx = 0; idx < lim; ++idx) {\n        const SplitCand& c = cands[idx];\n        if (c.ori == 0) {\n            long long areaL = 1LL * (c.t - L) * (T - B);\n            long long areaR = 1LL * (R - c.t) * (T - B);\n            if (areaL < c.k || areaR < (m - c.k)) continue;\n\n            vector<int> leftIds(ox.begin(), ox.begin() + c.k);\n            vector<int> rightIds(ox.begin() + c.k, ox.end());\n\n            if (buildPartitionRec(leftIds, L, B, c.t, T, out, rng) &&\n                buildPartitionRec(rightIds, c.t, B, R, T, out, rng)) {\n                return true;\n            }\n        } else {\n            long long areaB = 1LL * (R - L) * (c.t - B);\n            long long areaT = 1LL * (R - L) * (T - c.t);\n            if (areaB < c.k || areaT < (m - c.k)) continue;\n\n            vector<int> botIds(oy.begin(), oy.begin() + c.k);\n            vector<int> topIds(oy.begin() + c.k, oy.end());\n\n            if (buildPartitionRec(botIds, L, B, R, c.t, out, rng) &&\n                buildPartitionRec(topIds, L, c.t, R, T, out, rng)) {\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nint pickRect(const State& st, RNG& rng) {\n    int best = rng.nextInt(0, n - 1);\n    for (int t = 0; t < 3; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nint pickRect2(const State& st, RNG& rng, int avoid) {\n    int best = rng.nextInt(0, n - 1);\n    if (best == avoid) best = (best + 1) % n;\n    for (int t = 0; t < 3; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (j == avoid) continue;\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    C.resize(n);\n\n    uint64_t seed = 1469598103934665603ull ^ (uint64_t)n * 1000003ull;\n    for (int i = 0; i < n; ++i) {\n        cin >> C[i].x >> C[i].y >> C[i].r;\n        seed ^= (uint64_t)(C[i].x + 1) * 1000003ull;\n        seed ^= (uint64_t)(C[i].y + 1) * 1009837ull;\n        seed ^= (uint64_t)(C[i].r + 3) * 10000019ull;\n        seed *= 1099511628211ull;\n    }\n    RNG rng(seed);\n\n    auto start = chrono::steady_clock::now();\n    auto nowSec = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    // ---- Initial states ----\n    State bestInit;\n    bool initSet = false;\n\n    // multiple randomized 1x1 local searches\n    for (int rep = 0; rep < 3; ++rep) {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; ++i) rects[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n        State st = makeState(rects);\n\n        greedyOptimize(st, rng, 45);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 12);\n\n        if (!initSet || st.total > bestInit.total) {\n            bestInit = st;\n            initSet = true;\n        }\n        if (nowSec() > 0.70) break;\n    }\n\n    // randomized guillotine initial states\n    int attempt = 0;\n    while (attempt < 12 && nowSec() < 1.15) {\n        ++attempt;\n        vector<Rect> rects(n);\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n\n        buildCallCount = 0;\n        bool ok = buildPartitionRec(ids, 0, 0, BOARD, BOARD, rects, rng);\n        if (!ok || !validateRects(rects)) continue;\n\n        State st = makeState(rects);\n        greedyOptimize(st, rng, 35);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 10);\n\n        if (st.total > bestInit.total) bestInit = st;\n    }\n\n    State cur = bestInit;\n    State best = bestInit;\n\n    // ---- SA ----\n    const double TL = 4.78;\n    const double T0 = 0.06;\n    const double T1 = 0.0002;\n    double temp = T0;\n    double progress = 0.0;\n    double nextRefine = nowSec() + 0.65;\n\n    for (long long iter = 0;; ++iter) {\n        if ((iter & 255LL) == 0) {\n            double t = nowSec();\n            if (t >= TL) break;\n\n            progress = t / TL;\n            temp = T0 * pow(T1 / T0, progress);\n\n            if (t >= nextRefine) {\n                greedyOptimize(cur, rng, 2);\n                pairGreedyOptimize(cur, rng, 1);\n\n                if (cur.total > best.total) best = cur;\n                if (cur.total < best.total - 0.10 && rng.nextDouble() < 0.6) cur = best;\n\n                nextRefine += 0.65;\n            }\n        }\n\n        double op = rng.nextDouble();\n\n        if (op < 0.56) {\n            // single-side move\n            int i = pickRect(cur, rng);\n            int side = rng.nextInt(0, 3);\n\n            auto [L, U] = sideRange(cur, i, side);\n            if (L > U) continue;\n\n            int curV = getCoord(cur.rects[i], side);\n            int v = curV;\n\n            double mode = rng.nextDouble();\n            if (mode < 0.55) {\n                v = bestCoordForSide(cur, i, side, L, U);\n            } else if (mode < 0.85) {\n                int span = U - L;\n                int step = max(1, (int)(span * (1.0 - progress) * 0.35));\n                int d = rng.nextInt(-step, step);\n                v = curV + d;\n                if (v < L) v = L;\n                if (v > U) v = U;\n            } else {\n                v = rng.nextInt(L, U);\n            }\n\n            if (v == curV) continue;\n\n            long long newA = areaWithSide(cur.rects[i], side, v);\n            double newP = satisfaction(newA, C[i].r);\n            double delta = newP - cur.p[i];\n\n            if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                cur.total += delta;\n                cur.p[i] = newP;\n                cur.area[i] = newA;\n                setCoord(cur.rects[i], side, v);\n                if (cur.total > best.total) best = cur;\n            }\n\n        } else if (op < 0.81) {\n            // pair boundary move\n            int i = pickRect(cur, rng);\n            int j = pickRect2(cur, rng, i);\n\n            bool greedySel = (rng.nextDouble() < 0.68);\n            PairMove mv;\n            if (!proposePairMove(cur, i, j, rng, greedySel, mv)) continue;\n\n            double delta = mv.delta;\n            if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                applyPairMove(cur, mv);\n                if (cur.total > best.total) best = cur;\n            }\n\n        } else if (op < 0.905) {\n            // shift X\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeX(cur, i);\n            if (LB > UB) continue;\n\n            int dx;\n            if (LB == UB) dx = LB;\n            else if (rng.nextDouble() < 0.55) dx = (rng.nextDouble() < 0.5 ? LB : UB);\n            else dx = rng.nextInt(LB, UB);\n\n            if (dx == 0) continue;\n            cur.rects[i].l += dx;\n            cur.rects[i].r += dx;\n\n        } else {\n            // shift Y\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeY(cur, i);\n            if (LB > UB) continue;\n\n            int dy;\n            if (LB == UB) dy = LB;\n            else if (rng.nextDouble() < 0.55) dy = (rng.nextDouble() < 0.5 ? LB : UB);\n            else dy = rng.nextInt(LB, UB);\n\n            if (dy == 0) continue;\n            cur.rects[i].b += dy;\n            cur.rects[i].t += dy;\n        }\n    }\n\n    // ---- final polish ----\n    State ans = best;\n    pairGreedyOptimize(ans, rng, 1);\n    greedyOptimize(ans, rng, 55);\n    pairGreedyOptimize(ans, rng, 1);\n    greedyOptimize(ans, rng, 25);\n\n    if (ans.total > best.total) best = ans;\n    best = makeState(best.rects);\n\n    if (!validateRects(best.rects)) {\n        if (validateRects(bestInit.rects)) {\n            best = bestInit;\n        } else {\n            vector<Rect> safe(n);\n            for (int i = 0; i < n; ++i) safe[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n            best = makeState(safe);\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& rc = best.rects[i];\n        cout << rc.l << ' ' << rc.b << ' ' << rc.r << ' ' << rc.t << '\\n';\n    }\n\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 N = H * W;\nstatic constexpr int MAXT = 2500;\nstatic constexpr int WORDS = (MAXT + 63) / 64; // 40\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + int(next_u64() % uint64_t(r - l + 1));\n    }\n};\n\nstruct Policy {\n    double wVal, wLook, wDeg, wPair, wRand, eps, deadPenalty;\n};\n\nstruct RunParam {\n    Policy pol;\n    int evalRollouts;   // 1..3\n    int evalDepth;      // <=0 => full playout to dead-end\n    double mixBest;     // 0..1\n    double evalNoise;\n};\n\nstruct Result {\n    long long score = LLONG_MIN;\n    string path;\n};\n\nint tileId[N], pval[N], pairLoss[N];\nint degCell[N];\nint nxtCell[N][4];\nchar nxtDir[N][4];\nint nextAll[N][4];\nint M, startCell;\n\ninline bool bit_get(const uint64_t* bs, int t) {\n    return (bs[t >> 6] >> (t & 63)) & 1ULL;\n}\ninline void bit_set(uint64_t* bs, int t) {\n    bs[t >> 6] |= 1ULL << (t & 63);\n}\ninline void bit_clear_all(uint64_t* bs) {\n    memset(bs, 0, sizeof(uint64_t) * WORDS);\n}\n\ninline int charToDir(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\ninline int gatherMoves(int cur, const uint64_t* vis, int outCands[4], char outDirs[4]) {\n    int nc = 0;\n    for (int k = 0; k < degCell[cur]; k++) {\n        int to = nxtCell[cur][k];\n        if (!bit_get(vis, tileId[to])) {\n            outCands[nc] = to;\n            outDirs[nc] = nxtDir[cur][k];\n            nc++;\n        }\n    }\n    return nc;\n}\n\n// return index in [0, nc)\ninline int selectByPolicy(const int cands[4], int nc, const uint64_t* vis, const Policy& pol, XorShift64& rng) {\n    if (nc == 1) return 0;\n    if (rng.next_double() < pol.eps) return rng.next_int(0, nc - 1);\n\n    double bestScore = -1e100;\n    int bestIdx = 0;\n\n    for (int i = 0; i < nc; i++) {\n        int v = cands[i];\n        int degNext = 0;\n        int bestNextVal = 0;\n\n        for (int k = 0; k < degCell[v]; k++) {\n            int u = nxtCell[v][k];\n            if (!bit_get(vis, tileId[u])) {\n                degNext++;\n                if (pval[u] > bestNextVal) bestNextVal = pval[u];\n            }\n        }\n\n        double s = pol.wVal * pval[v]\n                 + pol.wLook * bestNextVal\n                 - pol.wDeg * degNext\n                 - pol.wPair * pairLoss[v]\n                 + pol.wRand * rng.next_double();\n\n        if (degNext == 0) s -= pol.deadPenalty;\n\n        if (s > bestScore + 1e-12) {\n            bestScore = s;\n            bestIdx = i;\n        } else if (fabs(s - bestScore) <= 1e-12) {\n            if (rng.next_u64() & 1ULL) bestIdx = i;\n        }\n    }\n    return bestIdx;\n}\n\nint playoutGain(\n    int cur,\n    uint64_t* vis,\n    const Policy& pol,\n    XorShift64& rng,\n    int maxDepth,\n    const chrono::steady_clock::time_point& deadline\n) {\n    int gain = 0;\n    int step = 0;\n\n    while (true) {\n        if (maxDepth > 0 && step >= maxDepth) break;\n\n        int cands[4];\n        char dirs[4];\n        int nc = gatherMoves(cur, vis, cands, dirs);\n        if (nc == 0) break;\n\n        int idx = selectByPolicy(cands, nc, vis, pol, rng);\n        int nxt = cands[idx];\n\n        bit_set(vis, tileId[nxt]);\n        cur = nxt;\n        gain += pval[cur];\n        step++;\n\n        if ((step & 63) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n    }\n\n    return gain;\n}\n\nResult simulate(\n    const RunParam& rp,\n    const string* basePath,\n    int cut,\n    XorShift64& rng,\n    const chrono::steady_clock::time_point& deadline\n) {\n    Result res;\n    uint64_t vis[WORDS];\n    bit_clear_all(vis);\n\n    string path;\n    path.reserve(2600);\n\n    int cur = startCell;\n    long long score = pval[cur];\n    bit_set(vis, tileId[cur]);\n\n    // Replay prefix from elite path (if any)\n    if (basePath && cut > 0) {\n        int L = min<int>(cut, basePath->size());\n        for (int i = 0; i < L; i++) {\n            int d = charToDir((*basePath)[i]);\n            if (d < 0) break;\n            int to = nextAll[cur][d];\n            if (to < 0) break;\n            if (bit_get(vis, tileId[to])) break;\n\n            path.push_back((*basePath)[i]);\n            cur = to;\n            bit_set(vis, tileId[cur]);\n            score += pval[cur];\n        }\n    }\n\n    int stepMain = 0;\n    while (true) {\n        if ((stepMain & 31) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n\n        int cands[4];\n        char dirs[4];\n        int nc = gatherMoves(cur, vis, cands, dirs);\n        if (nc == 0) break;\n\n        int pickIdx = 0;\n\n        if (nc == 1) {\n            pickIdx = 0;\n        } else {\n            if (chrono::steady_clock::now() >= deadline) {\n                pickIdx = selectByPolicy(cands, nc, vis, rp.pol, rng);\n            } else {\n                double bestEval = -1e100;\n                pickIdx = 0;\n\n                for (int i = 0; i < nc; i++) {\n                    int cand = cands[i];\n                    long long sumGain = 0;\n                    long long bestGain = LLONG_MIN;\n                    int done = 0;\n\n                    for (int r = 0; r < rp.evalRollouts; r++) {\n                        if ((r & 1) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n                        uint64_t vis2[WORDS];\n                        memcpy(vis2, vis, sizeof(vis2));\n                        bit_set(vis2, tileId[cand]);\n\n                        uint64_t mixSeed = rng.next_u64();\n                        mixSeed ^= (uint64_t)cand * 11995408973635179863ULL;\n                        mixSeed ^= (uint64_t)(r + 1) * 10150724397891781847ULL;\n                        XorShift64 rr(mixSeed);\n\n                        long long g = pval[cand];\n                        g += playoutGain(cand, vis2, rp.pol, rr, rp.evalDepth, deadline);\n\n                        sumGain += g;\n                        if (g > bestGain) bestGain = g;\n                        done++;\n                    }\n\n                    double ev;\n                    if (done == 0) {\n                        // fallback static heuristic\n                        int degNext = 0;\n                        int bestNextVal = 0;\n                        for (int k = 0; k < degCell[cand]; k++) {\n                            int u = nxtCell[cand][k];\n                            if (!bit_get(vis, tileId[u])) {\n                                degNext++;\n                                bestNextVal = max(bestNextVal, pval[u]);\n                            }\n                        }\n                        ev = 2.0 * pval[cand] + 0.8 * bestNextVal - 6.0 * degNext - 0.2 * pairLoss[cand];\n                    } else {\n                        double avg = (double)sumGain / (double)done;\n                        ev = (1.0 - rp.mixBest) * avg + rp.mixBest * (double)bestGain;\n\n                        // tiny static tie-break\n                        int degNext = 0;\n                        for (int k = 0; k < degCell[cand]; k++) {\n                            int u = nxtCell[cand][k];\n                            if (!bit_get(vis, tileId[u])) degNext++;\n                        }\n                        ev += 0.10 * pval[cand] - 0.8 * degNext - 0.03 * pairLoss[cand];\n                        ev += rp.evalNoise * rng.next_double();\n                    }\n\n                    if (ev > bestEval + 1e-9) {\n                        bestEval = ev;\n                        pickIdx = i;\n                    } else if (fabs(ev - bestEval) <= 1e-9) {\n                        if (rng.next_u64() & 1ULL) pickIdx = i;\n                    }\n                }\n            }\n        }\n\n        int nxt = cands[pickIdx];\n        path.push_back(dirs[pickIdx]);\n        cur = nxt;\n        bit_set(vis, tileId[cur]);\n        score += pval[cur];\n        stepMain++;\n    }\n\n    res.score = score;\n    res.path = std::move(path);\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    if (!(cin >> si >> sj)) return 0;\n\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x;\n            cin >> x;\n            tileId[i * W + j] = x;\n            maxTile = max(maxTile, x);\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[i * W + j];\n        }\n    }\n\n    startCell = si * W + sj;\n\n    // tile -> cells (1 or 2)\n    vector<int> c1(M, -1), c2(M, -1);\n    for (int v = 0; v < N; v++) {\n        int t = tileId[v];\n        if (c1[t] == -1) c1[t] = v;\n        else c2[t] = v;\n    }\n\n    // pair loss\n    for (int v = 0; v < N; v++) pairLoss[v] = 0;\n    for (int t = 0; t < M; t++) {\n        if (c1[t] != -1 && c2[t] != -1) {\n            int a = c1[t], b = c2[t];\n            pairLoss[a] = max(0, pval[b] - pval[a]);\n            pairLoss[b] = max(0, pval[a] - pval[b]);\n        }\n    }\n\n    // build adjacency\n    for (int v = 0; v < N; v++) {\n        degCell[v] = 0;\n        for (int d = 0; d < 4; d++) nextAll[v][d] = -1;\n    }\n\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    const char dc[4] = {'U', 'D', 'L', 'R'};\n\n    auto inside = [&](int r, int c) {\n        return (0 <= r && r < H && 0 <= c && c < W);\n    };\n\n    for (int r = 0; r < H; r++) {\n        for (int c = 0; c < W; c++) {\n            int v = r * W + c;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + di[d], nc = c + dj[d];\n                if (!inside(nr, nc)) continue;\n                int to = nr * W + nc;\n                nextAll[v][d] = to;\n\n                if (tileId[to] != tileId[v]) {\n                    int k = degCell[v]++;\n                    nxtCell[v][k] = to;\n                    nxtDir[v][k] = dc[d];\n                }\n            }\n        }\n    }\n\n    using Clock = chrono::steady_clock;\n    auto deadline = Clock::now() + chrono::milliseconds(1920);\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)startCell * 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; i += 53) {\n        seed ^= (uint64_t)(tileId[i] + 131 * pval[i] + i * 17) * 0xbf58476d1ce4e5b9ULL;\n        seed = (seed << 7) | (seed >> 57);\n    }\n    XorShift64 rng(seed);\n\n    auto randomParam = [&](XorShift64& rr) -> RunParam {\n        RunParam rp;\n        rp.pol.wVal = 0.8 + 1.8 * rr.next_double();\n        rp.pol.wLook = 0.0 + 1.4 * rr.next_double();\n        rp.pol.wDeg = 0.4 + 5.0 * rr.next_double();\n        rp.pol.wPair = 0.0 + 1.8 * rr.next_double();\n        rp.pol.wRand = 0.0 + 10.0 * rr.next_double();\n        rp.pol.eps = 0.00 + 0.12 * rr.next_double();\n        rp.pol.deadPenalty = 0.0 + 28.0 * rr.next_double();\n\n        double q = rr.next_double();\n        if (q < 0.70) rp.evalRollouts = 1;\n        else if (q < 0.95) rp.evalRollouts = 2;\n        else rp.evalRollouts = 3;\n\n        // pilot style mostly full playout\n        if (rr.next_double() < 0.75) rp.evalDepth = 0;\n        else rp.evalDepth = 60 + rr.next_int(0, 140);\n\n        rp.mixBest = 0.35 + 0.60 * rr.next_double();\n        rp.evalNoise = 0.0 + 60.0 * rr.next_double();\n        return rp;\n    };\n\n    // baseline\n    RunParam base;\n    base.pol = Policy{1.4, 0.8, 2.8, 0.5, 2.0, 0.02, 14.0};\n    base.evalRollouts = 2;\n    base.evalDepth = 0;  // full\n    base.mixBest = 0.65;\n    base.evalNoise = 0.0;\n\n    Result best = simulate(base, nullptr, 0, rng, deadline);\n\n    vector<Result> elites;\n    elites.push_back(best);\n\n    auto better = [](const Result& a, const Result& b) {\n        if (a.score != b.score) return a.score > b.score;\n        return a.path.size() > b.path.size();\n    };\n\n    auto pushElite = [&](Result&& r) {\n        elites.push_back(std::move(r));\n        sort(elites.begin(), elites.end(), better);\n\n        vector<Result> tmp;\n        tmp.reserve(elites.size());\n        for (auto& e : elites) {\n            bool dup = false;\n            for (auto& f : tmp) {\n                if (e.path == f.path) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) tmp.push_back(std::move(e));\n        }\n        elites.swap(tmp);\n\n        const int K = 8;\n        if ((int)elites.size() > K) elites.resize(K);\n    };\n\n    while (Clock::now() < deadline) {\n        RunParam rp = randomParam(rng);\n\n        const string* basePath = nullptr;\n        int cut = 0;\n\n        if (!elites.empty() && rng.next_double() < 0.72) {\n            int top = min<int>((int)elites.size(), 5);\n            double rsel = rng.next_double();\n            int idx = int(rsel * rsel * top);\n            if (idx >= top) idx = top - 1;\n\n            basePath = &elites[idx].path;\n            int L = (int)basePath->size();\n            if (L > 0) {\n                double rc = rng.next_double();\n                if (rc < 0.55) {\n                    int lo = max(0, L - 220);\n                    cut = rng.next_int(lo, L);\n                } else if (rc < 0.88) {\n                    int lo = max(0, L - 700);\n                    cut = rng.next_int(lo, L);\n                } else {\n                    cut = rng.next_int(0, L);\n                }\n            }\n        }\n\n        Result cur = simulate(rp, basePath, cut, rng, deadline);\n\n        if (better(cur, best)) best = cur;\n        pushElite(std::move(cur));\n    }\n\n    cout << best.path << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr int Q = 1000;\n\n    static constexpr double COST_MIN = 1000.0;\n    static constexpr double COST_MAX = 9000.0;\n\n    static constexpr double PRIOR_CNT = 1.0;\n    static constexpr double DELTA_CLIP = 4200.0;\n\n    static constexpr int WARMUP_MONO = 45;\n    static constexpr int REFIT_INTERVAL = 20;\n\n    using HMatD = array<array<double, N - 1>, N>;\n    using VMatD = array<array<double, N>, N - 1>;\n    using HMatI = array<array<int, N - 1>, N>;\n    using VMatI = array<array<int, N>, N - 1>;\n\n    struct EdgeRef {\n        bool horiz; // true: H edge, false: V edge\n        int i, j;\n    };\n\n    struct FitInfo {\n        double mean1 = 5000.0;\n        int split = -1; // 1..28\n        double meanL = 5000.0;\n        double meanR = 5000.0;\n        double ratio = 0.0; // (sse1 - sse2) / sse1\n        double diff = 0.0;  // |meanL - meanR|\n        int cLeft = 0;\n        int cRight = 0;\n    };\n\n    // Base model (piecewise line parameters)\n    array<double, N> row0{}, row1{}, col0{}, col1{};\n    array<int, N> rowSplit{}, colSplit{}; // split=29 => effectively 1 segment\n\n    // Local residuals\n    HMatD deltaH{};\n    VMatD deltaV{};\n\n    // Visit counts\n    HMatI cntH{};\n    VMatI cntV{};\n\n    bool m2Likely = false;\n\n    mt19937 rng;\n    uniform_real_distribution<double> urd;\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 int vid(int i, int j) { return i * N + j; }\n\n    double rndSym() {\n        return urd(rng) * 2.0 - 1.0;\n    }\n\n    inline double baseH(int i, int j) const {\n        return (j < rowSplit[i]) ? row0[i] : row1[i];\n    }\n\n    inline double baseV(int i, int j) const {\n        return (i < colSplit[j]) ? col0[j] : col1[j];\n    }\n\n    inline double edgeEstH(int i, int j) const {\n        double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n        double c = baseH(i, j) + sh * deltaH[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    inline double edgeEstV(int i, int j) const {\n        double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n        double c = baseV(i, j) + sh * deltaV[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    string directPath(int si, int sj, int ti, int tj) const {\n        string p;\n        if (ti > si) p.append(ti - si, 'D');\n        else p.append(si - ti, 'U');\n        if (tj > sj) p.append(tj - sj, 'R');\n        else p.append(sj - tj, 'L');\n        return p;\n    }\n\n    void buildCostTables(int q, HMatD& baseHMat, VMatD& baseVMat, HMatD& searchHMat, VMatD& searchVMat) {\n        double stepPenalty = (q < 140) ? (180.0 * (140 - q) / 140.0) : 0.0;\n        double bonusCoef = (q < 240) ? (360.0 * (240 - q) / 240.0) : 0.0;\n        double jitter = (q < 220) ? (0.025 * (220 - q) / 220.0) : 0.0;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                double b = edgeEstH(i, j);\n                baseHMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntH[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchHMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                double b = edgeEstV(i, j);\n                baseVMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntV[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchVMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n    }\n\n    string dijkstraPath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        constexpr double INF = 1e100;\n        array<double, N * N> dist;\n        array<int, N * N> prv;\n        array<char, N * N> pmv;\n        dist.fill(INF);\n        prv.fill(-1);\n        pmv.fill(0);\n\n        int S = vid(si, sj), T = vid(ti, tj);\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[S] = 0.0;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == T) break;\n\n            int i = u / N, j = u % N;\n\n            if (i > 0) {\n                int to = vid(i - 1, j);\n                double nd = d + v[i - 1][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'U';\n                    pq.push({nd, to});\n                }\n            }\n            if (i + 1 < N) {\n                int to = vid(i + 1, j);\n                double nd = d + v[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'D';\n                    pq.push({nd, to});\n                }\n            }\n            if (j > 0) {\n                int to = vid(i, j - 1);\n                double nd = d + h[i][j - 1];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'L';\n                    pq.push({nd, to});\n                }\n            }\n            if (j + 1 < N) {\n                int to = vid(i, j + 1);\n                double nd = d + h[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'R';\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        if (prv[T] == -1) return directPath(si, sj, ti, tj);\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmv[cur]);\n            cur = prv[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Best among monotone-only paths (length = Manhattan)\n    string bestMonotoneDP(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        if (si == ti && sj == tj) return \"\";\n\n        int di = (ti > si) ? 1 : (ti < si ? -1 : 0);\n        int dj = (tj > sj) ? 1 : (tj < sj ? -1 : 0);\n\n        int R = abs(ti - si) + 1;\n        int C = abs(tj - sj) + 1;\n\n        const double INF = 1e100;\n        vector<vector<double>> dp(R, vector<double>(C, INF));\n        vector<vector<char>> pre(R, vector<char>(C, 0));\n        dp[0][0] = 0.0;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = 0; b < C; b++) {\n                if (dp[a][b] >= INF / 2) continue;\n                int i = si + di * a;\n                int j = sj + dj * b;\n\n                if (a + 1 < R) {\n                    double w = (di == 1) ? v[i][j] : v[i - 1][j];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a + 1][b]) {\n                        dp[a + 1][b] = nd;\n                        pre[a + 1][b] = 'V';\n                    }\n                }\n                if (b + 1 < C) {\n                    double w = (dj == 1) ? h[i][j] : h[i][j - 1];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a][b + 1]) {\n                        dp[a][b + 1] = nd;\n                        pre[a][b + 1] = 'H';\n                    }\n                }\n            }\n        }\n\n        string path;\n        int a = R - 1, b = C - 1;\n        while (a > 0 || b > 0) {\n            char p = pre[a][b];\n            if (p == 'V') {\n                path.push_back(di == 1 ? 'D' : 'U');\n                --a;\n            } else {\n                path.push_back(dj == 1 ? 'R' : 'L');\n                --b;\n            }\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Warmup monotone exploration\n    string biasedMonotonePath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) {\n        int i = si, j = sj;\n        string path;\n        path.reserve(abs(ti - si) + abs(tj - sj));\n\n        while (i != ti || j != tj) {\n            bool canV = (i != ti);\n            bool canH = (j != tj);\n\n            if (canV && canH) {\n                double cv, ch;\n                int nv, nh;\n\n                if (ti > i) { // D\n                    cv = v[i][j];\n                    nv = cntV[i][j];\n                } else {      // U\n                    cv = v[i - 1][j];\n                    nv = cntV[i - 1][j];\n                }\n\n                if (tj > j) { // R\n                    ch = h[i][j];\n                    nh = cntH[i][j];\n                } else {      // L\n                    ch = h[i][j - 1];\n                    nh = cntH[i][j - 1];\n                }\n\n                double sv = (1.0 / (cv + 1e-9)) * (1.0 + 1.2 / sqrt(nv + 1.0));\n                double sh = (1.0 / (ch + 1e-9)) * (1.0 + 1.2 / sqrt(nh + 1.0));\n\n                double r = urd(rng) * (sv + sh);\n                if (r < sv) {\n                    if (ti > i) { path.push_back('D'); ++i; }\n                    else { path.push_back('U'); --i; }\n                } else {\n                    if (tj > j) { path.push_back('R'); ++j; }\n                    else { path.push_back('L'); --j; }\n                }\n            } else if (canV) {\n                if (ti > i) { path.push_back('D'); ++i; }\n                else { path.push_back('U'); --i; }\n            } else {\n                if (tj > j) { path.push_back('R'); ++j; }\n                else { path.push_back('L'); --j; }\n            }\n        }\n\n        return path;\n    }\n\n    void pathToEdges(\n        int si, int sj, const string& path, vector<EdgeRef>& edges,\n        array<int, N>& row0Cnt, array<int, N>& row1Cnt,\n        array<int, N>& col0Cnt, array<int, N>& col1Cnt\n    ) const {\n        row0Cnt.fill(0);\n        row1Cnt.fill(0);\n        col0Cnt.fill(0);\n        col1Cnt.fill(0);\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int i = si, j = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                --i;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                ++i;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                --j;\n            } else { // 'R'\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                ++j;\n            }\n        }\n    }\n\n    FitInfo fitLine29(const array<double, N - 1>& val, const array<int, N - 1>& cnt) const {\n        const double W0 = 0.35;\n\n        array<double, N> pw{}, ps{}, ps2{};\n        array<int, N> pc{};\n        for (int k = 0; k < N - 1; k++) {\n            double w = cnt[k] + W0;\n            double x = val[k];\n            pw[k + 1] = pw[k] + w;\n            ps[k + 1] = ps[k] + w * x;\n            ps2[k + 1] = ps2[k] + w * x * x;\n            pc[k + 1] = pc[k] + cnt[k];\n        }\n\n        FitInfo f;\n\n        double W = pw[N - 1];\n        double S = ps[N - 1];\n        double Qv = ps2[N - 1];\n        if (W <= 1e-12) {\n            f.mean1 = 5000.0;\n            return f;\n        }\n\n        f.mean1 = S / W;\n        double sse1 = max(0.0, Qv - S * S / W);\n\n        double bestSSE = 1e100;\n        int bestS = -1;\n        double bestL = f.mean1, bestR = f.mean1;\n\n        for (int s = 1; s <= N - 2; s++) { // 1..28\n            double WL = pw[s], WR = pw[N - 1] - pw[s];\n            if (WL <= 1e-12 || WR <= 1e-12) continue;\n\n            double SL = ps[s], SR = ps[N - 1] - ps[s];\n            double QL = ps2[s], QR = ps2[N - 1] - ps2[s];\n\n            double mL = SL / WL, mR = SR / WR;\n            double sse = max(0.0, QL - SL * SL / WL) + max(0.0, QR - SR * SR / WR);\n\n            if (sse < bestSSE) {\n                bestSSE = sse;\n                bestS = s;\n                bestL = mL;\n                bestR = mR;\n            }\n        }\n\n        f.split = bestS;\n        if (bestS == -1) {\n            f.meanL = f.meanR = f.mean1;\n            f.ratio = 0.0;\n            f.diff = 0.0;\n            return f;\n        }\n\n        f.meanL = bestL;\n        f.meanR = bestR;\n        f.diff = fabs(bestL - bestR);\n        f.cLeft = pc[bestS];\n        f.cRight = pc[N - 1] - pc[bestS];\n        f.ratio = (sse1 - bestSSE) / max(1.0, sse1);\n        if (f.ratio < 0.0) f.ratio = 0.0;\n\n        return f;\n    }\n\n    void refitStructure(int q) {\n        // 1) Current effective estimates\n        HMatD effH;\n        VMatD effV;\n        for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) effH[i][j] = edgeEstH(i, j);\n        for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) effV[i][j] = edgeEstV(i, j);\n\n        // 2) Fit each row/column as 1-seg vs best 2-seg\n        array<FitInfo, N> rowFit, colFit;\n\n        for (int i = 0; i < N; i++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int j = 0; j < N - 1; j++) {\n                val[j] = effH[i][j];\n                cnt[j] = cntH[i][j];\n            }\n            rowFit[i] = fitLine29(val, cnt);\n        }\n\n        for (int j = 0; j < N; j++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int i = 0; i < N - 1; i++) {\n                val[i] = effV[i][j];\n                cnt[i] = cntV[i][j];\n            }\n            colFit[j] = fitLine29(val, cnt);\n        }\n\n        // 3) Infer whether M=2 is likely globally\n        int strong = 0, considered = 0;\n        auto countStrong = [&](const FitInfo& f) {\n            if (f.split < 1 || f.split > N - 2) return;\n            int mc = min(f.cLeft, f.cRight);\n            if (mc < 5) return;\n            considered++;\n            if (f.ratio > 0.09 && f.diff > 500.0) strong++;\n        };\n        for (int i = 0; i < N; i++) countStrong(rowFit[i]);\n        for (int j = 0; j < N; j++) countStrong(colFit[j]);\n\n        if (q >= 70 && considered >= 20) {\n            if (strong >= 18) m2Likely = true;\n            else if (strong <= 8) m2Likely = false;\n        }\n\n        auto useTwoSeg = [&](const FitInfo& f) -> bool {\n            if (f.split < 1 || f.split > N - 2) return false;\n            if (q < 55) return false;\n            int mc = min(f.cLeft, f.cRight);\n\n            if (m2Likely) {\n                double thrRatio = (q < 220) ? 0.07 : 0.045;\n                double thrDiff = (q < 220) ? 450.0 : 300.0;\n                int thrCnt = (q < 220) ? 5 : 3;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            } else {\n                // strict mode for likely M=1, but allow very strong evidence\n                if (f.ratio > 0.22 && f.diff > 1200.0 && mc >= 8) return true;\n                double thrRatio = (q < 320) ? 0.16 : 0.12;\n                double thrDiff = (q < 320) ? 800.0 : 650.0;\n                int thrCnt = (q < 320) ? 10 : 7;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            }\n        };\n\n        // 4) Update base model\n        for (int i = 0; i < N; i++) {\n            const auto& f = rowFit[i];\n            if (useTwoSeg(f)) {\n                rowSplit[i] = f.split;\n                row0[i] = clampd(f.meanL, COST_MIN, COST_MAX);\n                row1[i] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                rowSplit[i] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                row0[i] = m;\n                row1[i] = m;\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            const auto& f = colFit[j];\n            if (useTwoSeg(f)) {\n                colSplit[j] = f.split;\n                col0[j] = clampd(f.meanL, COST_MIN, COST_MAX);\n                col1[j] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                colSplit[j] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                col0[j] = m;\n                col1[j] = m;\n            }\n        }\n\n        // 5) Re-center local residuals around the new base\n        //    (trusted edges mostly preserved; low-count edges pulled to new base)\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                if (cntH[i][j] == 0) {\n                    deltaH[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseH(i, j);\n                double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaH[i][j] = clampd((effH[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                if (cntV[i][j] == 0) {\n                    deltaV[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseV(i, j);\n                double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaV[i][j] = clampd((effV[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n    }\n\npublic:\n    Solver() : rng(20240315), urd(0.0, 1.0) {\n        row0.fill(5000.0);\n        row1.fill(5000.0);\n        col0.fill(5000.0);\n        col1.fill(5000.0);\n        rowSplit.fill(N - 1);\n        colSplit.fill(N - 1);\n\n        for (auto& r : deltaH) r.fill(0.0);\n        for (auto& r : deltaV) r.fill(0.0);\n        for (auto& r : cntH) r.fill(0);\n        for (auto& r : cntV) r.fill(0);\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int q = 0; q < Q; q++) {\n            if (q > 0 && q % REFIT_INTERVAL == 0) {\n                refitStructure(q);\n            }\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            HMatD baseHMat, searchHMat;\n            VMatD baseVMat, searchVMat;\n            buildCostTables(q, baseHMat, baseVMat, searchHMat, searchVMat);\n\n            string path;\n            if (q < WARMUP_MONO) {\n                path = biasedMonotonePath(si, sj, ti, tj, baseHMat, baseVMat);\n            } else {\n                path = dijkstraPath(si, sj, ti, tj, searchHMat, searchVMat);\n\n                int md = abs(si - ti) + abs(sj - tj);\n                int detourLimit = (q < 200) ? 10 : 16;\n                if ((int)path.size() > md + detourLimit) {\n                    path = bestMonotoneDP(si, sj, ti, tj, baseHMat, baseVMat);\n                }\n            }\n\n            cout << path << '\\n' << flush;\n\n            int obsInt;\n            if (!(cin >> obsInt)) return;\n            if (obsInt < 0) return; // interactive guard\n            double obs = static_cast<double>(obsInt);\n\n            vector<EdgeRef> edges;\n            array<int, N> row0Cnt, row1Cnt, col0Cnt, col1Cnt;\n            pathToEdges(si, sj, path, edges, row0Cnt, row1Cnt, col0Cnt, col1Cnt);\n\n            if (edges.empty()) continue;\n\n            // Prediction before update\n            double pred = 0.0;\n            for (const auto& e : edges) {\n                pred += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double err = obs - pred;\n\n            // Segment-level base update\n            double norm = 1e-9;\n            for (int i = 0; i < N; i++) {\n                norm += 1.0 * row0Cnt[i] * row0Cnt[i];\n                norm += 1.0 * row1Cnt[i] * row1Cnt[i];\n            }\n            for (int j = 0; j < N; j++) {\n                norm += 1.0 * col0Cnt[j] * col0Cnt[j];\n                norm += 1.0 * col1Cnt[j] * col1Cnt[j];\n            }\n\n            double etaBase = 0.40 * exp(-0.0022 * q) + 0.06;\n\n            for (int i = 0; i < N; i++) {\n                if (row0Cnt[i]) {\n                    row0[i] += etaBase * err * row0Cnt[i] / norm;\n                    row0[i] = clampd(row0[i], COST_MIN, COST_MAX);\n                }\n                if (row1Cnt[i]) {\n                    row1[i] += etaBase * err * row1Cnt[i] / norm;\n                    row1[i] = clampd(row1[i], COST_MIN, COST_MAX);\n                }\n            }\n            for (int j = 0; j < N; j++) {\n                if (col0Cnt[j]) {\n                    col0[j] += etaBase * err * col0Cnt[j] / norm;\n                    col0[j] = clampd(col0[j], COST_MIN, COST_MAX);\n                }\n                if (col1Cnt[j]) {\n                    col1[j] += etaBase * err * col1Cnt[j] / norm;\n                    col1[j] = clampd(col1[j], COST_MIN, COST_MAX);\n                }\n            }\n\n            // Residual after base update\n            double pred2 = 0.0;\n            for (const auto& e : edges) {\n                pred2 += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double residual = obs - pred2;\n\n            // Local residual update (uncertainty weighted)\n            double etaDelta = 0.60 * exp(-0.0015 * q) + 0.18;\n\n            vector<double> w(edges.size());\n            double sw = 0.0;\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                int c = e.horiz ? cntH[e.i][e.j] : cntV[e.i][e.j];\n                w[idx] = 1.0 / sqrt(c + 1.0);\n                sw += w[idx];\n            }\n            if (sw < 1e-12) sw = 1.0;\n\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                double d = etaDelta * residual * w[idx] / sw;\n                if (e.horiz) {\n                    deltaH[e.i][e.j] = clampd(deltaH[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntH[e.i][e.j]++;\n                } else {\n                    deltaV[e.i][e.j] = clampd(deltaV[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntV[e.i][e.j]++;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M;\n    int CELL, PPS, P;\n    vector<vector<uint8_t>> strs;\n    vector<uint8_t> len;\n    vector<int> groupLen;\n    vector<vector<uint32_t>> cellEntries; // packed: (pid << 3) | req(0..7)\n\n    vector<int16_t> matchCount;           // [0..12]\n    vector<array<int,13>> hist;           // hist[sid][match]\n    vector<uint8_t> best;                 // best match per string\n\n    vector<uint8_t> grid;\n    vector<uint8_t> bestGlobalGrid;\n    int bestGlobalC = -1;\n    int bestGlobalSoft = -1;\n\n    int g1[13];\n    int scoreTbl[13][13];\n\n    vector<int> order;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 2.90; // keep some safety margin from 3.0\n\n    Solver(int N_, int M_, const vector<string>& S): N(N_), M(M_) {\n        CELL = N * N;\n        PPS = 2 * CELL;\n        P = M * PPS;\n\n        strs.resize(M);\n        len.resize(M);\n        groupLen.resize(M);\n\n        for (int i = 0; i < M; i++) {\n            len[i] = (uint8_t)S[i].size();\n            groupLen[i] = 2 * (int)len[i];\n            strs[i].resize(len[i]);\n            for (int j = 0; j < (int)len[i]; j++) strs[i][j] = (uint8_t)(S[i][j] - 'A');\n        }\n\n        cellEntries.assign(CELL, {});\n        buildEntries();\n\n        matchCount.assign(P, 0);\n        hist.resize(M);\n        for (auto &a : hist) a.fill(0);\n        best.assign(M, 0);\n\n        grid.assign(CELL, 0);\n        bestGlobalGrid.assign(CELL, 0);\n\n        order.resize(CELL);\n        iota(order.begin(), order.end(), 0);\n\n        g1[0] = 1;\n        for (int i = 1; i <= 12; i++) g1[i] = g1[i-1] << 1;\n\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        rng.seed((uint32_t)(seed ^ (uint64_t(M) << 21) ^ uint64_t(P)));\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void buildEntries() {\n        int perCell = 0;\n        for (int i = 0; i < M; i++) perCell += groupLen[i];\n        for (int c = 0; c < CELL; c++) cellEntries[c].reserve(perCell);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            int k = len[sid];\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    int start = r * N + c;\n                    int pidH = base + start;\n                    int pidV = base + CELL + start;\n                    for (int p = 0; p < k; p++) {\n                        uint32_t req = strs[sid][p];\n                        int ch = r * N + ((c + p) % N);\n                        int cv = ((r + p) % N) * N + c;\n                        cellEntries[ch].push_back((uint32_t(pidH) << 3) | req);\n                        cellEntries[cv].push_back((uint32_t(pidV) << 3) | req);\n                    }\n                }\n            }\n        }\n    }\n\n    void initRandomGrid() {\n        for (int i = 0; i < CELL; i++) grid[i] = (uint8_t)(rng() & 7);\n    }\n\n    void recomputeMatchCount() {\n        fill(matchCount.begin(), matchCount.end(), 0);\n        for (int cell = 0; cell < CELL; cell++) {\n            int ch = grid[cell];\n            if (ch > 7) continue;\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                if ((int)(x & 7u) == ch) {\n                    int pid = (int)(x >> 3);\n                    matchCount[pid]++;\n                }\n            }\n        }\n    }\n\n    int phase1Sweep() {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int cell : order) {\n            int old = grid[cell];\n            long long bonus[8] = {0,0,0,0,0,0,0,0};\n\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n                int base = mc - ((old == req) ? 1 : 0);\n                bonus[req] += (long long)g1[base + 1] - g1[base];\n            }\n\n            int nw = old;\n            long long bestv = bonus[old];\n            for (int a = 0; a < 8; a++) {\n                if (bonus[a] > bestv) {\n                    bestv = bonus[a];\n                    nw = a;\n                }\n            }\n            if (nw == old) continue;\n\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                if (req == old) {\n                    if (req != nw) matchCount[pid]--;\n                } else if (req == nw) {\n                    matchCount[pid]++;\n                }\n            }\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildHistBest() {\n        for (int sid = 0; sid < M; sid++) hist[sid].fill(0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            for (int t = 0; t < PPS; t++) {\n                int mc = matchCount[base + t];\n                hist[sid][mc]++;\n            }\n        }\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = k;\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    void refreshBestAll() {\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            while (b < k && hist[sid][b + 1] > 0) b++;\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    inline int calcC() const {\n        int c = 0;\n        for (int sid = 0; sid < M; sid++) if (best[sid] == len[sid]) c++;\n        return c;\n    }\n\n    inline int calcSoft() const {\n        int s = 0;\n        for (int sid = 0; sid < M; sid++) s += best[sid];\n        return s;\n    }\n\n    void updateGlobal() {\n        int c = calcC();\n        int soft = calcSoft();\n        if (c > bestGlobalC || (c == bestGlobalC && soft > bestGlobalSoft)) {\n            bestGlobalC = c;\n            bestGlobalSoft = soft;\n            bestGlobalGrid = grid;\n        }\n    }\n\n    void buildScoreTbl(int bonusFull) {\n        for (int k = 0; k <= 12; k++) {\n            for (int b = 0; b <= 12; b++) {\n                if (b > k) scoreTbl[k][b] = -1000000000;\n                else scoreTbl[k][b] = b * b + ((b == k) ? bonusFull : 0);\n            }\n        }\n    }\n\n    int chooseLetterPhase2(int cell) {\n        int old = grid[cell];\n        long long delta[8] = {0,0,0,0,0,0,0,0};\n\n        const auto &vec = cellEntries[cell];\n        int pos = 0;\n\n        // Entries are grouped by sid (build order is sid-major),\n        // and each sid contributes exactly 2*len[sid] entries for every cell.\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            int gsz = groupLen[sid];\n\n            int cnt[8][3] = {}; // [req][0:b-1, 1:b, 2:b+1]\n\n            for (int t = 0; t < gsz; t++) {\n                uint32_t x = vec[pos + t];\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n\n                if (b > 0 && mc == b - 1) cnt[req][0]++;\n                if (mc == b) cnt[req][1]++;\n                if (b < k && mc == b + 1) cnt[req][2]++;\n            }\n            pos += gsz;\n\n            int baseScore = scoreTbl[k][b];\n            int hb = hist[sid][b];\n            int hbp1 = (b < k ? hist[sid][b + 1] : 0);\n\n            int old0 = cnt[old][1];\n            int oldp1 = cnt[old][2];\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                int nb;\n\n                if (b < k) {\n                    int cb1 = hbp1 - oldp1 + cnt[a][1];\n                    if (cb1 > 0) {\n                        nb = b + 1;\n                    } else {\n                        int cb = hb - old0 + oldp1 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                        nb = (cb > 0 ? b : b - 1);\n                        if (nb < 0) nb = 0;\n                    }\n                } else {\n                    int cb = hb - old0 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                    nb = (cb > 0 ? b : b - 1);\n                    if (nb < 0) nb = 0;\n                }\n\n                delta[a] += (long long)scoreTbl[k][nb] - baseScore;\n            }\n        }\n\n        int nw = old;\n        long long bestD = 0;\n        for (int a = 0; a < 8; a++) {\n            if (delta[a] > bestD) {\n                bestD = delta[a];\n                nw = a;\n            }\n        }\n        return nw;\n    }\n\n    int phase2Sweep() {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int cell : order) {\n            int old = grid[cell];\n            int nw = chooseLetterPhase2(cell);\n            if (nw == old) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        if (req != nw) {\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc - 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc - 1]++;\n                        }\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc + 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc + 1]++;\n                    }\n                }\n                pos += gsz;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            refreshBestAll();\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void runOne(double deadline) {\n        initRandomGrid();\n        recomputeMatchCount();\n\n        // Phase 1: smoother objective on all placements\n        for (int s = 0; s < 6; s++) {\n            if (elapsed() >= deadline) return;\n            int ch = phase1Sweep();\n            if (ch == 0) break;\n        }\n\n        if (elapsed() >= deadline) return;\n        buildHistBest();\n        updateGlobal();\n\n        // Phase 2: closer-to-score objective\n        const int stageBonus[] = {0, 200, 100000};\n        const int stageSweep[] = {3, 4, 3};\n\n        for (int st = 0; st < 3; st++) {\n            buildScoreTbl(stageBonus[st]);\n            for (int it = 0; it < stageSweep[st]; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep();\n                updateGlobal();\n                if (ch == 0) break;\n            }\n        }\n\n        // Extra polishing with strong full-match bonus\n        buildScoreTbl(100000);\n        while (elapsed() < deadline) {\n            int ch = phase2Sweep();\n            updateGlobal();\n            if (ch == 0) break;\n        }\n    }\n\n    void dotPostprocessIfPossible() {\n        if (bestGlobalC != M) return;\n        if (elapsed() > TL - 0.03) return;\n\n        grid = bestGlobalGrid;\n        recomputeMatchCount();\n        buildHistBest();\n        if (calcC() != M) return; // safety\n\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int cell : order) {\n            if (elapsed() > TL - 0.005) break;\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            bool touched = false;\n\n            // Try old -> '.'\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    if (req == old) {\n                        int pid = (int)(x >> 3);\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                        touched = true;\n                    }\n                }\n                pos += gsz;\n            }\n\n            if (!touched) {\n                grid[cell] = 8;\n                continue;\n            }\n\n            refreshBestAll();\n            if (calcC() == M) {\n                grid[cell] = 8; // keep '.'\n            } else {\n                // Revert\n                pos = 0;\n                for (int sid = 0; sid < M; sid++) {\n                    int gsz = groupLen[sid];\n                    for (int t = 0; t < gsz; t++) {\n                        uint32_t x = vec[pos + t];\n                        int req = (int)(x & 7u);\n                        if (req == old) {\n                            int pid = (int)(x >> 3);\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc + 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc + 1]++;\n                        }\n                    }\n                    pos += gsz;\n                }\n                refreshBestAll();\n            }\n        }\n\n        bestGlobalGrid = grid;\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        int restart = 0;\n        while (true) {\n            double now = elapsed();\n            double rem = TL - now;\n            if (rem < 0.15) break;\n\n            double budget = (restart == 0 ? min(1.6, rem - 0.02) : min(1.0, rem - 0.02));\n            if (budget < 0.10) break;\n\n            runOne(now + budget);\n            restart++;\n        }\n\n        if (bestGlobalC < 0) {\n            initRandomGrid();\n            bestGlobalGrid = grid;\n            bestGlobalC = 0;\n        }\n\n        dotPostprocessIfPossible();\n    }\n\n    void output() const {\n        for (int r = 0; r < N; r++) {\n            string line(N, '.');\n            for (int c = 0; c < N; c++) {\n                int v = bestGlobalGrid[r * N + c];\n                if (0 <= v && v < 8) line[c] = char('A' + v);\n                else line[c] = '.';\n            }\n            cout << line << '\\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<string> S(M);\n    for (int i = 0; i < M; i++) cin >> S[i];\n\n    Solver solver(N, M, S);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    using ull = unsigned long long;\n    static constexpr int INF = 1e9;\n\n    inline static constexpr int DI[4] = {-1, 1, 0, 0};\n    inline static constexpr int DJ[4] = {0, 0, -1, 1};\n    inline static constexpr char MV[4] = {'U', 'D', 'L', 'R'};\n    inline static constexpr int OPP[4] = {1, 0, 3, 2};\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0;\n    int startRid = -1;\n    vector<vector<int>> id;     // grid -> road id\n    vector<int> ri, rj;         // road id -> row,col\n    vector<int> enterCost;      // road id -> entering cost (5..9)\n    vector<array<int,4>> nbr;   // road graph neighbors by dir\n\n    int B = 0;\n    vector<ull> allBits;                // all road bits\n    vector<vector<ull>> roadVisBits;    // road id -> visibility bitset\n\n    vector<int> candRid;                // candidate index -> road id\n    vector<vector<int>> candVisList;    // candidate index -> visible road-id list\n    vector<char> inCand;                // road id flag\n\n    vector<vector<int>> distC;          // candidate -> candidate dist\n    vector<vector<int>> prevFrom;       // candidate -> prev road-id table (for path reconstruction)\n\n    chrono::steady_clock::time_point t0;\n\n    long long elapsed_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - t0\n        ).count();\n    }\n\n    void read_input() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void build_graph() {\n        id.assign(N, vector<int>(N, -1));\n        ri.clear(); rj.clear(); enterCost.clear();\n\n        R = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    ri.push_back(i);\n                    rj.push_back(j);\n                    enterCost.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n        startRid = id[si][sj];\n\n        nbr.assign(R, array<int,4>{-1,-1,-1,-1});\n        for (int u = 0; u < R; u++) {\n            int i = ri[u], j = rj[u];\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                    nbr[u][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void init_bits() {\n        B = (R + 63) >> 6;\n        allBits.assign(B, ~0ULL);\n        if (B > 0 && (R & 63)) {\n            allBits.back() = (1ULL << (R & 63)) - 1ULL;\n        }\n    }\n\n    void build_road_visibility() {\n        roadVisBits.assign(R, vector<ull>(B, 0ULL));\n\n        for (int rid = 0; rid < R; rid++) {\n            auto &bits = roadVisBits[rid];\n            auto add = [&](int v) {\n                bits[v >> 6] |= (1ULL << (v & 63));\n            };\n\n            int i = ri[rid], j = rj[rid];\n            add(rid);\n\n            for (int y = j - 1; y >= 0; y--) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int y = j + 1; y < N; y++) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i - 1; x >= 0; x--) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i + 1; x < N; x++) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n        }\n    }\n\n    vector<int> bits_to_list(const vector<ull>& bits) const {\n        vector<int> res;\n        for (int b = 0; b < B; b++) {\n            ull x = bits[b];\n            while (x) {\n                int t = __builtin_ctzll(x);\n                int v = (b << 6) + t;\n                if (v < R) res.push_back(v);\n                x &= (x - 1);\n            }\n        }\n        return res;\n    }\n\n    void build_candidates() {\n        candRid.clear();\n        candVisList.clear();\n        inCand.assign(R, 0);\n\n        auto add_candidate = [&](int rid) {\n            if (inCand[rid]) return;\n            inCand[rid] = 1;\n            candRid.push_back(rid);\n            candVisList.push_back(bits_to_list(roadVisBits[rid]));\n        };\n\n        // start must be candidate[0]\n        add_candidate(startRid);\n\n        for (int u = 0; u < R; u++) {\n            if (u == startRid) continue;\n\n            int deg = 0;\n            for (int d = 0; d < 4; d++) if (nbr[u][d] != -1) deg++;\n\n            bool isCand = false;\n            if (deg != 2) {\n                isCand = true; // branch/end\n            } else {\n                bool U = (nbr[u][0] != -1);\n                bool D = (nbr[u][1] != -1);\n                bool L = (nbr[u][2] != -1);\n                bool Rr = (nbr[u][3] != -1);\n                bool straight = (U && D) || (L && Rr);\n                isCand = !straight; // turn\n            }\n\n            if (isCand) add_candidate(u);\n        }\n\n        // Safety: ensure every road cell is visible from at least one candidate.\n        vector<ull> uni(B, 0ULL);\n        for (int c = 0; c < (int)candRid.size(); c++) {\n            const auto &vb = roadVisBits[candRid[c]];\n            for (int b = 0; b < B; b++) uni[b] |= vb[b];\n        }\n\n        for (int b = 0; b < B; b++) {\n            ull miss = allBits[b] & (~uni[b]);\n            while (miss) {\n                int t = __builtin_ctzll(miss);\n                int rid = (b << 6) + t;\n                if (rid < R) add_candidate(rid);\n                miss &= (miss - 1);\n            }\n        }\n    }\n\n    void dijkstra_from_rid(int srcRid, vector<int>& dist, vector<int>& prev) {\n        dist.assign(R, INF);\n        prev.assign(R, -1);\n\n        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n        dist[srcRid] = 0;\n        prev[srcRid] = srcRid;\n        pq.push({0, srcRid});\n\n        while (!pq.empty()) {\n            auto [du, u] = pq.top();\n            pq.pop();\n            if (du != dist[u]) continue;\n\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1) continue;\n                int nd = du + enterCost[v];\n                if (nd < dist[v] || (nd == dist[v] && (prev[v] == -1 || u < prev[v]))) {\n                    dist[v] = nd;\n                    prev[v] = u;\n                    pq.push({nd, v});\n                }\n            }\n        }\n    }\n\n    void precompute_shortest_paths() {\n        int C = (int)candRid.size();\n        distC.assign(C, vector<int>(C, INF));\n        prevFrom.assign(C, vector<int>(R, -1));\n\n        vector<int> dist, prev;\n        for (int s = 0; s < C; s++) {\n            dijkstra_from_rid(candRid[s], dist, prev);\n            prevFrom[s].swap(prev);\n            for (int t = 0; t < C; t++) {\n                distC[s][t] = dist[candRid[t]];\n            }\n        }\n    }\n\n    inline int edge_cost(int a, int b) const {\n        return distC[a][b];\n    }\n\n    bool bits_empty(const vector<ull>& bits) const {\n        for (ull x : bits) if (x) return false;\n        return true;\n    }\n\n    int gain_for_candidate(int cidx, const vector<ull>& unc) const {\n        const auto &vb = roadVisBits[candRid[cidx]];\n        int g = 0;\n        for (int b = 0; b < B; b++) {\n            g += __builtin_popcountll(vb[b] & unc[b]);\n        }\n        return g;\n    }\n\n    struct Choice {\n        double score;\n        int cidx;\n        int pos;\n        int gain;\n        int inc;\n    };\n\n    vector<int> build_cycle_cover(double alpha, double beta, int topk, double noise, XorShift64& rng) {\n        int C = (int)candRid.size();\n        vector<int> seq = {0}; // candidate index\n        vector<char> used(C, 0);\n        used[0] = 1;\n\n        vector<ull> unc = allBits;\n        {\n            const auto &vb = roadVisBits[candRid[0]];\n            for (int b = 0; b < B; b++) unc[b] &= ~vb[b];\n        }\n\n        while (!bits_empty(unc)) {\n            vector<Choice> top;\n            top.reserve(topk + 1);\n            int m = (int)seq.size();\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n                int gain = gain_for_candidate(c, unc);\n                if (gain == 0) continue;\n\n                int incMin = INF;\n                int bestPos = 0;\n\n                if (m == 1) {\n                    incMin = edge_cost(0, c) + edge_cost(c, 0);\n                    bestPos = 0;\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p];\n                        int v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < incMin) {\n                            incMin = inc;\n                            bestPos = p;\n                        }\n                    }\n                }\n\n                if (incMin >= INF / 4) continue;\n                double sc = pow((double)gain, alpha) / pow((double)(incMin + 1), beta);\n                if (noise > 0.0) {\n                    double z = rng.next_double() * 2.0 - 1.0; // [-1,1)\n                    sc *= (1.0 + noise * z);\n                }\n\n                Choice ch{sc, c, bestPos, gain, incMin};\n\n                // keep top-k by score\n                int ins = (int)top.size();\n                while (ins > 0 && top[ins - 1].score < ch.score) ins--;\n                if ((int)top.size() < topk) {\n                    top.insert(top.begin() + ins, ch);\n                } else if (ins < topk) {\n                    top.insert(top.begin() + ins, ch);\n                    top.pop_back();\n                }\n            }\n\n            if (top.empty()) break;\n\n            int pick = 0;\n            if ((int)top.size() > 1) {\n                int sz = (int)top.size();\n                int total = sz * (sz + 1) / 2; // rank-weighted\n                int r = rng.next_int(1, total);\n                for (int i = 0; i < sz; i++) {\n                    int w = sz - i;\n                    r -= w;\n                    if (r <= 0) {\n                        pick = i;\n                        break;\n                    }\n                }\n            }\n\n            Choice chosen = top[pick];\n            seq.insert(seq.begin() + chosen.pos + 1, chosen.cidx);\n            used[chosen.cidx] = 1;\n\n            const auto &vb = roadVisBits[candRid[chosen.cidx]];\n            for (int b = 0; b < B; b++) unc[b] &= ~vb[b];\n        }\n\n        // deterministic safety fill if needed\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            int bestC = -1, bestGain = -1, bestPos = 0, bestInc = INF;\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n                int gain = gain_for_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int incMin = INF, pos = 0;\n                if (m == 1) {\n                    incMin = edge_cost(0, c) + edge_cost(c, 0);\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < incMin) {\n                            incMin = inc;\n                            pos = p;\n                        }\n                    }\n                }\n\n                if (gain > bestGain || (gain == bestGain && incMin < bestInc)) {\n                    bestGain = gain;\n                    bestInc = incMin;\n                    bestC = c;\n                    bestPos = pos;\n                }\n            }\n\n            if (bestC == -1) break;\n            seq.insert(seq.begin() + bestPos + 1, bestC);\n            used[bestC] = 1;\n\n            const auto &vb = roadVisBits[candRid[bestC]];\n            for (int b = 0; b < B; b++) unc[b] &= ~vb[b];\n        }\n\n        return seq;\n    }\n\n    long long cycle_cost(const vector<int>& seq) const {\n        int m = (int)seq.size();\n        if (m <= 1) return 0;\n        long long c = 0;\n        for (int i = 0; i < m; i++) {\n            c += edge_cost(seq[i], seq[(i + 1) % m]);\n        }\n        return c;\n    }\n\n    void prune_waypoint_cost(vector<int>& seq) {\n        if (seq.size() <= 1) return;\n\n        vector<int> cnt(R, 0);\n        for (int idx : seq) {\n            for (int rid : candVisList[idx]) cnt[rid]++;\n        }\n\n        while (true) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestPos = -1;\n            long long bestSave = LLONG_MIN;\n\n            for (int p = 1; p < m; p++) { // keep start fixed\n                int idx = seq[p];\n\n                bool removable = true;\n                for (int rid : candVisList[idx]) {\n                    if (cnt[rid] <= 1) {\n                        removable = false;\n                        break;\n                    }\n                }\n                if (!removable) continue;\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n                long long save = (long long)edge_cost(pr, idx) + edge_cost(idx, nx) - edge_cost(pr, nx);\n\n                if (save > bestSave) {\n                    bestSave = save;\n                    bestPos = p;\n                }\n            }\n\n            if (bestPos == -1 || bestSave < 0) break; // allow zero-save removals\n            int idx = seq[bestPos];\n            for (int rid : candVisList[idx]) cnt[rid]--;\n            seq.erase(seq.begin() + bestPos);\n        }\n    }\n\n    bool improve_relocate(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n\n            int x = seq[i];\n            int p = seq[(i - 1 + m) % m];\n            int n = seq[(i + 1) % m];\n\n            long long rem = -(long long)edge_cost(p, x) - edge_cost(x, n) + edge_cost(p, n);\n\n            for (int j = 0; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n                if (j == i) continue;\n                if (j == (i - 1 + m) % m) continue; // edge p->x\n                // j edge is a->b where b=next(j)\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n\n                long long delta = rem - (long long)edge_cost(a, b) + edge_cost(a, x) + edge_cost(x, b);\n\n                if (delta < 0) {\n                    int node = seq[i];\n                    seq.erase(seq.begin() + i);\n                    int jj = j;\n                    if (jj > i) jj--;\n                    seq.insert(seq.begin() + jj + 1, node);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool improve_swap(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n\n                long long delta = 0;\n                if (i + 1 == j) {\n                    int p = seq[i - 1], a = seq[i], b = seq[j], n = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(p, a) + edge_cost(a, b) + edge_cost(b, n);\n                    long long newc = (long long)edge_cost(p, b) + edge_cost(b, a) + edge_cost(a, n);\n                    delta = newc - oldc;\n                } else {\n                    int pi = seq[i - 1], a = seq[i], ni = seq[(i + 1) % m];\n                    int pj = seq[j - 1], b = seq[j], nj = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(pi, a) + edge_cost(a, ni)\n                                   + (long long)edge_cost(pj, b) + edge_cost(b, nj);\n                    long long newc = (long long)edge_cost(pi, b) + edge_cost(b, ni)\n                                   + (long long)edge_cost(pj, a) + edge_cost(a, nj);\n                    delta = newc - oldc;\n                }\n\n                if (delta < 0) {\n                    swap(seq[i], seq[j]);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    void local_search(vector<int>& seq, long long& curCost, long long endMs) {\n        if (seq.size() <= 2) return;\n        int it = 0;\n        while (elapsed_ms() < endMs) {\n            bool imp = false;\n            if (improve_relocate(seq, curCost, endMs)) imp = true;\n            else if (improve_swap(seq, curCost, endMs)) imp = true;\n            if (!imp) break;\n            if (++it > 200000) break;\n        }\n    }\n\n    bool coverage_full_route_skip(const vector<int>& seq, int skipPos) const {\n        if (seq.empty()) return false;\n\n        vector<ull> cov(B, 0ULL);\n        vector<int> rev;\n        rev.reserve(256);\n\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int b = 0; b < B; b++) cov[b] |= vb[b];\n        };\n\n        auto addEdge = [&](int sCand, int tCand, bool includeSrc) -> bool {\n            int src = candRid[sCand];\n            int dst = candRid[tCand];\n\n            if (includeSrc) addRid(src);\n            if (src == dst) return true;\n\n            rev.clear();\n            int cur = dst;\n            while (cur != src) {\n                rev.push_back(cur);\n                cur = prevFrom[sCand][cur];\n                if (cur < 0) return false;\n            }\n\n            for (int k = (int)rev.size() - 1; k >= 0; k--) addRid(rev[k]);\n            return true;\n        };\n\n        int first = -1, prevC = -1;\n        bool firstEdge = true;\n        for (int i = 0; i < (int)seq.size(); i++) {\n            if (i == skipPos) continue;\n            int c = seq[i];\n            if (first == -1) {\n                first = c;\n                prevC = c;\n            } else {\n                if (!addEdge(prevC, c, firstEdge)) return false;\n                firstEdge = false;\n                prevC = c;\n            }\n        }\n\n        if (first == -1) return false;\n        if (!addEdge(prevC, first, firstEdge)) return false;\n\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    void route_aware_prune(vector<int>& seq, long long endMs) {\n        if (seq.size() <= 1) return;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestPos = -1;\n            long long bestSave = -1;\n\n            for (int p = 1; p < m; p++) {\n                if (elapsed_ms() > endMs) break;\n\n                int pr = seq[(p - 1 + m) % m];\n                int cur = seq[p];\n                int nx = seq[(p + 1) % m];\n                long long save = (long long)edge_cost(pr, cur) + edge_cost(cur, nx) - edge_cost(pr, nx);\n                if (save < 0) continue;\n\n                if (coverage_full_route_skip(seq, p)) {\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestPos = p;\n                    }\n                }\n            }\n\n            if (bestPos == -1) break;\n            seq.erase(seq.begin() + bestPos);\n        }\n    }\n\n    char move_char(int u, int v) const {\n        if (ri[v] == ri[u] - 1 && rj[v] == rj[u]) return 'U';\n        if (ri[v] == ri[u] + 1 && rj[v] == rj[u]) return 'D';\n        if (ri[v] == ri[u] && rj[v] == rj[u] - 1) return 'L';\n        if (ri[v] == ri[u] && rj[v] == rj[u] + 1) return 'R';\n        return '?';\n    }\n\n    string build_answer(const vector<int>& seq) const {\n        string ans;\n        int m = (int)seq.size();\n        if (m <= 1) return ans;\n\n        long long cc = cycle_cost(seq);\n        ans.reserve((size_t)(max(1LL, cc / 6) + 64));\n\n        vector<int> rev;\n        rev.reserve(256);\n\n        for (int i = 0; i < m; i++) {\n            int sCand = seq[i];\n            int tCand = seq[(i + 1) % m];\n            int src = candRid[sCand];\n            int dst = candRid[tCand];\n\n            if (src == dst) continue;\n\n            rev.clear();\n            int cur = dst;\n            while (cur != src) {\n                rev.push_back(cur);\n                cur = prevFrom[sCand][cur];\n                if (cur < 0) return \"\";\n            }\n\n            int u = src;\n            for (int k = (int)rev.size() - 1; k >= 0; k--) {\n                int v = rev[k];\n                char ch = move_char(u, v);\n                if (ch == '?') return \"\";\n                ans.push_back(ch);\n                u = v;\n            }\n        }\n\n        return ans;\n    }\n\n    int dir_id(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    bool validate_ans(const string& ans) const {\n        if (startRid < 0) return false;\n\n        vector<ull> cov(B, 0ULL);\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int b = 0; b < B; b++) cov[b] |= vb[b];\n        };\n\n        int cur = startRid;\n        addRid(cur);\n\n        for (char ch : ans) {\n            int d = dir_id(ch);\n            if (d < 0) return false;\n            int nx = nbr[cur][d];\n            if (nx == -1) return false;\n            cur = nx;\n            addRid(cur);\n        }\n\n        if (cur != startRid) return false;\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    string fallback_dfs_tour() const {\n        vector<char> vis(R, 0);\n        string out;\n        out.reserve(max(0, 2 * R + 8));\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1 || vis[v]) continue;\n                out.push_back(MV[d]);\n                dfs(v);\n                out.push_back(MV[OPP[d]]);\n            }\n        };\n\n        dfs(startRid);\n        return out;\n    }\n\n    uint64_t calc_seed() const {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)si);\n        mix((uint64_t)sj);\n        mix((uint64_t)R);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                mix((uint64_t)(unsigned char)grid[i][j]\n                    + ((uint64_t)i << 8)\n                    + ((uint64_t)j << 16));\n            }\n        }\n        return h;\n    }\n\n    string solve() {\n        t0 = chrono::steady_clock::now();\n\n        build_graph();\n        if (R == 0) return \"\";\n\n        init_bits();\n        build_road_visibility();\n        build_candidates();\n        precompute_shortest_paths();\n\n        XorShift64 rng(calc_seed());\n\n        vector<int> bestSeq;\n        long long bestCost = (1LL << 60);\n\n        int attempt = 0;\n        while (true) {\n            long long now = elapsed_ms();\n            if (attempt > 0 && (now > 2100 || attempt >= 16)) break;\n\n            double alpha, beta, noise;\n            int topk;\n            if (attempt == 0) {\n                alpha = 2.0;\n                beta = 1.0;\n                topk = 1;\n                noise = 0.0;\n            } else {\n                static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.4};\n                static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n                static const int KS[] = {1, 2, 3, 4, 6};\n\n                alpha = AS[rng.next_int(0, 5)];\n                beta  = BS[rng.next_int(0, 3)];\n                topk  = KS[rng.next_int(0, 4)];\n                noise = 0.12;\n            }\n\n            auto seq = build_cycle_cover(alpha, beta, topk, noise, rng);\n            prune_waypoint_cost(seq);\n\n            long long cost = cycle_cost(seq);\n            long long lsEnd = min(2350LL, elapsed_ms() + (attempt == 0 ? 140LL : 80LL));\n            local_search(seq, cost, lsEnd);\n\n            prune_waypoint_cost(seq);\n            cost = cycle_cost(seq);\n\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestSeq = seq;\n            }\n\n            attempt++;\n        }\n\n        if (bestSeq.empty()) bestSeq = {0};\n\n        long long curCost = cycle_cost(bestSeq);\n        if (elapsed_ms() < 2500) {\n            local_search(bestSeq, curCost, 2550);\n            prune_waypoint_cost(bestSeq);\n            curCost = cycle_cost(bestSeq);\n        }\n\n        vector<int> finalSeq = bestSeq;\n        if (elapsed_ms() < 2650 && finalSeq.size() <= 220) {\n            vector<int> tmp = finalSeq;\n            route_aware_prune(tmp, 2720);\n            if (coverage_full_route_skip(tmp, -1)) {\n                finalSeq.swap(tmp);\n            }\n        }\n\n        string ans = build_answer(finalSeq);\n        if ((ans.empty() && finalSeq.size() > 1) || !validate_ans(ans)) {\n            string ans2 = build_answer(bestSeq);\n            if (validate_ans(ans2)) {\n                ans = ans2;\n            } else {\n                ans = fallback_dfs_tour();\n            }\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    string ans = solver.solve();\n    cout << ans << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\nusing namespace std;\nusing namespace atcoder;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n\n    int N, M, K, R;\n    vector<vector<int>> d;\n    vector<vector<int>> succ;\n    vector<int> indeg0, indegRem, outdeg;\n    vector<int> sumd;\n    vector<int> lp;          // dynamic remaining longest path (among unfinished tasks)\n    vector<int> descCnt;     // static descendant count\n    vector<int> taskState;   // 0:not started, 1:in progress, 2:done\n\n    vector<int> ready, readyPos, readySince;\n    int day = 1;\n    int stallDays = 0;\n\n    struct Member {\n        bool busy = false;\n        int task = -1;\n        int startDay = 0;\n        vector<int> s;\n        vector<int> histTask;\n        vector<int> histDur;\n        bool dirty = false;\n        int doneCount = 0;\n    };\n    vector<Member> members;\n\n    // ---- parameters ----\n    static constexpr int INIT_SKILL = 8;\n    static constexpr int SKILL_MAX = 80;\n    static constexpr int MAX_HIST = 120;\n\n    static constexpr int MAX_CAND = 180;\n    static constexpr int BASE_CAND = 110;\n    static constexpr int AGE_CAND = 40;\n\n    static constexpr int LP_W = 100;\n    static constexpr int DESC_W = 2;\n    static constexpr int UNLOCK_W = 70;\n    static constexpr int AGE_W = 6;\n\n    static constexpr double PRED_W = 40.0;\n    static constexpr double CRIT_MARGIN = 2.0;\n    static constexpr double CRIT_EXCESS_W = 220.0;\n    static constexpr double NEWBIE_CRIT_PEN = 120.0;\n\n    static constexpr double IDLE_UTILITY = -1800.0;\n    static constexpr long long COST_SHIFT = 1'000'000LL;\n\n    static inline double expected_time_from_w(int w) {\n        if (w <= 0) return 1.0;\n        if (w == 1) return 13.0 / 7.0;\n        if (w == 2) return 17.0 / 7.0;\n        if (w == 3) return 22.0 / 7.0;\n        return (double)w;\n    }\n\n    static inline long long utility_to_cost(double util) {\n        long long u10 = llround(util * 10.0);\n        long long c = COST_SHIFT - u10;\n        if (c < 0) c = 0;\n        return c;\n    }\n\n    double sample_loss(int w, int obs) const {\n        const double pred = expected_time_from_w(w);\n        const double e = pred - (double)obs;\n        const double ae = fabs(e);\n\n        // robust / noise-tolerant loss\n        double l;\n        if (ae <= 2.0) {\n            l = 0.25 * ae * ae;\n        } else {\n            const double z = ae - 2.0;\n            l = 1.0 + z * z;\n        }\n\n        // short tasks are less informative (especially obs=1 due clipping)\n        const double wt = (obs <= 1 ? 0.30 : (obs <= 3 ? 0.70 : 1.00));\n        return wt * l;\n    }\n\n    inline int calc_w(const vector<int>& s, int task) const {\n        int w = 0;\n        for (int k = 0; k < K; k++) {\n            if (d[task][k] > s[k]) w += d[task][k] - s[k];\n        }\n        return w;\n    }\n\n    inline double predict_time_exp(int member, int task) const {\n        int w = calc_w(members[member].s, task);\n        return expected_time_from_w(w);\n    }\n\n    void add_ready(int t, int availDay) {\n        if (t < 0 || t >= N) return;\n        if (taskState[t] != 0) return;\n        if (indegRem[t] != 0) return;\n        if (readyPos[t] != -1) return;\n        readyPos[t] = (int)ready.size();\n        ready.push_back(t);\n        readySince[t] = availDay;\n    }\n\n    void remove_ready(int t) {\n        int p = readyPos[t];\n        if (p == -1) return;\n        int last = ready.back();\n        ready[p] = last;\n        readyPos[last] = p;\n        ready.pop_back();\n        readyPos[t] = -1;\n        readySince[t] = -1;\n    }\n\n    void compute_static_descendants() {\n        descCnt.assign(N, 0);\n        if (N <= MAXN) {\n            vector<bitset<MAXN>> reach(N);\n            for (int i = N - 1; i >= 0; i--) {\n                for (int to : succ[i]) {\n                    reach[i] |= reach[to];\n                    reach[i].set(to);\n                }\n                descCnt[i] = (int)reach[i].count();\n            }\n        } else {\n            // fallback (shouldn't be used in official generator)\n            for (int i = 0; i < N; i++) descCnt[i] = outdeg[i];\n        }\n    }\n\n    void update_remaining_lp() {\n        if ((int)lp.size() != N) lp.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            if (taskState[i] == 2) {\n                lp[i] = 0;\n                continue;\n            }\n            int best = 1;\n            for (int to : succ[i]) {\n                if (taskState[to] != 2) best = max(best, lp[to] + 1);\n            }\n            lp[i] = best;\n        }\n    }\n\n    int task_base(int t) const {\n        int unlock = 0;\n        for (int ch : succ[t]) {\n            if (taskState[ch] == 0 && indegRem[ch] == 1) unlock++;\n        }\n        int age = 0;\n        if (readySince[t] >= 0) age = max(0, day - readySince[t]);\n\n        int base = 0;\n        base += LP_W * lp[t];\n        base += DESC_W * descCnt[t];\n        base += UNLOCK_W * unlock;\n        base += AGE_W * age;\n        base += outdeg[t]; // tiny tie-break\n        return base;\n    }\n\n    vector<int> make_candidates() const {\n        if ((int)ready.size() <= MAX_CAND) return ready;\n\n        vector<pair<int, int>> byBase; // (-base, t)\n        vector<pair<int, int>> byAge;  // (-age, t)\n        byBase.reserve(ready.size());\n        byAge.reserve(ready.size());\n\n        for (int t : ready) {\n            byBase.push_back({-task_base(t), t});\n            int age = max(0, day - readySince[t]);\n            byAge.push_back({-age, t});\n        }\n\n        sort(byBase.begin(), byBase.end());\n        sort(byAge.begin(), byAge.end());\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(MAX_CAND);\n\n        int t1 = min(BASE_CAND, (int)byBase.size());\n        for (int i = 0; i < t1; i++) {\n            int t = byBase[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        int t2 = min(AGE_CAND, (int)byAge.size());\n        for (int i = 0; i < t2 && (int)cand.size() < MAX_CAND; i++) {\n            int t = byAge[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        if ((int)cand.size() < MAX_CAND) {\n            vector<pair<int, int>> byEasy; // (sumd, t)\n            byEasy.reserve(ready.size());\n            for (int t : ready) {\n                if (!used[t]) byEasy.push_back({sumd[t], t});\n            }\n            sort(byEasy.begin(), byEasy.end());\n            for (auto &p : byEasy) {\n                if ((int)cand.size() >= MAX_CAND) break;\n                cand.push_back(p.second);\n            }\n        }\n        return cand;\n    }\n\n    void optimize_member(int j) {\n        Member &mb = members[j];\n        int total = (int)mb.histTask.size();\n        if (total == 0) {\n            mb.dirty = false;\n            return;\n        }\n\n        int st = max(0, total - MAX_HIST);\n        int h = total - st;\n\n        vector<int> tasks(h), obs(h), w(h);\n        for (int i = 0; i < h; i++) {\n            tasks[i] = mb.histTask[st + i];\n            obs[i] = mb.histDur[st + i];\n        }\n\n        for (int i = 0; i < h; i++) {\n            w[i] = calc_w(mb.s, tasks[i]);\n        }\n\n        const double reg = 0.30 / (h + 3.0); // stronger when data is scarce\n\n        double loss = 0.0;\n        for (int i = 0; i < h; i++) loss += sample_loss(w[i], obs[i]);\n        for (int k = 0; k < K; k++) {\n            double diff = (double)mb.s[k] - INIT_SKILL;\n            loss += reg * diff * diff;\n        }\n\n        static const int deltas_small[] = {-2, -1, 1, 2};\n        static const int deltas_large[] = {-8, -4, -2, -1, 1, 2, 4, 8};\n        const int *deltas = (h < 5 ? deltas_small : deltas_large);\n        int nd = (h < 5 ? 4 : 8);\n\n        int passes = (h < 8 ? 6 : (h < 20 ? 5 : 4));\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            bool improved = false;\n            if (pass & 1) reverse(order.begin(), order.end());\n\n            for (int idx = 0; idx < K; idx++) {\n                int k = order[idx];\n                int curS = mb.s[k];\n                double bestLoss = loss;\n                int bestS = curS;\n\n                for (int di = 0; di < nd; di++) {\n                    int ns = curS + deltas[di];\n                    if (ns < 0 || ns > SKILL_MAX || ns == curS) continue;\n\n                    double newLoss = loss;\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)ns - INIT_SKILL;\n                        newLoss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > ns ? dval - ns : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n\n                        newLoss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                    }\n\n                    if (newLoss + 1e-9 < bestLoss) {\n                        bestLoss = newLoss;\n                        bestS = ns;\n                    }\n                }\n\n                if (bestS != curS) {\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)bestS - INIT_SKILL;\n                        loss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > bestS ? dval - bestS : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n                        loss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                        w[i] = nw;\n                    }\n\n                    mb.s[k] = bestS;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        mb.dirty = false;\n    }\n\n    vector<pair<int, int>> decide_assignments(bool force) {\n        vector<pair<int, int>> ret;\n\n        vector<int> freeMembers;\n        freeMembers.reserve(M);\n        for (int j = 0; j < M; j++) {\n            if (!members[j].busy) freeMembers.push_back(j);\n        }\n        if (freeMembers.empty() || ready.empty()) return ret;\n\n        vector<int> cand = make_candidates();\n        int F = (int)freeMembers.size();\n        int T = (int)cand.size();\n        if (T == 0) return ret;\n\n        vector<int> base(T);\n        int maxReadyLp = 0, maxReadyDesc = 0;\n        for (int t : ready) {\n            maxReadyLp = max(maxReadyLp, lp[t]);\n            maxReadyDesc = max(maxReadyDesc, descCnt[t]);\n        }\n\n        vector<char> critical(T, 0);\n        for (int ti = 0; ti < T; ti++) {\n            int t = cand[ti];\n            base[ti] = task_base(t);\n            if (lp[t] >= maxReadyLp - 1) critical[ti] = 1;\n            if (descCnt[t] >= maxReadyDesc - 20) critical[ti] = 1;\n        }\n\n        vector<vector<double>> predAll(M, vector<double>(T));\n        vector<double> bestAllPred(T, 1e100);\n        for (int m = 0; m < M; m++) {\n            for (int ti = 0; ti < T; ti++) {\n                double p = predict_time_exp(m, cand[ti]);\n                predAll[m][ti] = p;\n                if (p < bestAllPred[ti]) bestAllPred[ti] = p;\n            }\n        }\n\n        int S = F + T;\n        int G = S + 1;\n        mcf_graph<int, long long> g(G + 1);\n\n        for (int fi = 0; fi < F; fi++) g.add_edge(S, fi, 1, 0);\n        for (int ti = 0; ti < T; ti++) g.add_edge(F + ti, G, 1, 0);\n\n        if (!force) {\n            long long idleCost = utility_to_cost(IDLE_UTILITY);\n            for (int fi = 0; fi < F; fi++) {\n                g.add_edge(fi, G, 1, idleCost);\n            }\n        }\n\n        vector<int> eid(F * T, -1);\n\n        for (int fi = 0; fi < F; fi++) {\n            int m = freeMembers[fi];\n            for (int ti = 0; ti < T; ti++) {\n                double pred = predAll[m][ti];\n                double util = (double)base[ti] - PRED_W * pred;\n\n                if (critical[ti]) {\n                    double excess = pred - bestAllPred[ti];\n                    if (excess > CRIT_MARGIN) {\n                        util -= CRIT_EXCESS_W * (excess - CRIT_MARGIN);\n                    }\n                    if (members[m].doneCount < 2) {\n                        util -= NEWBIE_CRIT_PEN;\n                    }\n                }\n\n                long long cost = utility_to_cost(util);\n                eid[fi * T + ti] = g.add_edge(fi, F + ti, 1, cost);\n            }\n        }\n\n        if (force) {\n            int L = min(T, max(1, F / 2)); // conservative forced progress\n            g.flow(S, G, L);\n        } else {\n            g.flow(S, G, F); // each free member: task or idle\n        }\n\n        for (int fi = 0; fi < F; fi++) {\n            for (int ti = 0; ti < T; ti++) {\n                auto e = g.get_edge(eid[fi * T + ti]);\n                if (e.flow > 0) {\n                    ret.push_back({freeMembers[fi], cand[ti]});\n                }\n            }\n        }\n\n        for (auto [m, t] : ret) {\n            members[m].busy = true;\n            members[m].task = t;\n            members[m].startDay = day;\n\n            taskState[t] = 1;\n            remove_ready(t);\n        }\n\n        return ret;\n    }\n\n    void read_initial() {\n        cin >> N >> M >> K >> R;\n\n        d.assign(N, vector<int>(K));\n        sumd.assign(N, 0);\n        for (int i = 0; i < N; i++) {\n            int s = 0;\n            for (int k = 0; k < K; k++) {\n                cin >> d[i][k];\n                s += d[i][k];\n            }\n            sumd[i] = s;\n        }\n\n        succ.assign(N, {});\n        indeg0.assign(N, 0);\n\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            succ[u].push_back(v);\n            indeg0[v]++;\n        }\n\n        outdeg.assign(N, 0);\n        for (int i = 0; i < N; i++) outdeg[i] = (int)succ[i].size();\n\n        compute_static_descendants();\n\n        indegRem = indeg0;\n        taskState.assign(N, 0);\n\n        ready.clear();\n        readyPos.assign(N, -1);\n        readySince.assign(N, -1);\n\n        day = 1;\n        for (int i = 0; i < N; i++) {\n            if (indegRem[i] == 0) add_ready(i, 1);\n        }\n\n        members.assign(M, Member());\n        for (int j = 0; j < M; j++) {\n            members[j].s.assign(K, INIT_SKILL);\n        }\n\n        lp.assign(N, 1);\n        update_remaining_lp();\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        read_initial();\n\n        while (true) {\n            update_remaining_lp();\n\n            int freeCntBefore = 0;\n            for (int j = 0; j < M; j++) if (!members[j].busy) freeCntBefore++;\n            bool hadReady = !ready.empty();\n\n            bool force = (stallDays >= 2);\n            auto assignments = decide_assignments(force);\n\n            if (hadReady && freeCntBefore > 0 && assignments.empty()) {\n                stallDays++;\n            } else if (!assignments.empty()) {\n                stallDays = 0;\n            } else if (!hadReady || freeCntBefore == 0) {\n                stallDays = 0;\n            }\n\n            cout << assignments.size();\n            for (auto [m, t] : assignments) {\n                cout << ' ' << (m + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int n;\n            if (!(cin >> n)) return;\n            if (n == -1) return;\n\n            vector<int> finished(n);\n            for (int i = 0; i < n; i++) {\n                cin >> finished[i];\n                --finished[i];\n            }\n\n            for (int m : finished) {\n                if (m < 0 || m >= M) continue;\n                Member &mb = members[m];\n                if (!mb.busy) continue;\n\n                int task = mb.task;\n                int duration = day - mb.startDay + 1;\n\n                mb.busy = false;\n                mb.task = -1;\n                mb.doneCount++;\n                mb.histTask.push_back(task);\n                mb.histDur.push_back(duration);\n                mb.dirty = true;\n\n                taskState[task] = 2;\n\n                for (int ch : succ[task]) {\n                    indegRem[ch]--;\n                    if (indegRem[ch] == 0 && taskState[ch] == 0) {\n                        add_ready(ch, day + 1);\n                    }\n                }\n            }\n\n            for (int m : finished) {\n                if (0 <= m && m < M && members[m].dirty) {\n                    optimize_member(m);\n                }\n            }\n\n            day++;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic uint16_t DISTMAT[2001][2001];\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t nextU32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n    int nextInt(int n) { return static_cast<int>(nextU32() % static_cast<uint32_t>(n)); }\n    double nextDouble() { return (nextU32() + 0.5) / 4294967296.0; }\n};\n\nstruct Solver {\n    static constexpr int N = 1000;\n    static constexpr int M = 50;\n    static constexpr int TOT = 2001;\n    static constexpr int DEP = 2000;\n\n    struct Insertion {\n        int delta;\n        int i, j; // insert pickup at i, delivery at j (after pickup insertion)\n    };\n\n    struct State {\n        vector<int> route; // node IDs: pickup [0..999], delivery [1000..1999]\n        vector<int> sel;   // selected order IDs [0..999], size 50\n        array<int, N> pos; // pos[id] in sel, -1 if not selected\n        int len;\n\n        State() : len(INT_MAX) {\n            pos.fill(-1);\n            route.reserve(2 * M);\n            sel.reserve(M);\n        }\n    };\n\n    int a[N], b[N], c[N], d[N];\n    int nodeX[TOT], nodeY[TOT];\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n    double TL = 1.90;\n\n    vector<int> tmp1, tmp2, tmp3;\n    vector<int> candIds;\n    vector<pair<int, int>> approx; // (approxDelta, orderID)\n    vector<int> ordBuf;\n\n    array<int, N> mark{};\n    int stamp = 1;\n\n    Solver()\n        : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        tmp1.reserve(2 * M);\n        tmp2.reserve(2 * M);\n        tmp3.reserve(2 * M);\n        candIds.reserve(N);\n        approx.reserve(N);\n        ordBuf.reserve(M);\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline void shuffleVec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    inline int calcLen(const vector<int>& route) const {\n        int prev = DEP;\n        int len = 0;\n        for (int v : route) {\n            len += DISTMAT[prev][v];\n            prev = v;\n        }\n        len += DISTMAT[prev][DEP];\n        return len;\n    }\n\n    Insertion bestInsertPair(const vector<int>& route, int oid) const {\n        const int p = oid;\n        const int q = oid + N;\n        const int n = (int)route.size();\n\n        Insertion best{INT_MAX, 0, 1};\n        const uint16_t* rowQ = DISTMAT[q];\n\n        for (int i = 0; i <= n; ++i) {\n            int A = (i == 0 ? DEP : route[i - 1]);\n            int B = (i == n ? DEP : route[i]);\n\n            int dAB = DISTMAT[A][B];\n            int baseP = DISTMAT[A][p] + DISTMAT[p][B] - dAB;\n\n            // adjacent insertion: A -> p -> q -> B\n            int adj = DISTMAT[A][p] + DISTMAT[p][q] + rowQ[B] - dAB;\n            if (adj < best.delta) best = {adj, i, i + 1};\n\n            // separated delivery insertion\n            for (int j = i + 2; j <= n + 1; ++j) {\n                int C = route[j - 2];\n                int D = (j - 1 == n ? DEP : route[j - 1]);\n                int delta = baseP + DISTMAT[C][q] + rowQ[D] - DISTMAT[C][D];\n                if (delta < best.delta) best = {delta, i, j};\n            }\n        }\n        return best;\n    }\n\n    inline int bestAdjacentDelta(const vector<int>& route, int oid) const {\n        const int p = oid;\n        const int q = oid + N;\n        const int pq = DISTMAT[p][q];\n        const int n = (int)route.size();\n        int best = INT_MAX;\n        for (int i = 0; i <= n; ++i) {\n            int A = (i == 0 ? DEP : route[i - 1]);\n            int B = (i == n ? DEP : route[i]);\n            int delta = DISTMAT[A][p] + pq + DISTMAT[q][B] - DISTMAT[A][B];\n            if (delta < best) best = delta;\n        }\n        return best;\n    }\n\n    inline void insertPair(vector<int>& route, const Insertion& ins, int oid) const {\n        route.insert(route.begin() + ins.i, oid);\n        route.insert(route.begin() + ins.j, oid + N);\n    }\n\n    inline void removeOrder(const vector<int>& route, int oid, vector<int>& out) const {\n        out.clear();\n        int p = oid;\n        int q = oid + N;\n        for (int v : route) {\n            if (v == p || v == q) continue;\n            out.push_back(v);\n        }\n    }\n\n    inline void nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            mark.fill(0);\n            stamp = 1;\n        }\n    }\n\n    State buildGreedy(int rcl, int shortlistK) {\n        State s;\n        vector<int> shortlist;\n        shortlist.reserve(shortlistK);\n\n        struct Cand {\n            int val;\n            int id;\n            Insertion ins;\n        };\n\n        for (int step = 0; step < M; ++step) {\n            approx.clear();\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                int ad = bestAdjacentDelta(s.route, id);\n                approx.emplace_back(ad, id);\n            }\n\n            int extra = min(20, shortlistK / 5);\n            int topK = max(1, shortlistK - extra);\n\n            if ((int)approx.size() > topK) {\n                nth_element(approx.begin(), approx.begin() + topK, approx.end(),\n                            [](const auto& l, const auto& r) { return l.first < r.first; });\n                approx.resize(topK);\n            }\n\n            shortlist.clear();\n            nextStamp();\n            for (auto& pr : approx) {\n                int id = pr.second;\n                mark[id] = stamp;\n                shortlist.push_back(id);\n            }\n\n            int attempts = 0;\n            while ((int)shortlist.size() < shortlistK && attempts < 5000) {\n                ++attempts;\n                int id = rng.nextInt(N);\n                if (s.pos[id] != -1 || mark[id] == stamp) continue;\n                mark[id] = stamp;\n                shortlist.push_back(id);\n            }\n            if ((int)shortlist.size() < shortlistK) {\n                for (int id = 0; id < N && (int)shortlist.size() < shortlistK; ++id) {\n                    if (s.pos[id] != -1 || mark[id] == stamp) continue;\n                    mark[id] = stamp;\n                    shortlist.push_back(id);\n                }\n            }\n\n            vector<Cand> top;\n            top.reserve(max(1, rcl));\n\n            auto pushTop = [&](const Cand& c) {\n                if ((int)top.size() < rcl) {\n                    top.push_back(c);\n                    for (int i = (int)top.size() - 1; i > 0 && top[i].val < top[i - 1].val; --i) {\n                        swap(top[i], top[i - 1]);\n                    }\n                } else if (c.val < top.back().val) {\n                    top.back() = c;\n                    for (int i = (int)top.size() - 1; i > 0 && top[i].val < top[i - 1].val; --i) {\n                        swap(top[i], top[i - 1]);\n                    }\n                }\n            };\n\n            for (int id : shortlist) {\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTop({ins.delta, id, ins});\n            }\n\n            if (top.empty()) {\n                Cand best{INT_MAX, -1, {INT_MAX, 0, 1}};\n                for (int id = 0; id < N; ++id) {\n                    if (s.pos[id] != -1) continue;\n                    Insertion ins = bestInsertPair(s.route, id);\n                    if (ins.delta < best.val) best = {ins.delta, id, ins};\n                }\n                top.push_back(best);\n            }\n\n            int pick = 0;\n            if (rcl > 1 && (int)top.size() > 1) {\n                int lim = min((int)top.size(), rcl);\n                pick = rng.nextInt(lim);\n            }\n\n            int chosen = top[pick].id;\n            insertPair(s.route, top[pick].ins, chosen);\n            s.pos[chosen] = (int)s.sel.size();\n            s.sel.push_back(chosen);\n        }\n\n        s.len = calcLen(s.route);\n        return s;\n    }\n\n    bool relocateOrder(State& s, int oid) {\n        removeOrder(s.route, oid, tmp1);\n        int base = calcLen(tmp1);\n        Insertion ins = bestInsertPair(tmp1, oid);\n        int nlen = base + ins.delta;\n        if (nlen < s.len) {\n            tmp2 = tmp1;\n            insertPair(tmp2, ins, oid);\n            s.route.swap(tmp2);\n            s.len = nlen;\n            return true;\n        }\n        return false;\n    }\n\n    void intensify(State& s, double deadline) {\n        while (elapsed() < deadline) {\n            ordBuf = s.sel;\n            shuffleVec(ordBuf);\n            int imp = 0;\n            for (int oid : ordBuf) {\n                if (elapsed() >= deadline) break;\n                if (relocateOrder(s, oid)) ++imp;\n            }\n            if (imp == 0) break;\n        }\n    }\n\n    int pickOldByGain(const State& s, int sample) {\n        int bestOid = s.sel[rng.nextInt(M)];\n        int bestGain = INT_MIN;\n        for (int t = 0; t < sample; ++t) {\n            int oid = s.sel[rng.nextInt(M)];\n            removeOrder(s.route, oid, tmp3);\n            int l = calcLen(tmp3);\n            int gain = s.len - l;\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestOid = oid;\n            }\n        }\n        return bestOid;\n    }\n\n    void collectApproxCandidates(const State& s, const vector<int>& routeWO, int old, int k, vector<int>& out) {\n        approx.clear();\n        for (int id = 0; id < N; ++id) {\n            if (id == old || s.pos[id] != -1) continue;\n            int ad = bestAdjacentDelta(routeWO, id);\n            approx.emplace_back(ad, id);\n        }\n\n        out.clear();\n        if (approx.empty()) return;\n\n        int randExtra = min(20, k / 4);\n        int topK = max(1, k - randExtra);\n\n        if ((int)approx.size() > topK) {\n            nth_element(approx.begin(), approx.begin() + topK, approx.end(),\n                        [](const auto& l, const auto& r) { return l.first < r.first; });\n            approx.resize(topK);\n        }\n\n        nextStamp();\n        out.reserve(k);\n        for (auto& pr : approx) {\n            int id = pr.second;\n            if (mark[id] == stamp) continue;\n            mark[id] = stamp;\n            out.push_back(id);\n        }\n\n        int target = k;\n        int attempts = 0;\n        while ((int)out.size() < target && attempts < 5000) {\n            ++attempts;\n            int id = rng.nextInt(N);\n            if (id == old || s.pos[id] != -1 || mark[id] == stamp) continue;\n            mark[id] = stamp;\n            out.push_back(id);\n        }\n        if ((int)out.size() < target) {\n            for (int id = 0; id < N && (int)out.size() < target; ++id) {\n                if (id == old || s.pos[id] != -1 || mark[id] == stamp) continue;\n                mark[id] = stamp;\n                out.push_back(id);\n            }\n        }\n    }\n\n    bool tryReplaceSA(State& s, double temp, int shortlistK) {\n        int old = pickOldByGain(s, 5);\n        if (rng.nextInt(7) == 0) old = s.sel[rng.nextInt(M)];\n\n        removeOrder(s.route, old, tmp1);\n        int base = calcLen(tmp1);\n\n        collectApproxCandidates(s, tmp1, old, shortlistK, candIds);\n        if (candIds.empty()) return false;\n\n        int bestLen = INT_MAX;\n        int bestId = -1;\n        Insertion bestIns{INT_MAX, 0, 1};\n\n        for (int id : candIds) {\n            Insertion ins = bestInsertPair(tmp1, id);\n            int nlen = base + ins.delta;\n            if (nlen < bestLen) {\n                bestLen = nlen;\n                bestId = id;\n                bestIns = ins;\n            }\n        }\n\n        int diff = bestLen - s.len;\n        bool accept = false;\n        if (diff <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-double(diff) / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n        if (!accept) return false;\n\n        tmp2 = tmp1;\n        insertPair(tmp2, bestIns, bestId);\n\n        int idx = s.pos[old];\n        s.pos[old] = -1;\n        s.pos[bestId] = idx;\n        s.sel[idx] = bestId;\n        s.route.swap(tmp2);\n        s.len = bestLen;\n        return true;\n    }\n\n    bool tryReplaceGreedy(State& s, int shortlistK) {\n        int old = pickOldByGain(s, 6);\n\n        removeOrder(s.route, old, tmp1);\n        int base = calcLen(tmp1);\n\n        collectApproxCandidates(s, tmp1, old, shortlistK, candIds);\n        if (candIds.empty()) return false;\n\n        int bestLen = s.len;\n        int bestId = -1;\n        Insertion bestIns{INT_MAX, 0, 1};\n\n        for (int id : candIds) {\n            Insertion ins = bestInsertPair(tmp1, id);\n            int nlen = base + ins.delta;\n            if (nlen < bestLen) {\n                bestLen = nlen;\n                bestId = id;\n                bestIns = ins;\n            }\n        }\n\n        if (bestId == -1) return false;\n\n        tmp2 = tmp1;\n        insertPair(tmp2, bestIns, bestId);\n\n        int idx = s.pos[old];\n        s.pos[old] = -1;\n        s.pos[bestId] = idx;\n        s.sel[idx] = bestId;\n        s.route.swap(tmp2);\n        s.len = bestLen;\n        return true;\n    }\n\n    void output(const State& s) const {\n        cout << M;\n        for (int id : s.sel) cout << ' ' << (id + 1);\n        cout << '\\n';\n\n        int n = (int)s.route.size() + 2;\n        cout << n << ' ' << 400 << ' ' << 400;\n        for (int v : s.route) {\n            if (v < N) {\n                cout << ' ' << a[v] << ' ' << b[v];\n            } else {\n                int id = v - N;\n                cout << ' ' << c[id] << ' ' << d[id];\n            }\n        }\n        cout << ' ' << 400 << ' ' << 400 << '\\n';\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 0; i < N; ++i) {\n            cin >> a[i] >> b[i] >> c[i] >> d[i];\n        }\n\n        for (int i = 0; i < N; ++i) {\n            nodeX[i] = a[i];\n            nodeY[i] = b[i];\n            nodeX[i + N] = c[i];\n            nodeY[i + N] = d[i];\n        }\n        nodeX[DEP] = 400;\n        nodeY[DEP] = 400;\n\n        for (int i = 0; i < TOT; ++i) {\n            for (int j = 0; j < TOT; ++j) {\n                DISTMAT[i][j] = (uint16_t)(abs(nodeX[i] - nodeX[j]) + abs(nodeY[i] - nodeY[j]));\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n\n        // Multi-start: deterministic + randomized\n        State cur = buildGreedy(1, 220);\n        if (elapsed() < 0.35) {\n            State cand = buildGreedy(4, 220);\n            if (cand.len < cur.len) cur = std::move(cand);\n        }\n\n        double firstDeadline = min(TL * 0.35, elapsed() + 0.25);\n        intensify(cur, firstDeadline);\n\n        State best = cur;\n\n        int iter = 0;\n        while (elapsed() < TL - 0.08) {\n            ++iter;\n            double p = elapsed() / TL;\n            double temp = 35.0 * (1.0 - p) + 0.8;\n            int shortlistK = (p < 0.55 ? 150 : 100);\n\n            bool changed = tryReplaceSA(cur, temp, shortlistK);\n\n            if (changed) {\n                relocateOrder(cur, cur.sel[rng.nextInt(M)]);\n                if ((iter & 3) == 0) relocateOrder(cur, cur.sel[rng.nextInt(M)]);\n            } else {\n                if ((iter & 1) == 0) relocateOrder(cur, cur.sel[rng.nextInt(M)]);\n            }\n\n            if (cur.len < best.len) best = cur;\n            if ((iter % 128) == 0) {\n                if (cur.len > best.len + 320) cur = best;\n            }\n        }\n\n        // Final greedy replacement polish\n        int fail = 0;\n        while (elapsed() < TL - 0.03 && fail < 20) {\n            if (tryReplaceGreedy(best, 120)) {\n                fail = 0;\n                relocateOrder(best, best.sel[rng.nextInt(M)]);\n            } else {\n                ++fail;\n            }\n        }\n\n        if (elapsed() < TL) intensify(best, TL - 0.001);\n\n        output(best);\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int MC_SAMPLES = 10;\n\nstruct DSU {\n    array<int, N> p{};\n    array<int, N> sz{};\n    int comps = N;\n\n    DSU() { init(); }\n\n    void init() {\n        for (int i = 0; i < N; ++i) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n        comps = N;\n    }\n\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        --comps;\n        return true;\n    }\n\n    bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n};\n\nstruct Edge {\n    int u, v, d;\n};\n\nstruct ScenEdge {\n    int idx, u, v, w;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n\n    uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n\n    int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Read fixed initial information\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; ++i) {\n        if (!(cin >> xs[i] >> ys[i])) return 0;\n    }\n\n    vector<Edge> edges(M);\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        long long dx = xs[u] - xs[v];\n        long long dy = ys[u] - ys[v];\n        int d = static_cast<int>(llround(sqrt((long double)dx * dx + (long double)dy * dy)));\n        edges[i] = {u, v, d};\n    }\n\n    // Pre-sample future scenarios and sort each scenario by sampled weight.\n    XorShift64 rng(123456789123ull);\n    vector<vector<ScenEdge>> scenarios(MC_SAMPLES, vector<ScenEdge>(M));\n\n    for (int s = 0; s < MC_SAMPLES; ++s) {\n        for (int i = 0; i < M; ++i) {\n            int w = rng.next_int(edges[i].d, 3 * edges[i].d);\n            scenarios[s][i] = {i, edges[i].u, edges[i].v, w};\n        }\n        sort(scenarios[s].begin(), scenarios[s].end(),\n             [](const ScenEdge& a, const ScenEdge& b) {\n                 if (a.w != b.w) return a.w < b.w;\n                 return a.idx < b.idx;\n             });\n    }\n\n    DSU uf_selected; // adopted edges forest\n\n    for (int i = 0; i < M; ++i) {\n        int li;\n        if (!(cin >> li)) return 0;\n\n        const Edge& cur = edges[i];\n        int ans = 0;\n\n        // Cycle edges in selected forest are never useful.\n        if (uf_selected.same(cur.u, cur.v)) {\n            ans = 0;\n        } else {\n            // Mandatory check:\n            // Can we reject this edge while keeping possibility to connect?\n            // Need connectivity between cur.u and cur.v using selected + future edges.\n            DSU uf_possible = uf_selected;\n            bool can_reject = false;\n            for (int j = i + 1; j < M; ++j) {\n                uf_possible.unite(edges[j].u, edges[j].v);\n                if (uf_possible.same(cur.u, cur.v)) {\n                    can_reject = true;\n                    break;\n                }\n            }\n\n            if (!can_reject) {\n                ans = 1; // must adopt\n            } else {\n                // Monte Carlo expected completion-cost comparison\n                // gain = cost(reject) - cost(adopt)\n                // adopt if gain >= 0\n                long long gain_sum = 0;\n\n                for (int s = 0; s < MC_SAMPLES; ++s) {\n                    // Reject case\n                    DSU uf_rej = uf_selected;\n                    long long cost_rej = 0;\n                    for (const auto& se : scenarios[s]) {\n                        if (se.idx <= i) continue; // only future edges\n                        if (uf_rej.unite(se.u, se.v)) {\n                            cost_rej += se.w;\n                            if (uf_rej.comps == 1) break;\n                        }\n                    }\n\n                    // Adopt case\n                    DSU uf_acc = uf_selected;\n                    uf_acc.unite(cur.u, cur.v); // forced adoption\n                    long long cost_acc = li;\n                    for (const auto& se : scenarios[s]) {\n                        if (se.idx <= i) continue; // only future edges\n                        if (uf_acc.unite(se.u, se.v)) {\n                            cost_acc += se.w;\n                            if (uf_acc.comps == 1) break;\n                        }\n                    }\n\n                    gain_sum += (cost_rej - cost_acc);\n                }\n\n                ans = (gain_sum >= 0 ? 1 : 0);\n            }\n        }\n\n        if (ans == 1) {\n            uf_selected.unite(cur.u, cur.v);\n        }\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int r, c; };\nbool operator==(const Pos& a, const Pos& b){ return a.r == b.r && a.c == b.c; }\n\nstatic constexpr int BOARD = 30;\nstatic constexpr int BASE = 31;\nstatic constexpr int SZ = BASE * BASE;\nstatic constexpr long long INF64 = (1LL << 60);\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\ninline bool inBoard(int r, int c){ return 1 <= r && r <= BOARD && 1 <= c && c <= BOARD; }\ninline bool inBoard(const Pos& p){ return inBoard(p.r, p.c); }\ninline int pid(int r, int c){ return r * BASE + c; }\ninline int pid(const Pos& p){ return pid(p.r, p.c); }\nint manhattan(const Pos& a, const Pos& b){ return abs(a.r - b.r) + abs(a.c - b.c); }\n\nint dirFromUpper(char ch){\n    if(ch == 'U') return 0;\n    if(ch == 'D') return 1;\n    if(ch == 'L') return 2;\n    if(ch == 'R') return 3;\n    return -1;\n}\nint dirFromLower(char ch){\n    if(ch == 'u') return 0;\n    if(ch == 'd') return 1;\n    if(ch == 'l') return 2;\n    if(ch == 'r') return 3;\n    return -1;\n}\nchar lowerFromDelta(int dr, int dc){\n    if(dr == -1 && dc == 0) return 'u';\n    if(dr == 1 && dc == 0) return 'd';\n    if(dr == 0 && dc == -1) return 'l';\n    if(dr == 0 && dc == 1) return 'r';\n    return '.';\n}\nPos moved(const Pos& p, int d){ return Pos{p.r + DR[d], p.c + DC[d]}; }\n\nint petWeight(int t){\n    if(t == 1) return 1; // cow\n    if(t == 2) return 2; // pig\n    if(t == 3) return 3; // rabbit\n    if(t == 4) return 2; // dog\n    return 2;            // cat\n}\n\nstruct WallTask {\n    Pos target;\n    Pos standOut;\n    Pos standIn;\n    char buildOut;\n    char buildIn;\n};\n\nstruct RegionPlan {\n    int corner = 0; // 0:TL 1:TR 2:BL 3:BR\n    int s = 6;\n    vector<WallTask> tasks;\n    int gateIdx = 0;\n    Pos safeCell{1,1};\n    Pos decoyCell{30,30};\n\n    bool inRegion(const Pos& p) const {\n        if(corner == 0){\n            return (1 <= p.r && p.r <= s && 1 <= p.c && p.c <= s);\n        }else if(corner == 1){\n            int cL = 31 - s;\n            return (1 <= p.r && p.r <= s && cL <= p.c && p.c <= 30);\n        }else if(corner == 2){\n            int rT = 31 - s;\n            return (rT <= p.r && p.r <= 30 && 1 <= p.c && p.c <= s);\n        }else{\n            int rT = 31 - s;\n            int cL = 31 - s;\n            return (rT <= p.r && p.r <= 30 && cL <= p.c && p.c <= 30);\n        }\n    }\n};\n\nclass Solver {\npublic:\n    void run();\n\nprivate:\n    int N = 0, M = 0;\n    vector<Pos> pets;\n    vector<int> petType;\n    vector<Pos> humans;\n    bool passable[31][31]{};\n\n    RegionPlan plan;\n\n    enum Phase { BUILD, ENTER, CLOSE, DONE };\n    Phase phase = BUILD;\n\n    int gateCloser = -1;\n    int attemptCnt = 0;\n    int lastReplanTurn = -1000;\n    int lastBuiltCnt = 0;\n    int stallTurns = 0;\n    int closeStartTurn = -1;\n    int targetInside = 1;\n\n    // basics\n    void buildCounts(int humanCnt[31][31], int petCnt[31][31]) const;\n    bool canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const;\n\n    // path\n    void runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const;\n    void computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const;\n    char moveToward(int i, const Pos& target,\n                    const vector<array<int,SZ>>& dist,\n                    const vector<array<int,SZ>>& first) const;\n\n    // planning\n    RegionPlan generatePlan(int corner, int s) const;\n    void computeComponents(int compId[31][31], vector<int>& humCompCnt) const;\n    bool reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const;\n    long long evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                const int compId[31][31], const vector<int>& humCompCnt) const;\n    RegionPlan choosePlan(bool emergency, int avoidCorner) const;\n\n    // plan stats\n    int countInsideHumans(const RegionPlan& p) const;\n    int countInsidePets(const RegionPlan& p) const;\n    int builtNonGateWalls(const RegionPlan& p) const;\n    int remainingNonGateWalls(const RegionPlan& p) const;\n\n    // phase / replan\n    bool isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const;\n    int computeTargetInside(int turn, int insidePets, bool pressure) const;\n    void updatePhase(int turn, const int petCnt[31][31]);\n    bool shouldReplan(int turn, const int petCnt[31][31]) const;\n    bool replan(int turn);\n\n    // action generation\n    vector<char> decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]);\n\n    // simulation\n    void sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const;\n    void applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]);\n    void applyPetMoves(const vector<string>& pMoves);\n};\n\nvoid Solver::buildCounts(int humanCnt[31][31], int petCnt[31][31]) const {\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            humanCnt[r][c] = 0;\n            petCnt[r][c] = 0;\n        }\n    }\n    for(const auto& h: humans) humanCnt[h.r][h.c]++;\n    for(const auto& p: pets) petCnt[p.r][p.c]++;\n}\n\nbool Solver::canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    if(!inBoard(t)) return false;\n    if(humanCnt[t.r][t.c] > 0) return false;\n    if(petCnt[t.r][t.c] > 0) return false;\n    for(int d=0; d<4; d++){\n        int nr = t.r + DR[d], nc = t.c + DC[d];\n        if(!inBoard(nr, nc)) continue;\n        if(petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nvoid Solver::runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const {\n    dist.fill(-1);\n    first.fill(-1);\n    queue<Pos> q;\n    dist[pid(st)] = 0;\n    q.push(st);\n\n    while(!q.empty()){\n        Pos cur = q.front(); q.pop();\n        int cid = pid(cur);\n        for(int d=0; d<4; d++){\n            Pos nx{cur.r + DR[d], cur.c + DC[d]};\n            if(!inBoard(nx)) continue;\n            if(!passable[nx.r][nx.c]) continue;\n            int nid = pid(nx);\n            if(dist[nid] != -1) continue;\n            dist[nid] = dist[cid] + 1;\n            first[nid] = (cur == st ? d : first[cid]);\n            q.push(nx);\n        }\n    }\n}\n\nvoid Solver::computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const {\n    dist.resize(M);\n    first.resize(M);\n    for(int i=0; i<M; i++) runBFS(humans[i], dist[i], first[i]);\n}\n\nchar Solver::moveToward(int i, const Pos& target,\n                        const vector<array<int,SZ>>& dist,\n                        const vector<array<int,SZ>>& first) const {\n    if(!inBoard(target) || !passable[target.r][target.c]) return '.';\n    if(humans[i] == target) return '.';\n    int d = dist[i][pid(target)];\n    if(d <= 0) return '.';\n    int fd = first[i][pid(target)];\n    if(fd < 0) return '.';\n    return MOVE_CH[fd];\n}\n\nRegionPlan Solver::generatePlan(int corner, int s) const {\n    RegionPlan p;\n    p.corner = corner;\n    p.s = s;\n    p.tasks.clear();\n\n    auto addTask = [&](Pos target, Pos standOut, Pos standIn){\n        WallTask t;\n        t.target = target;\n        t.standOut = standOut;\n        t.standIn = standIn;\n        t.buildOut = lowerFromDelta(target.r - standOut.r, target.c - standOut.c);\n        t.buildIn = lowerFromDelta(target.r - standIn.r, target.c - standIn.c);\n        p.tasks.push_back(t);\n    };\n\n    Pos gate{-1,-1};\n\n    if(corner == 0){\n        for(int c=1; c<=s; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{s+1,1};\n        p.safeCell = Pos{1,1};\n        p.decoyCell = Pos{30,30};\n    }else if(corner == 1){\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{s+1,30};\n        p.safeCell = Pos{1,30};\n        p.decoyCell = Pos{30,1};\n    }else if(corner == 2){\n        int rT = 30 - s;\n        for(int c=1; c<=s; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{rT,1};\n        p.safeCell = Pos{30,1};\n        p.decoyCell = Pos{1,30};\n    }else{\n        int rT = 30 - s;\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{rT,30};\n        p.safeCell = Pos{30,30};\n        p.decoyCell = Pos{1,1};\n    }\n\n    p.gateIdx = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(p.tasks[i].target == gate){\n            p.gateIdx = i;\n            break;\n        }\n    }\n    return p;\n}\n\nvoid Solver::computeComponents(int compId[31][31], vector<int>& humCompCnt) const {\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) compId[r][c] = 0;\n\n    int cid = 0;\n    queue<Pos> q;\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            if(!passable[r][c] || compId[r][c] != 0) continue;\n            cid++;\n            compId[r][c] = cid;\n            q.push(Pos{r,c});\n            while(!q.empty()){\n                Pos cur = q.front(); q.pop();\n                for(int d=0; d<4; d++){\n                    int nr = cur.r + DR[d], nc = cur.c + DC[d];\n                    if(!inBoard(nr,nc) || !passable[nr][nc] || compId[nr][nc] != 0) continue;\n                    compId[nr][nc] = cid;\n                    q.push(Pos{nr,nc});\n                }\n            }\n        }\n    }\n\n    humCompCnt.assign(cid + 1, 0);\n    for(const auto& h: humans){\n        if(!passable[h.r][h.c]) continue;\n        int id = compId[h.r][h.c];\n        if(id >= 1 && id < (int)humCompCnt.size()) humCompCnt[id]++;\n    }\n}\n\nbool Solver::reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(!inBoard(p) || !passable[p.r][p.c]) return false;\n    int id = compId[p.r][p.c];\n    if(id <= 0 || id >= (int)humCompCnt.size()) return false;\n    return humCompCnt[id] > 0;\n}\n\nlong long Solver::evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                    const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(p.tasks.empty()) return INF64/2;\n    const WallTask& gate = p.tasks[p.gateIdx];\n\n    if(!inBoard(gate.target) || !passable[gate.target.r][gate.target.c]) return INF64/2;\n    if(!(reachableByHuman(gate.standIn, compId, humCompCnt) ||\n         reachableByHuman(gate.standOut, compId, humCompCnt))) return INF64/2;\n\n    int insidePets = 0, insidePetsW = 0;\n    int nearBoundary = 0, nearGate = 0;\n\n    for(int i=0; i<N; i++){\n        const Pos& pet = pets[i];\n        int w = petWeight(petType[i]);\n\n        if(p.inRegion(pet)){\n            insidePets++;\n            insidePetsW += w;\n        }\n\n        int md = 100;\n        for(const auto& t: p.tasks) md = min(md, manhattan(pet, t.target));\n        if(md <= 1) nearBoundary += 2*w;\n        else if(md == 2) nearBoundary += w;\n\n        if(manhattan(pet, gate.target) <= 2) nearGate += w;\n    }\n\n    int remaining = 0, impossible = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i];\n        if(!passable[t.target.r][t.target.c]) continue;\n        remaining++;\n        bool okOut = reachableByHuman(t.standOut, compId, humCompCnt);\n        bool okIn  = reachableByHuman(t.standIn, compId, humCompCnt);\n        if(!okOut && !okIn) impossible++;\n    }\n\n    int interiorWalls = 0;\n    if(p.corner == 0){\n        for(int r=1; r<=p.s; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 1){\n        int cL = 31 - p.s;\n        for(int r=1; r<=p.s; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 2){\n        int rT = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else{\n        int rT = 31 - p.s, cL = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }\n\n    long long humDist = 0;\n    for(const auto& h: humans) humDist += manhattan(h, gate.standOut);\n\n    long long score = 0;\n    score += 300000000LL * insidePets;\n    score +=  50000000LL * insidePetsW;\n    score +=    900000LL * nearGate;\n    score +=    250000LL * nearBoundary;\n    score +=  40000000LL * impossible;\n    score +=      4000LL * remaining;\n    score +=       120LL * humDist;\n    score +=    350000LL * interiorWalls;\n    score -= (emergency ? 1700LL : 3000LL) * p.s * p.s;\n\n    if(!passable[p.safeCell.r][p.safeCell.c]) score += 8000000LL;\n    if(avoidCorner >= 0 && p.corner == avoidCorner){\n        score += (emergency ? 300000LL : 1200000LL);\n    }\n    return score;\n}\n\nRegionPlan Solver::choosePlan(bool emergency, int avoidCorner) const {\n    int compId[31][31];\n    vector<int> humCompCnt;\n    computeComponents(compId, humCompCnt);\n\n    int sL = emergency ? 4 : 6;\n    int sR = emergency ? 7 : 10;\n\n    long long bestScore = INF64;\n    RegionPlan bestPlan;\n    bool found = false;\n\n    for(int corner=0; corner<4; corner++){\n        for(int s=sL; s<=sR; s++){\n            RegionPlan cand = generatePlan(corner, s);\n            long long sc = evaluateCandidate(cand, emergency, avoidCorner, compId, humCompCnt);\n            if(sc >= INF64/4) continue;\n            if(!found || sc < bestScore){\n                found = true;\n                bestScore = sc;\n                bestPlan = cand;\n            }\n        }\n    }\n\n    if(found) return bestPlan;\n    if(!plan.tasks.empty()) return plan;\n    return generatePlan(0, emergency ? 4 : 6);\n}\n\nint Solver::countInsideHumans(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& h: humans) if(p.inRegion(h)) cnt++;\n    return cnt;\n}\n\nint Solver::countInsidePets(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& x: pets) if(p.inRegion(x)) cnt++;\n    return cnt;\n}\n\nint Solver::builtNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int b = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(!passable[t.r][t.c]) b++;\n    }\n    return b;\n}\n\nint Solver::remainingNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int rem = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(passable[t.r][t.c]) rem++;\n    }\n    return rem;\n}\n\nbool Solver::isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const {\n    const Pos& g = p.tasks[p.gateIdx].target;\n    for(int r=max(1, g.r-2); r<=min(30, g.r+2); r++){\n        for(int c=max(1, g.c-2); c<=min(30, g.c+2); c++){\n            if(abs(r-g.r) + abs(c-g.c) > 2) continue;\n            if(petCnt[r][c] > 0) return true;\n        }\n    }\n    return false;\n}\n\nint Solver::computeTargetInside(int turn, int insidePets, bool pressure) const {\n    int t = max(1, M-1);\n    if(pressure) t = max(1, M-2);\n    if(insidePets >= 1) t = max(1, M-2);\n    if(turn >= 240) t = max(1, M-2);\n    if(turn >= 270) t = max(1, M-3);\n    if(turn >= 290) t = 1;\n    return min(t, M);\n}\n\nvoid Solver::updatePhase(int turn, const int petCnt[31][31]) {\n    if(phase == BUILD){\n        if(remainingNonGateWalls(plan) == 0){\n            phase = ENTER;\n            gateCloser = -1;\n            targetInside = max(1, M-1);\n        }\n    }\n\n    if(phase == ENTER){\n        int insideHum = countInsideHumans(plan);\n        int insidePets = countInsidePets(plan);\n        bool pressure = isGatePressured(plan, petCnt) || (insidePets > 0);\n        targetInside = computeTargetInside(turn, insidePets, pressure);\n\n        if(insideHum >= targetInside || (turn >= 289 && insideHum >= 1)){\n            phase = CLOSE;\n            closeStartTurn = turn;\n        }\n    }\n\n    if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(!passable[gt.r][gt.c]) phase = DONE;\n    }\n}\n\nbool Solver::shouldReplan(int turn, const int petCnt[31][31]) const {\n    if(phase == DONE) return false;\n    if(attemptCnt >= 2) return false;\n    if(turn - lastReplanTurn < 20) return false;\n\n    int rem = remainingNonGateWalls(plan);\n    int insidePets = countInsidePets(plan);\n    bool pressure = isGatePressured(plan, petCnt);\n\n    if(phase == BUILD){\n        if(rem > 0 && turn >= 190) return true;\n        if(rem > 0 && stallTurns >= 30 && turn <= 245) return true;\n        if(insidePets >= 2 && turn <= 175) return true;\n    }else if(phase == ENTER){\n        if(insidePets >= 2 && turn <= 220) return true;\n        if(turn >= 250 && countInsideHumans(plan) < max(1, M-2)) return true;\n    }else if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(passable[gt.r][gt.c] && closeStartTurn >= 0 &&\n           (turn - closeStartTurn) >= 40 && pressure && turn <= 245){\n            return true;\n        }\n    }\n    return false;\n}\n\nbool Solver::replan(int turn) {\n    bool emergency = (turn >= 140 || attemptCnt >= 1);\n    int avoid = plan.corner;\n    RegionPlan np = choosePlan(emergency, avoid);\n\n    if(np.corner == plan.corner && np.s == plan.s){\n        lastReplanTurn = turn; // cooldown\n        return false;\n    }\n\n    plan = np;\n    phase = BUILD;\n    gateCloser = -1;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n\n    attemptCnt++;\n    lastReplanTurn = turn;\n\n    if(remainingNonGateWalls(plan) == 0) phase = ENTER;\n    return true;\n}\n\nvector<char> Solver::decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n\n    vector<int> remaining;\n    for(int i=0; i<(int)plan.tasks.size(); i++){\n        if(i == plan.gateIdx) continue;\n        const Pos& t = plan.tasks[i].target;\n        if(passable[t.r][t.c]) remaining.push_back(i);\n    }\n    if(remaining.empty()) return act;\n\n    vector<char> isBuildable(plan.tasks.size(), 0);\n    vector<int> buildable;\n    for(int idx: remaining){\n        if(canBuildCell(plan.tasks[idx].target, humanCnt, petCnt)){\n            isBuildable[idx] = 1;\n            buildable.push_back(idx);\n        }\n    }\n\n    const vector<int>& cand = (!buildable.empty() ? buildable : remaining);\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    bool reserved[31][31]{};\n    vector<int> useCnt(plan.tasks.size(), 0);\n\n    // immediate build\n    for(int i=0; i<M; i++){\n        for(int idx: cand){\n            if(!isBuildable[idx]) continue;\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n\n            if(humans[i] == t.standOut){\n                act[i] = t.buildOut;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n            if(humans[i] == t.standIn){\n                act[i] = t.buildIn;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(act[i] != '.') continue;\n\n        int bestCost = 1e9;\n        int bestIdx = -1, bestMode = 0, bestD = -1;\n\n        for(int idx: cand){\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n            bool buildNow = isBuildable[idx];\n\n            for(int mode=0; mode<2; mode++){\n                Pos st = (mode == 0 ? t.standOut : t.standIn);\n                if(!inBoard(st) || !passable[st.r][st.c]) continue;\n                int d = dist[i][pid(st)];\n                if(d < 0) continue;\n                if(d == 0 && !buildNow) continue;\n\n                int cost = d*10 + useCnt[idx]*18 + (mode==1 ? 8 : 0) + (buildNow ? 0 : 30);\n                if(cost < bestCost){\n                    bestCost = cost;\n                    bestIdx = idx;\n                    bestMode = mode;\n                    bestD = d;\n                }\n            }\n        }\n\n        if(bestIdx == -1) continue;\n\n        useCnt[bestIdx]++;\n        const auto& t = plan.tasks[bestIdx];\n        bool buildNow = isBuildable[bestIdx];\n\n        if(bestD == 0 && buildNow && !reserved[t.target.r][t.target.c]){\n            act[i] = (bestMode == 0 ? t.buildOut : t.buildIn);\n            reserved[t.target.r][t.target.c] = true;\n        }else if(bestD > 0){\n            Pos st = (bestMode == 0 ? t.standOut : t.standIn);\n            int fd = first[i][pid(st)];\n            if(fd >= 0) act[i] = MOVE_CH[fd];\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)humanCnt;\n    (void)petCnt;\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        int da = dist[a][pid(gate.standIn)];\n        int db = dist[b][pid(gate.standIn)];\n        bool ra = (da >= 0), rb = (db >= 0);\n        if(ra != rb) return ra > rb;\n\n        bool ia = plan.inRegion(humans[a]);\n        bool ib = plan.inRegion(humans[b]);\n        if(ia != ib) return ia > ib;\n\n        int ka = ra ? da : 1000000;\n        int kb = rb ? db : 1000000;\n        if(ka != kb) return ka < kb;\n        return a < b;\n    });\n\n    vector<char> insideSet(M, 0);\n    int need = max(1, min(targetInside, M));\n    int got = 0;\n    for(int id: ord){\n        int d = dist[id][pid(gate.standIn)];\n        bool can = (d >= 0) || plan.inRegion(humans[id]);\n        if(!can) continue;\n        insideSet[id] = 1;\n        got++;\n        if(got >= need) break;\n    }\n\n    if(got == 0){\n        int fb = -1, best = 1e9;\n        for(int i=0; i<M; i++){\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; fb = i; }\n        }\n        if(fb == -1) fb = 0;\n        insideSet[fb] = 1;\n    }\n\n    gateCloser = -1;\n    int best = 1e9;\n    for(int i=0; i<M; i++){\n        if(!insideSet[i]) continue;\n        int d = dist[i][pid(gate.standIn)];\n        if(d >= 0 && d < best){ best = d; gateCloser = i; }\n    }\n    if(gateCloser == -1){\n        best = 1e9;\n        for(int i=0; i<M; i++){\n            if(!insideSet[i]) continue;\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; gateCloser = i; }\n        }\n    }\n    if(gateCloser == -1){\n        for(int i=0; i<M; i++) if(insideSet[i]) { gateCloser = i; break; }\n        if(gateCloser == -1) gateCloser = 0;\n    }\n\n    for(int i=0; i<M; i++){\n        if(insideSet[i]){\n            Pos tgt;\n            if(i == gateCloser){\n                tgt = gate.standIn;\n                if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n            }else{\n                if(plan.inRegion(humans[i])) tgt = plan.safeCell;\n                else{\n                    tgt = gate.standIn;\n                    if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n                }\n            }\n            act[i] = moveToward(i, tgt, dist, first);\n        }else{\n            act[i] = moveToward(i, plan.decoyCell, dist, first);\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    int builder = -1;\n    int buildSide = 0; // 0=in 1=out\n    int bestCost = 1e9;\n\n    for(int i=0; i<M; i++){\n        for(int side=0; side<2; side++){\n            Pos st = (side == 0 ? gate.standIn : gate.standOut);\n            if(!inBoard(st) || !passable[st.r][st.c]) continue;\n            int d = dist[i][pid(st)];\n            if(d < 0) continue;\n\n            int cost = d*10 + (side==1 ? 4 : 0);\n            if(gateCloser >= 0 && i != gateCloser) cost += 2;\n            if(!plan.inRegion(humans[i])) cost += 1;\n            if(d == 0 && canBuildCell(gate.target, humanCnt, petCnt)) cost -= 1000;\n\n            if(cost < bestCost){\n                bestCost = cost;\n                builder = i;\n                buildSide = side;\n            }\n        }\n    }\n\n    if(builder != -1){\n        Pos st = (buildSide == 0 ? gate.standIn : gate.standOut);\n        if(humans[builder] == st){\n            if(canBuildCell(gate.target, humanCnt, petCnt)){\n                act[builder] = (buildSide == 0 ? gate.buildIn : gate.buildOut);\n            }\n        }else{\n            act[builder] = moveToward(builder, st, dist, first);\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(i == builder) continue;\n        Pos tgt = plan.inRegion(humans[i]) ? plan.safeCell : plan.decoyCell;\n        act[i] = moveToward(i, tgt, dist, first);\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)turn;\n    if(phase == DONE) return vector<char>(M, '.');\n    if(phase == BUILD) return decideBuildActions(humanCnt, petCnt);\n    if(phase == ENTER) return decideEnterActions(humanCnt, petCnt);\n    return decideCloseActions(humanCnt, petCnt);\n}\n\nvoid Solver::sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    bool buildNow[31][31]{};\n\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }else{\n            act[i] = '.';\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to) || !passable[to.r][to.c] || buildNow[to.r][to.c]){\n            act[i] = '.';\n        }\n    }\n}\n\nvoid Solver::applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) {\n    bool passBefore[31][31];\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passBefore[r][c] = passable[r][c];\n\n    bool buildNow[31][31]{};\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }\n    }\n\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) if(buildNow[r][c]) passable[r][c] = false;\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to)) continue;\n        if(!passBefore[to.r][to.c]) continue;\n        if(buildNow[to.r][to.c]) continue;\n        humans[i] = to;\n    }\n}\n\nvoid Solver::applyPetMoves(const vector<string>& pMoves) {\n    for(int i=0; i<N; i++){\n        if(pMoves[i] == \".\") continue;\n        for(char ch: pMoves[i]){\n            int d = dirFromUpper(ch);\n            if(d < 0) continue;\n            pets[i].r += DR[d];\n            pets[i].c += DC[d];\n        }\n    }\n}\n\nvoid Solver::run() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if(!(cin >> N)) return;\n    pets.resize(N);\n    petType.resize(N);\n    for(int i=0; i<N; i++) cin >> pets[i].r >> pets[i].c >> petType[i];\n    cin >> M;\n    humans.resize(M);\n    for(int i=0; i<M; i++) cin >> humans[i].r >> humans[i].c;\n\n    for(int r=0; r<=BOARD; r++) for(int c=0; c<=BOARD; c++) passable[r][c] = false;\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passable[r][c] = true;\n\n    plan = choosePlan(false, -1);\n\n    phase = BUILD;\n    gateCloser = -1;\n    attemptCnt = 0;\n    lastReplanTurn = -1000;\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n\n    for(int turn=0; turn<300; turn++){\n        int humanCnt[31][31], petCnt[31][31];\n        buildCounts(humanCnt, petCnt);\n\n        if(phase == BUILD){\n            int b = builtNonGateWalls(plan);\n            if(b > lastBuiltCnt){\n                lastBuiltCnt = b;\n                stallTurns = 0;\n            }else{\n                stallTurns++;\n            }\n        }else{\n            stallTurns = 0;\n        }\n\n        updatePhase(turn, petCnt);\n\n        if(shouldReplan(turn, petCnt)){\n            bool changed = replan(turn);\n            if(changed) updatePhase(turn, petCnt);\n        }\n\n        vector<char> actions = decideActions(turn, humanCnt, petCnt);\n        sanitizeActions(actions, humanCnt, petCnt);\n\n        string out;\n        out.reserve(M);\n        for(char ch: actions) out.push_back(ch);\n        cout << out << '\\n';\n        cout.flush();\n\n        applyActions(actions, humanCnt, petCnt);\n\n        vector<string> pMoves(N);\n        for(int i=0; i<N; i++){\n            if(!(cin >> pMoves[i])) return;\n        }\n        applyPetMoves(pMoves);\n    }\n}\n\nint main(){\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t 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\nclass Solver {\n    static constexpr int H = 20;\n    static constexpr int W = 20;\n    static constexpr int N = H * W;\n    static constexpr int L = 200;\n\n    int si, sj, ti, tj;\n    int start, target;\n    double p, q;\n    string h[H], v[H - 1];\n\n    int to_raw[N][4];\n    int to_eval[N][4];\n\n    vector<array<double, N>> fw, bw, ub;\n    array<double, L + 1> pref{};\n\n    vector<uint8_t> seq, bestSeq;\n    double curScore = -1e100, bestScore = -1e100;\n\n    vector<pair<double, vector<uint8_t>>> elite;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver()\n        : fw(L + 1), bw(L + 1), ub(L + 1), seq(L), bestSeq(L),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void solve() {\n        readInput();\n        buildTransitions();\n        st = chrono::steady_clock::now();\n\n        precomputeUpperBound();\n\n        vector<vector<uint8_t>> cands;\n        buildInitialCandidates(cands);\n\n        elite.clear();\n        bestScore = -1e100;\n        for (auto &c : cands) {\n            seq = c;\n            curScore = recompute();\n            addElite(seq, curScore);\n        }\n\n        const double TL = 1.95;\n\n        // Refine top initial seeds\n        {\n            auto init = elite;\n            int use = min<int>(4, init.size());\n            for (int i = 0; i < use; i++) {\n                if (now() > 0.90) break;\n                seq = init[i].second;\n                curScore = recompute();\n                double dl = min(1.00, now() + 0.12);\n                improve(dl, 2);\n                addElite(seq, curScore);\n            }\n        }\n\n        // Iterated local search\n        while (now() < TL - 0.03) {\n            int es = min<int>(5, elite.size());\n            int pick = 0;\n            int r = rng.nextInt(100);\n            if (es >= 2) {\n                if (r < 65) pick = 0;\n                else if (r < 90) pick = rng.nextInt(min(es, 2));\n                else pick = rng.nextInt(es);\n            }\n\n            seq = elite[pick].second;\n            mutateCurrent();\n            curScore = recompute();\n\n            double rem = TL - now();\n            if (rem <= 0) break;\n            double budget = min(0.05, rem * 0.70);\n            improve(now() + budget, 2);\n\n            addElite(seq, curScore);\n        }\n\n        // Final polish\n        seq = bestSeq;\n        curScore = recompute();\n        improve(TL, 4);\n\n        const char mp[4] = {'U', 'D', 'L', 'R'};\n        string ans(L, 'U');\n        for (int i = 0; i < L; i++) ans[i] = mp[bestSeq[i]];\n        cout << ans << '\\n';\n    }\n\nprivate:\n    inline int id(int i, int j) const { return i * W + j; }\n\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void readInput() {\n        cin >> si >> sj >> ti >> tj >> p;\n        for (int i = 0; i < H; i++) cin >> h[i];\n        for (int i = 0; i < H - 1; i++) cin >> v[i];\n        start = id(si, sj);\n        target = id(ti, tj);\n        q = 1.0 - p;\n    }\n\n    void buildTransitions() {\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                int s = id(i, j);\n\n                // U\n                if (i == 0 || v[i - 1][j] == '1') to_raw[s][0] = s;\n                else to_raw[s][0] = id(i - 1, j);\n\n                // D\n                if (i == H - 1 || v[i][j] == '1') to_raw[s][1] = s;\n                else to_raw[s][1] = id(i + 1, j);\n\n                // L\n                if (j == 0 || h[i][j - 1] == '1') to_raw[s][2] = s;\n                else to_raw[s][2] = id(i, j - 1);\n\n                // R\n                if (j == W - 1 || h[i][j] == '1') to_raw[s][3] = s;\n                else to_raw[s][3] = id(i, j + 1);\n            }\n        }\n\n        for (int s = 0; s < N; s++) {\n            for (int a = 0; a < 4; a++) to_eval[s][a] = to_raw[s][a];\n        }\n        // absorbing target\n        for (int a = 0; a < 4; a++) to_eval[target][a] = target;\n    }\n\n    // Adaptive-policy upper bound:\n    // ub[r][s] = max expected additional objective for r remaining turns from state s.\n    // r-turn objective form: sum_{i=1}^{r-1} I(target at i) + 201*I(target at r)\n    void precomputeUpperBound() {\n        ub[0].fill(0.0);\n        for (int r = 1; r <= L; r++) {\n            int coef = (r == 1 ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double rs = (s == target ? (double)coef : 0.0);\n                    double rn = (n == target ? (double)coef : 0.0);\n                    double cand;\n                    if (n == s) {\n                        cand = rs + ub[r - 1][s];\n                    } else {\n                        cand = p * (rs + ub[r - 1][s]) + q * (rn + ub[r - 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                ub[r][s] = best;\n            }\n        }\n    }\n\n    void stepDist(const array<double, N>& cur, int a, array<double, N>& nxt) const {\n        nxt.fill(0.0);\n        for (int s = 0; s < N; s++) {\n            double pr = cur[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            if (n == s) {\n                nxt[s] += pr;\n            } else {\n                double mv = pr * q;\n                nxt[s] += pr - mv;\n                nxt[n] += mv;\n            }\n        }\n    }\n\n    int bestActionUB(const array<double, N>& dist, int step) const {\n        int remAfter = L - (step + 1);\n        int coef = (step + 1 == L ? 201 : 1);\n        const auto &U = ub[remAfter];\n\n        double bestVal = -1e100;\n        int bestA = 0;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n            for (int s = 0; s < N; s++) {\n                double pr = dist[s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                double rs = (s == target ? (double)coef : 0.0);\n                double rn = (n == target ? (double)coef : 0.0);\n                if (n == s) {\n                    val += pr * (rs + U[s]);\n                } else {\n                    val += pr * (p * (rs + U[s]) + q * (rn + U[n]));\n                }\n            }\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n        return bestA;\n    }\n\n    vector<int> shortestPathBFS() {\n        vector<int> dist(N, -1), par(N, -1), pdir(N, -1);\n        queue<int> qu;\n        dist[start] = 0;\n        qu.push(start);\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            if (s == target) break;\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (dist[n] != -1) continue;\n                dist[n] = dist[s] + 1;\n                par[n] = s;\n                pdir[n] = a;\n                qu.push(n);\n            }\n        }\n\n        vector<int> path;\n        if (dist[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> weightedPath(double penUL, double noise) {\n        const double INF = 1e100;\n        vector<double> d(N, INF), bias(N);\n        for (int s = 0; s < N; s++) bias[s] = rng.nextDouble();\n\n        vector<int> par(N, -1), pdir(N, -1);\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        d[start] = 0.0;\n        pq.push({0.0, start});\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!pq.empty()) {\n            auto [cd, s] = pq.top();\n            pq.pop();\n            if (cd > d[s] + 1e-15) continue;\n            if (s == target) break;\n\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n\n                double w = 1.0 + ((a == 0 || a == 2) ? penUL : 0.0) + noise * bias[n];\n                double nd = cd + w;\n                if (nd < d[n]) {\n                    d[n] = nd;\n                    par[n] = s;\n                    pdir[n] = a;\n                    pq.push({nd, n});\n                }\n            }\n        }\n\n        vector<int> path;\n        if (par[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> distToTarget() {\n        const int INF = 1e9;\n        vector<int> d(N, INF);\n        queue<int> qu;\n        d[target] = 0;\n        qu.push(target);\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            for (int a = 0; a < 4; a++) {\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (d[n] > d[s] + 1) {\n                    d[n] = d[s] + 1;\n                    qu.push(n);\n                }\n            }\n        }\n        return d;\n    }\n\n    vector<uint8_t> buildPathSeed(const vector<int>& path, int rep) {\n        vector<uint8_t> out;\n        out.reserve(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int dir : path) {\n            for (int k = 0; k < rep && (int)out.size() < L; k++) {\n                out.push_back((uint8_t)dir);\n                stepDist(cur, dir, nxt);\n                cur = nxt;\n            }\n            if ((int)out.size() == L) break;\n        }\n\n        while ((int)out.size() < L) {\n            int t = (int)out.size();\n            int a = bestActionUB(cur, t);\n            out.push_back((uint8_t)a);\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n        return out;\n    }\n\n    vector<uint8_t> greedyUBSeed() {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int a = bestActionUB(cur, t);\n            out[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n        return out;\n    }\n\n    vector<uint8_t> greedyStaticSeed(const vector<double>& val) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int bestA = 0;\n            double bestV = -1e100;\n\n            for (int a = 0; a < 4; a++) {\n                double vexp = 0.0;\n                for (int s = 0; s < N; s++) {\n                    double pr = cur[s];\n                    if (pr == 0.0) continue;\n                    int n = to_eval[s][a];\n                    if (n == s) {\n                        vexp += pr * val[s];\n                    } else {\n                        vexp += pr * (p * val[s] + q * val[n]);\n                    }\n                }\n                if (vexp > bestV) {\n                    bestV = vexp;\n                    bestA = a;\n                }\n            }\n\n            out[t] = (uint8_t)bestA;\n            stepDist(cur, bestA, nxt);\n            cur = nxt;\n        }\n        return out;\n    }\n\n    vector<uint8_t> beamSeed(int B) {\n        struct Node {\n            array<float, N> dist;\n            double score;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double score;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> beam(1);\n        beam[0].dist.fill(0.0f);\n        beam[0].dist[start] = 1.0f;\n        beam[0].score = 0.0;\n        beam[0].key = ub[L][start];\n\n        vector<vector<pair<int, uint8_t>>> trace(L + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 4);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            if (a.key != b.key) return a.key > b.key;\n            return a.score > b.score;\n        };\n\n        for (int d = 0; d < L; d++) {\n            int coef = (d + 1 == L ? 201 : 1);\n            int rem = L - (d + 1);\n\n            cand.clear();\n            for (int i = 0; i < (int)beam.size(); i++) {\n                const auto &nd = beam[i];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = i;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    double heur = 0.0;\n\n                    for (int s = 0; s < N; s++) {\n                        float prf = nd.dist[s];\n                        if (prf == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += prf;\n                            if (s == target) inc += (double)prf;\n                            if (rem > 0) heur += (double)prf * ub[rem][s];\n                        } else {\n                            float ps = (float)(prf * p);\n                            float pn = (float)(prf * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                            if (rem > 0) {\n                                heur += (double)ps * ub[rem][s] + (double)pn * ub[rem][n];\n                            }\n                        }\n                    }\n\n                    ch.score = nd.score + coef * inc;\n                    ch.key = ch.score + heur;\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            vector<Node> nxt(cand.size());\n            trace[d + 1].resize(cand.size());\n            for (int i = 0; i < (int)cand.size(); i++) {\n                nxt[i].dist = std::move(cand[i].dist);\n                nxt[i].score = cand[i].score;\n                nxt[i].key = cand[i].key;\n                trace[d + 1][i] = {cand[i].par, cand[i].act};\n            }\n            beam.swap(nxt);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)beam.size(); i++) {\n            if (beam[i].score > beam[bestIdx].score) bestIdx = i;\n        }\n\n        vector<uint8_t> out(L);\n        int idx = bestIdx;\n        for (int d = L; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            out[d - 1] = act;\n            idx = par;\n        }\n        return out;\n    }\n\n    void buildInitialCandidates(vector<vector<uint8_t>>& cands) {\n        auto sp = shortestPathBFS();\n\n        int baseRep = (int)llround(1.4 / max(1e-9, q));\n        baseRep = max(1, min(6, baseRep));\n\n        set<int> repsSet;\n        repsSet.insert(max(1, baseRep - 1));\n        repsSet.insert(baseRep);\n        repsSet.insert(min(7, baseRep + 1));\n        vector<int> reps(repsSet.begin(), repsSet.end());\n\n        vector<int> repsSmall;\n        repsSmall.push_back(baseRep);\n        if (baseRep + 1 <= 7) repsSmall.push_back(baseRep + 1);\n\n        if (!sp.empty()) {\n            for (int rep : reps) cands.push_back(buildPathSeed(sp, rep));\n        }\n\n        vector<pair<double, double>> params = {\n            {0.0, 0.0}, {0.4, 0.0}, {0.8, 0.0},\n            {0.0, 0.15}, {0.4, 0.15}, {0.8, 0.15},\n            {0.2, 0.35}, {0.6, 0.35}\n        };\n        for (auto [pen, noise] : params) {\n            auto pth = weightedPath(pen, noise);\n            if (pth.empty()) continue;\n            for (int rep : repsSmall) cands.push_back(buildPathSeed(pth, rep));\n        }\n\n        cands.push_back(greedyUBSeed());\n\n        int bw = 120;\n        if (now() > 0.35) bw = 80;\n        cands.push_back(beamSeed(bw));\n\n        auto d = distToTarget();\n        vector<double> val1(N), val2(N);\n        for (int s = 0; s < N; s++) {\n            val1[s] = -1.0 * d[s];\n            val2[s] = -1.0 * d[s] * d[s];\n        }\n        cands.push_back(greedyStaticSeed(val1));\n        cands.push_back(greedyStaticSeed(val2));\n\n        // Baselines\n        vector<uint8_t> pat(L);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 1 : 3); // D then R\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 3 : 1); // R then D\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i & 1 ? 3 : 1); // D,R,D,R...\n        cands.push_back(pat);\n    }\n\n    double recompute() {\n        fw[0].fill(0.0);\n        fw[0][start] = 1.0;\n        pref[0] = 0.0;\n\n        for (int t = 0; t < L; t++) {\n            fw[t + 1].fill(0.0);\n            int a = seq[t];\n            for (int s = 0; s < N; s++) {\n                double pr = fw[t][s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                if (n == s) {\n                    fw[t + 1][s] += pr;\n                } else {\n                    double mv = pr * q;\n                    fw[t + 1][s] += pr - mv;\n                    fw[t + 1][n] += mv;\n                }\n            }\n            int coef = (t + 1 == L ? 201 : 1);\n            pref[t + 1] = pref[t] + coef * fw[t + 1][target];\n        }\n\n        bw[L].fill(0.0);\n        for (int t = L - 1; t >= 0; t--) {\n            int a = seq[t];\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                int n = to_eval[s][a];\n                double rs = (s == target ? (double)coef : 0.0);\n                double rn = (n == target ? (double)coef : 0.0);\n                if (n == s) {\n                    bw[t][s] = rs + bw[t + 1][s];\n                } else {\n                    bw[t][s] = p * (rs + bw[t + 1][s]) + q * (rn + bw[t + 1][n]);\n                }\n            }\n        }\n\n        return pref[L];\n    }\n\n    double evalChange(int pos, int a) const {\n        double total = pref[pos];\n        int coef = (pos + 1 == L ? 201 : 1);\n\n        const auto &dist = fw[pos];\n        const auto &suf = bw[pos + 1];\n\n        for (int s = 0; s < N; s++) {\n            double pr = dist[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            double rs = (s == target ? (double)coef : 0.0);\n            double rn = (n == target ? (double)coef : 0.0);\n            double v;\n            if (n == s) {\n                v = rs + suf[s];\n            } else {\n                v = p * (rs + suf[s]) + q * (rn + suf[n]);\n            }\n            total += pr * v;\n        }\n\n        return total;\n    }\n\n    void improve(double deadline, int maxSweeps) {\n        array<int, L> ord;\n        iota(ord.begin(), ord.end(), 0);\n\n        int sweeps = 0;\n        while (sweeps < maxSweeps && now() < deadline) {\n            sweeps++;\n\n            for (int i = L - 1; i > 0; i--) {\n                int j = rng.nextInt(i + 1);\n                swap(ord[i], ord[j]);\n            }\n\n            bool improved = false;\n            for (int ii = 0; ii < L; ii++) {\n                if ((ii & 15) == 0 && now() >= deadline) return;\n\n                int pos = ord[ii];\n                int curA = seq[pos];\n                int bestA = curA;\n                double bestLocal = curScore;\n\n                for (int a = 0; a < 4; a++) {\n                    if (a == curA) continue;\n                    double sc = evalChange(pos, a);\n                    if (sc > bestLocal + 1e-12) {\n                        bestLocal = sc;\n                        bestA = a;\n                    }\n                }\n\n                if (bestA != curA) {\n                    seq[pos] = (uint8_t)bestA;\n                    curScore = recompute();\n                    improved = true;\n                    if (curScore > bestScore) {\n                        bestScore = curScore;\n                        bestSeq = seq;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    void addElite(const vector<uint8_t>& s, double sc) {\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestSeq = s;\n        }\n\n        for (auto &e : elite) {\n            if (e.second == s) {\n                if (sc > e.first) e.first = sc;\n                sort(elite.begin(), elite.end(),\n                     [](const auto& a, const auto& b) { return a.first > b.first; });\n                return;\n            }\n        }\n\n        elite.push_back({sc, s});\n        sort(elite.begin(), elite.end(),\n             [](const auto& a, const auto& b) { return a.first > b.first; });\n        if ((int)elite.size() > 8) elite.resize(8);\n    }\n\n    array<double, N> prefixDist(const vector<uint8_t>& s, int len) const {\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n        for (int t = 0; t < len; t++) {\n            nxt.fill(0.0);\n            int a = s[t];\n            for (int u = 0; u < N; u++) {\n                double pr = cur[u];\n                if (pr == 0.0) continue;\n                int n = to_eval[u][a];\n                if (n == u) {\n                    nxt[u] += pr;\n                } else {\n                    double mv = pr * q;\n                    nxt[u] += pr - mv;\n                    nxt[n] += mv;\n                }\n            }\n            cur = nxt;\n        }\n        return cur;\n    }\n\n    void mutateCurrent() {\n        int type = rng.nextInt(100);\n\n        if (type < 55) {\n            int m = 1 + rng.nextInt(4);\n            for (int k = 0; k < m; k++) {\n                int pos = rng.nextInt(L);\n                seq[pos] = (uint8_t)rng.nextInt(4);\n            }\n        } else if (type < 85) {\n            int len = 5 + rng.nextInt(25);\n            int l = rng.nextInt(L - len + 1);\n            for (int i = 0; i < len; i++) seq[l + i] = (uint8_t)rng.nextInt(4);\n        } else {\n            int cut = rng.nextInt(L - 5);\n            auto cur = prefixDist(seq, cut);\n            array<double, N> nxt{};\n            for (int t = cut; t < L; t++) {\n                int a = bestActionUB(cur, t);\n                if (rng.nextInt(100) < 20) a = rng.nextInt(4);\n                seq[t] = (uint8_t)a;\n                stepDist(cur, a, nxt);\n                cur = nxt;\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int C = N * N;\nstatic constexpr int S = C * 4;\n\nint 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\nuint8_t SIDE[8] = {\n    (1u << 0) | (1u << 1), // 0\n    (1u << 0) | (1u << 3), // 1\n    (1u << 2) | (1u << 3), // 2\n    (1u << 1) | (1u << 2), // 3\n    0b1111,                // 4\n    0b1111,                // 5\n    (1u << 0) | (1u << 2), // 6\n    (1u << 1) | (1u << 3), // 7\n};\n\nint ROT1[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nint ROT[8][4];\nint NEI[C][4];\nint OPP[4] = {2, 3, 0, 1};\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463393265ull) {\n        x = seed ^ 0x9e3779b97f4a7c15ULL;\n        if (x == 0) x = 88172645463393265ull;\n        for (int i = 0; i < 8; i++) next_u64();\n    }\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t next_u32() { return static_cast<uint32_t>(next_u64()); }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Eval {\n    int l1 = 0, l2 = 0, l3 = 0, l4 = 0;\n    int loopCnt = 0;\n    int sumLoop = 0;\n    int matched = 0;\n    long long contest = 0;\n};\n\ninline bool better_best(const Eval& a, const Eval& b) {\n    if (a.contest != b.contest) return a.contest > b.contest;\n    if (a.l1 != b.l1) return a.l1 > b.l1;\n    if (a.l2 != b.l2) return a.l2 > b.l2;\n    if (a.l3 != b.l3) return a.l3 > b.l3;\n    if (a.sumLoop != b.sumLoop) return a.sumLoop > b.sumLoop;\n    return a.matched > b.matched;\n}\n\ninline double objective(const Eval& e, double p) {\n    double core;\n    if (e.loopCnt >= 2) {\n        core = (double)e.l1 * (double)e.l2; // contest score\n    } else {\n        core = -3000.0 + 25.0 * e.l1 + 8.0 * e.sumLoop + 120.0 * e.loopCnt;\n    }\n    double early = 3.5 * e.sumLoop + 1.2 * e.l1 + 1.0 * e.l2 + 0.6 * e.l3 + 0.05 * e.matched;\n    double w = 0.2 + 0.8 * p; // p=1 -> pure core\n    return (1.0 - w) * early + w * core;\n}\n\ninline double elapsed_sec(const chrono::steady_clock::time_point& st) {\n    return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n}\n\nstruct Evaluator {\n    int nxt[S];\n    int partner[S];\n    int vis[S];\n    int posi[S];\n    int stk[S];\n    uint8_t done[S];\n    uint8_t canon[S];\n\n    Eval eval(const array<uint8_t, C>& board) {\n        uint8_t mask[C];\n        for (int c = 0; c < C; c++) mask[c] = SIDE[board[c]];\n\n        int matched = 0;\n        for (int i = 0; i < N; i++) {\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                int c = base + j;\n                uint8_t m = mask[c];\n                if (j + 1 < N) {\n                    if ((m & (1 << 2)) && (mask[c + 1] & (1 << 0))) matched++;\n                }\n                if (i + 1 < N) {\n                    if ((m & (1 << 3)) && (mask[c + N] & (1 << 1))) matched++;\n                }\n            }\n        }\n\n        for (int c = 0; c < C; c++) {\n            int t = board[c];\n            int c4 = c << 2;\n            for (int d = 0; d < 4; d++) {\n                int s = c4 | d;\n                int d2 = TO[t][d];\n                if (d2 < 0) {\n                    nxt[s] = -1;\n                    partner[s] = -1;\n                    continue;\n                }\n                partner[s] = c4 | d2;\n                int nc = NEI[c][d2];\n                if (nc < 0) {\n                    nxt[s] = -1;\n                    continue;\n                }\n                if (mask[nc] & (1 << OPP[d2])) nxt[s] = (nc << 2) | OPP[d2];\n                else nxt[s] = -1;\n            }\n        }\n\n        memset(done, 0, sizeof(done));\n        memset(vis, 0, sizeof(vis));\n        memset(canon, 0, sizeof(canon));\n\n        int iter = 1;\n        int loopCnt = 0;\n        int sumLoop = 0;\n        int t0 = 0, t1 = 0, t2 = 0, t3 = 0;\n\n        auto push_len = [&](int len) {\n            if (len > t0) {\n                t3 = t2; t2 = t1; t1 = t0; t0 = len;\n            } else if (len > t1) {\n                t3 = t2; t2 = t1; t1 = len;\n            } else if (len > t2) {\n                t3 = t2; t2 = len;\n            } else if (len > t3) {\n                t3 = len;\n            }\n        };\n\n        for (int s0 = 0; s0 < S; s0++) {\n            if (done[s0]) continue;\n\n            int cur = s0;\n            int top = 0;\n            while (cur != -1 && !done[cur] && vis[cur] != iter) {\n                vis[cur] = iter;\n                posi[cur] = top;\n                stk[top++] = cur;\n                cur = nxt[cur];\n            }\n\n            if (cur != -1 && !done[cur] && vis[cur] == iter) {\n                int st = posi[cur];\n                int len = top - st;\n                int can = INT_MAX;\n                for (int k = st; k < top; k++) {\n                    int v = stk[k];\n                    int p = partner[v];\n                    int m = (v < p ? v : p);\n                    if (m < can) can = m;\n                }\n                if (!canon[can]) {\n                    canon[can] = 1;\n                    loopCnt++;\n                    sumLoop += len;\n                    push_len(len);\n                }\n            }\n\n            for (int k = 0; k < top; k++) done[stk[k]] = 1;\n            iter++;\n        }\n\n        Eval e;\n        e.l1 = t0;\n        e.l2 = t1;\n        e.l3 = t2;\n        e.l4 = t3;\n        e.loopCnt = loopCnt;\n        e.sumLoop = sumLoop;\n        e.matched = matched;\n        e.contest = (loopCnt >= 2 ? 1LL * t0 * t1 : 0LL);\n        return e;\n    }\n};\n\ninline int cell_badness(int c, const array<uint8_t, C>& board) {\n    uint8_t m = SIDE[board[c]];\n    int bad = 0;\n    for (int d = 0; d < 4; d++) {\n        int nc = NEI[c][d];\n        int b1 = (m >> d) & 1;\n        if (nc < 0) {\n            if (b1) bad += 2;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 != b2) bad += 1;\n        }\n    }\n    return bad;\n}\n\ninline int local_potential(int c, uint8_t cand, const array<uint8_t, C>& board) {\n    int score = 0;\n    uint8_t m = SIDE[cand];\n\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) score -= 6;\n            continue;\n        }\n        int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n        if (b1 && b2) score += 4;\n        else if (b1 ^ b2) score -= 3;\n    }\n\n    for (int d = 0; d < 4; d++) {\n        int d2 = TO[cand][d];\n        if (d2 < 0) continue;\n        int nc = NEI[c][d2];\n        if (nc >= 0 && (SIDE[board[nc]] & (1 << OPP[d2]))) score += 1;\n        else score -= 1;\n    }\n    return score;\n}\n\nvoid improve_connectivity(\n    array<uint8_t, C>& board,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng,\n    int passes\n) {\n    array<int, C> ord;\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int p = 0; p < passes; p++) {\n        for (int i = C - 1; i > 0; i--) {\n            int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n            swap(ord[i], ord[j]);\n        }\n        for (int id = 0; id < C; id++) {\n            int c = ord[id];\n            int bestScore = INT_MIN;\n            uint8_t bestState = board[c];\n            for (int k = 0; k < possCnt[c]; k++) {\n                uint8_t cand = poss[c][k];\n                int sc = local_potential(c, cand, board);\n                if (sc > bestScore || (sc == bestScore && (rng.next_u32() & 1))) {\n                    bestScore = sc;\n                    bestState = cand;\n                }\n            }\n            board[c] = bestState;\n        }\n    }\n}\n\nvoid pair_hillclimb(\n    array<uint8_t, C>& board,\n    Eval& curEval,\n    const vector<int>& cells,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int passes,\n    const chrono::steady_clock::time_point& start,\n    double deadline_sec\n) {\n    if (cells.empty()) return;\n    vector<int> ord = cells;\n    double curObj = objective(curEval, p);\n\n    for (int pass = 0; pass < passes; pass++) {\n        for (int i = (int)ord.size() - 1; i > 0; i--) {\n            int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n            swap(ord[i], ord[j]);\n        }\n        for (int idx = 0; idx < (int)ord.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec(start) >= deadline_sec) return;\n            int c = ord[idx];\n            if (possCnt[c] != 2) continue;\n            uint8_t old = board[c];\n            uint8_t nw = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n            board[c] = nw;\n            Eval ne = evaluator.eval(board);\n            double o = objective(ne, p);\n            if (o >= curObj) {\n                curEval = ne;\n                curObj = o;\n            } else {\n                board[c] = old;\n            }\n        }\n    }\n}\n\nvoid exact_subset_descent(\n    array<uint8_t, C>& board,\n    Eval& curEval,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int maxCells,\n    const chrono::steady_clock::time_point& start,\n    double deadline_sec\n) {\n    if (maxCells <= 0) return;\n    if (maxCells > C) maxCells = C;\n\n    array<int, C> ord;\n    iota(ord.begin(), ord.end(), 0);\n    for (int i = C - 1; i > 0; i--) {\n        int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n        swap(ord[i], ord[j]);\n    }\n\n    double curObj = objective(curEval, p);\n\n    for (int ii = 0; ii < maxCells; ii++) {\n        if ((ii & 15) == 0 && elapsed_sec(start) >= deadline_sec) return;\n\n        int c = ord[ii];\n        uint8_t old = board[c];\n\n        uint8_t bestState = old;\n        Eval bestEval = curEval;\n        double bestObj = curObj;\n\n        for (int k = 0; k < possCnt[c]; k++) {\n            uint8_t cand = poss[c][k];\n            if (cand == old) continue;\n            board[c] = cand;\n            Eval ne = evaluator.eval(board);\n            double o = objective(ne, p);\n            if (o > bestObj + 1e-12) {\n                bestObj = o;\n                bestState = cand;\n                bestEval = ne;\n            }\n        }\n\n        board[c] = bestState;\n        if (bestState != old) {\n            curEval = bestEval;\n            curObj = bestObj;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int t = 0; t < 8; t++) {\n        ROT[t][0] = t;\n        for (int k = 1; k < 4; k++) ROT[t][k] = ROT1[ROT[t][k - 1]];\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = i * N + j;\n            NEI[c][0] = (j > 0 ? c - 1 : -1);\n            NEI[c][1] = (i > 0 ? c - N : -1);\n            NEI[c][2] = (j + 1 < N ? c + 1 : -1);\n            NEI[c][3] = (i + 1 < N ? c + N : -1);\n        }\n    }\n\n    array<uint8_t, C> orig{};\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) orig[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)(uintptr_t)&seed;\n    RNG rng(seed);\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.94;\n    const double SA_END = TL - 0.12;\n\n    array<array<uint8_t, 4>, C> poss{};\n    array<uint8_t, C> possCnt{};\n    vector<int> twoStateCells;\n    vector<int> doubleCells;\n\n    for (int c = 0; c < C; c++) {\n        int t = orig[c];\n        if (t <= 3) {\n            possCnt[c] = 4;\n            for (int k = 0; k < 4; k++) poss[c][k] = (uint8_t)ROT[t][k];\n        } else if (t <= 5) {\n            possCnt[c] = 2;\n            poss[c][0] = 4;\n            poss[c][1] = 5;\n            twoStateCells.push_back(c);\n            doubleCells.push_back(c);\n        } else {\n            possCnt[c] = 2;\n            poss[c][0] = 6;\n            poss[c][1] = 7;\n            twoStateCells.push_back(c);\n        }\n    }\n\n    auto random_other = [&](int c, uint8_t old, array<uint8_t, C>& st) {\n        if (possCnt[c] == 2) {\n            st[c] = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n        } else {\n            uint8_t nw = old;\n            do nw = poss[c][rng.next_u32() & 3];\n            while (nw == old);\n            st[c] = nw;\n        }\n    };\n\n    Evaluator evaluator;\n\n    array<uint8_t, C> bestState = orig;\n    Eval bestEval = evaluator.eval(bestState);\n\n    const int KSEED = 5;\n    vector<array<uint8_t, C>> seedStates;\n    vector<Eval> seedEvals;\n    vector<double> seedKeys;\n    auto add_seed = [&](const array<uint8_t, C>& st, const Eval& ev, double key) {\n        if ((int)seedStates.size() < KSEED) {\n            seedStates.push_back(st);\n            seedEvals.push_back(ev);\n            seedKeys.push_back(key);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < KSEED; i++) {\n            if (seedKeys[i] < seedKeys[wi]) wi = i;\n        }\n        if (key > seedKeys[wi]) {\n            seedStates[wi] = st;\n            seedEvals[wi] = ev;\n            seedKeys[wi] = key;\n        }\n    };\n\n    add_seed(bestState, bestEval, objective(bestEval, 0.2));\n\n    // Initialization\n    const double initDeadline = 0.34;\n    int trial = 0;\n    while (elapsed_sec(start) < initDeadline && trial < 14) {\n        array<uint8_t, C> cand;\n\n        if (trial == 0) {\n            cand = orig;\n        } else if (trial % 3 == 0) {\n            cand = bestState;\n            int flips = 25 + (int)(rng.next_u32() % 45);\n            for (int f = 0; f < flips; f++) {\n                int c = (int)(rng.next_u32() % C);\n                random_other(c, cand[c], cand);\n            }\n        } else {\n            for (int c = 0; c < C; c++) {\n                if (possCnt[c] == 4) cand[c] = poss[c][rng.next_u32() & 3];\n                else cand[c] = poss[c][rng.next_u32() & 1];\n            }\n        }\n\n        int passes = (trial == 0 ? 8 : 5 + (trial % 3));\n        improve_connectivity(cand, poss, possCnt, rng, passes);\n\n        Eval e = evaluator.eval(cand);\n\n        if (trial < 6 && elapsed_sec(start) < initDeadline - 0.01) {\n            pair_hillclimb(cand, e, twoStateCells, poss, possCnt, evaluator, rng, 0.18, 1, start, initDeadline);\n        }\n        if (trial < 4 && elapsed_sec(start) < initDeadline - 0.005) {\n            exact_subset_descent(cand, e, poss, possCnt, evaluator, rng, 0.20, 140, start, initDeadline);\n        }\n\n        if (better_best(e, bestEval)) {\n            bestEval = e;\n            bestState = cand;\n        }\n\n        add_seed(cand, e, objective(e, 0.22));\n        trial++;\n    }\n\n    if (seedStates.empty()) {\n        seedStates.push_back(bestState);\n        seedEvals.push_back(bestEval);\n        seedKeys.push_back(objective(bestEval, 0.2));\n    }\n\n    int startIdx = 0;\n    for (int i = 1; i < (int)seedStates.size(); i++) {\n        if (seedKeys[i] > seedKeys[startIdx]) startIdx = i;\n    }\n\n    array<uint8_t, C> curState = seedStates[startIdx];\n    Eval curEval = seedEvals[startIdx];\n    if (better_best(curEval, bestEval)) {\n        bestEval = curEval;\n        bestState = curState;\n    }\n\n    // Small pre-SA intensification\n    if (elapsed_sec(start) < 0.55) {\n        double d = min(SA_END, elapsed_sec(start) + 0.05);\n        pair_hillclimb(curState, curEval, twoStateCells, poss, possCnt, evaluator, rng, 0.25, 1, start, d);\n        exact_subset_descent(curState, curEval, poss, possCnt, evaluator, rng, 0.25, 220, start, d);\n        if (better_best(curEval, bestEval)) {\n            bestEval = curEval;\n            bestState = curState;\n            add_seed(bestState, bestEval, objective(bestEval, 0.5));\n        }\n    }\n\n    // SA\n    long long iter = 0;\n    long long lastBestIter = 0;\n    long long lastRestartIter = 0;\n    long long lastIntenseIter = 0;\n\n    const double T0 = 160.0;\n    const double T1 = 0.03;\n    double progress = min(1.0, elapsed_sec(start) / TL);\n    double temp = T0 * pow(T1 / T0, progress);\n\n    auto pick_cell = [&]() -> int {\n        uint32_t r = rng.next_u32() % 100;\n        if (r < 18 && !doubleCells.empty()) {\n            return doubleCells[rng.next_u32() % doubleCells.size()];\n        }\n        if (r < 65) {\n            int best = (int)(rng.next_u32() % C);\n            int bestB = -1;\n            for (int t = 0; t < 5; t++) {\n                int c = (int)(rng.next_u32() % C);\n                int b = cell_badness(c, curState);\n                if (b > bestB) {\n                    bestB = b;\n                    best = c;\n                }\n            }\n            return best;\n        }\n        return (int)(rng.next_u32() % C);\n    };\n\n    while (true) {\n        if ((iter & 127LL) == 0) {\n            double now = elapsed_sec(start);\n            if (now >= SA_END) break;\n            progress = now / TL;\n            if (progress > 1.0) progress = 1.0;\n            temp = T0 * pow(T1 / T0, progress);\n\n            if (iter - lastBestIter > 7000 && iter - lastIntenseIter > 5000 && progress < 0.90) {\n                double d = min(SA_END, now + 0.025);\n                exact_subset_descent(curState, curEval, poss, possCnt, evaluator, rng, max(0.28, progress), 90, start, d);\n                if (better_best(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    lastBestIter = iter;\n                    add_seed(bestState, bestEval, objective(bestEval, 0.7));\n                }\n                lastIntenseIter = iter;\n            }\n\n            if (iter - lastBestIter > 15000 && iter - lastRestartIter > 6000) {\n                if (!seedStates.empty() && (rng.next_u32() % 100) < 50) {\n                    int si = (int)(rng.next_u32() % seedStates.size());\n                    curState = seedStates[si];\n                    curEval = seedEvals[si];\n                } else {\n                    curState = bestState;\n                    curEval = bestEval;\n                }\n                int flips = 24 + (int)(rng.next_u32() % 38);\n                for (int f = 0; f < flips; f++) {\n                    int c = (int)(rng.next_u32() % C);\n                    random_other(c, curState[c], curState);\n                }\n                improve_connectivity(curState, poss, possCnt, rng, 1);\n                curEval = evaluator.eval(curState);\n                lastRestartIter = iter;\n            }\n        }\n\n        double curObj = objective(curEval, progress);\n\n        int changedCount = 0;\n        int changedIdx[16];\n        uint8_t oldVal[16];\n\n        int mt = (int)(rng.next_u32() % 100);\n\n        if (mt < 40 && !doubleCells.empty()) {\n            int c = doubleCells[rng.next_u32() % doubleCells.size()];\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changedCount = 1;\n            curState[c] = (curState[c] == 4 ? 5 : 4);\n        } else if (mt < 78) {\n            int c = pick_cell();\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changedCount = 1;\n            random_other(c, curState[c], curState);\n        } else if (mt < 90) {\n            int c1 = pick_cell();\n            int c2 = (int)(rng.next_u32() % C);\n            while (c2 == c1) c2 = (int)(rng.next_u32() % C);\n\n            changedIdx[0] = c1; oldVal[0] = curState[c1];\n            changedIdx[1] = c2; oldVal[1] = curState[c2];\n            changedCount = 2;\n\n            random_other(c1, curState[c1], curState);\n            random_other(c2, curState[c2], curState);\n        } else if (mt < 97) {\n            int i = (int)(rng.next_u32() % (N - 1));\n            int j = (int)(rng.next_u32() % (N - 1));\n            int delta = (rng.next_u32() & 1) ? 1 : 3;\n            int c0 = i * N + j;\n            int cells[4] = {c0, c0 + 1, c0 + N, c0 + N + 1};\n            for (int k = 0; k < 4; k++) {\n                changedIdx[k] = cells[k];\n                oldVal[k] = curState[cells[k]];\n            }\n            changedCount = 4;\n            for (int k = 0; k < 4; k++) curState[cells[k]] = (uint8_t)ROT[curState[cells[k]]][delta];\n        } else {\n            int i = (int)(rng.next_u32() % (N - 2));\n            int j = (int)(rng.next_u32() % (N - 2));\n            changedCount = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    int c = (i + di) * N + (j + dj);\n                    changedIdx[changedCount] = c;\n                    oldVal[changedCount] = curState[c];\n                    changedCount++;\n                    if (possCnt[c] == 4) curState[c] = poss[c][rng.next_u32() & 3];\n                    else curState[c] = poss[c][rng.next_u32() & 1];\n                }\n            }\n        }\n\n        Eval ne = evaluator.eval(curState);\n        double newObj = objective(ne, progress);\n        double diff = newObj - curObj;\n\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else if (rng.next_double() < exp(diff / temp)) accept = true;\n\n        if (accept) {\n            curEval = ne;\n            if (better_best(curEval, bestEval)) {\n                bestEval = curEval;\n                bestState = curState;\n                lastBestIter = iter;\n                add_seed(bestState, bestEval, objective(bestEval, 0.85));\n            }\n        } else {\n            for (int k = 0; k < changedCount; k++) curState[changedIdx[k]] = oldVal[k];\n        }\n\n        iter++;\n    }\n\n    // Final polish\n    array<uint8_t, C> polState = bestState;\n    Eval polEval = bestEval;\n\n    double finalP = 0.97;\n    double now = elapsed_sec(start);\n    double finalDeadline = TL - 0.003;\n\n    if (now < finalDeadline) {\n        double d1 = min(finalDeadline, now + 0.04);\n        pair_hillclimb(polState, polEval, twoStateCells, poss, possCnt, evaluator, rng, finalP, 1, start, d1);\n        exact_subset_descent(polState, polEval, poss, possCnt, evaluator, rng, finalP, C, start, finalDeadline);\n        if (better_best(polEval, bestEval)) {\n            bestEval = polEval;\n            bestState = polState;\n        }\n    }\n\n    string ans(C, '0');\n    for (int c = 0; c < C; c++) {\n        int o = orig[c];\n        int f = bestState[c];\n        int rot = 0;\n        for (; rot < 4; rot++) {\n            if (ROT[o][rot] == f) break;\n        }\n        if (rot == 4) rot = 0;\n        ans[c] = char('0' + rot);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N_global, T_global, NN_global, FULLV;\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};\n\nuint64_t splitmix64(uint64_t &x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ull);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n    return z ^ (z >> 31);\n}\n\nstruct AdjEdge {\n    uint8_t u, v;\n    uint8_t mu, mv;\n};\n\nvector<AdjEdge> g_edges;\nuint64_t zobrist[100][16];\n\nconst int DR[4] = {-1, 1, 0, 0}; // blank movement for U,D,L,R\nconst int DC[4] = {0, 0, -1, 1};\nconst char OP[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\ninline int uf_find(int x, int parent[]) {\n    while (parent[x] != x) {\n        parent[x] = parent[parent[x]];\n        x = parent[x];\n    }\n    return x;\n}\n\nstruct EvalInfo {\n    int S = 0;            // largest tree component size\n    int cmax = 0;         // largest connected component size\n    int cmaxEx = 0;       // cycle excess of largest connected component\n    int potential = 0;    // max(v - cycleW * excess)\n    int totalEdges = 0;\n    int totalExcess = 0;\n    long long key = LLONG_MIN;\n};\n\nEvalInfo evaluate_state(const array<uint8_t, 100> &b, int cycleW) {\n    int parent[100];\n    int sz[100];\n    int ed[100];\n\n    for (int i = 0; i < NN_global; i++) {\n        if (b[i] != 0) {\n            parent[i] = i;\n            sz[i] = 1;\n            ed[i] = 0;\n        } else {\n            parent[i] = -1;\n        }\n    }\n\n    for (const auto &e : g_edges) {\n        uint8_t a = b[e.u];\n        uint8_t c = b[e.v];\n        if (a != 0 && c != 0 && (a & e.mu) && (c & e.mv)) {\n            int ra = uf_find((int)e.u, parent);\n            int rb = uf_find((int)e.v, parent);\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\n    EvalInfo r;\n    bool first = true;\n    for (int i = 0; i < NN_global; i++) {\n        if (parent[i] == i) {\n            int v = sz[i];\n            int e = ed[i];\n            int ex = e - (v - 1);\n\n            if (ex == 0) r.S = max(r.S, v);\n            r.totalEdges += e;\n            if (ex > 0) r.totalExcess += ex;\n\n            int p = v - cycleW * ex;\n            r.potential = max(r.potential, p);\n\n            if (first || v > r.cmax || (v == r.cmax && ex < r.cmaxEx)) {\n                r.cmax = v;\n                r.cmaxEx = ex;\n                first = false;\n            }\n        }\n    }\n\n    if (r.S == 0) r.S = 1;\n    if (r.potential < 0) r.potential = 0;\n\n    // Beam priority key (heuristic)\n    r.key = 400000LL * r.potential\n          + 100000LL * r.S\n          +   1000LL * r.cmax\n          -   8000LL * r.cmaxEx\n          +     20LL * r.totalEdges\n          -   1000LL * r.totalExcess;\n    return r;\n}\n\nuint64_t compute_hash(const array<uint8_t, 100> &b) {\n    uint64_t h = 0;\n    for (int i = 0; i < NN_global; i++) h ^= zobrist[i][b[i]];\n    return h;\n}\n\nstruct Node {\n    array<uint8_t, 100> b{};\n    uint16_t blank = 0;\n    int parent = -1;\n    int depth = 0;\n    uint8_t lastDir = 4; // 0..3 or 4=none\n    char mv = '?';\n\n    int S = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN; // key + random jitter\n    uint64_t hash = 0;\n};\n\nbool better_node(const Node &a, const Node &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.depth != b.depth) return a.depth < b.depth;\n    if (a.key != b.key) return a.key > b.key;\n    return a.depth < b.depth;\n}\n\nstruct SearchResult {\n    string path;\n    array<uint8_t, 100> board{};\n    int blank = 0;\n    int lastDir = 4;\n    int S = 0;\n    long long key = LLONG_MIN;\n};\n\nbool better_result(const SearchResult &a, const SearchResult &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    if (a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    return a.key > b.key;\n}\n\nSearchResult run_beam(\n    const array<uint8_t, 100> &initBoard,\n    int initBlank,\n    int width,\n    int cycleW,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng\n) {\n    vector<Node> nodes;\n    nodes.reserve((size_t)width * (size_t)T_global * 3 + 1024);\n\n    Node root;\n    root.b = initBoard;\n    root.blank = (uint16_t)initBlank;\n    root.parent = -1;\n    root.depth = 0;\n    root.lastDir = 4;\n    root.mv = '?';\n    root.hash = compute_hash(root.b);\n    {\n        EvalInfo e0 = evaluate_state(root.b, cycleW);\n        root.S = e0.S;\n        root.key = e0.key;\n        root.pri = e0.key;\n    }\n    nodes.push_back(root);\n\n    int bestId = 0;\n\n    vector<int> beam, nextBeam, cand;\n    beam.reserve(width);\n    nextBeam.reserve(width);\n    cand.reserve(width * 4 + 8);\n    beam.push_back(0);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(width * 8 + 16);\n\n    for (int depth = 0; depth < T_global; depth++) {\n        if ((depth & 7) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        cand.clear();\n        bool timeout = false;\n\n        for (int bi = 0; bi < (int)beam.size(); bi++) {\n            if ((bi & 31) == 0 && chrono::steady_clock::now() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int id = beam[bi];\n            const Node &cur = nodes[id];\n            int br = cur.blank / N_global;\n            int bc = cur.blank % N_global;\n\n            for (int d = 0; d < 4; d++) {\n                if (cur.lastDir < 4 && d == OPP[cur.lastDir]) continue;\n\n                int nr = br + DR[d];\n                int nc = bc + DC[d];\n                if ((unsigned)nr >= (unsigned)N_global || (unsigned)nc >= (unsigned)N_global) continue;\n\n                int nb = nr * N_global + nc;\n\n                Node child;\n                child.b = cur.b;\n                uint8_t tile = child.b[nb];\n                child.b[cur.blank] = tile;\n                child.b[nb] = 0;\n\n                child.blank = (uint16_t)nb;\n                child.parent = id;\n                child.depth = cur.depth + 1;\n                child.lastDir = (uint8_t)d;\n                child.mv = OP[d];\n\n                child.hash = cur.hash\n                           ^ zobrist[cur.blank][0]\n                           ^ zobrist[cur.blank][tile]\n                           ^ zobrist[nb][tile]\n                           ^ zobrist[nb][0];\n\n                EvalInfo ec = evaluate_state(child.b, cycleW);\n                child.S = ec.S;\n                child.key = ec.key;\n                child.pri = ec.key * 1024LL + (long long)(rng.next() & 1023ULL);\n\n                nodes.push_back(std::move(child));\n                int nid = (int)nodes.size() - 1;\n                cand.push_back(nid);\n\n                if (better_node(nodes[nid], nodes[bestId])) bestId = nid;\n            }\n        }\n\n        if (timeout || cand.empty()) break;\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            if (nodes[a].pri != nodes[b].pri) return nodes[a].pri > nodes[b].pri;\n            return nodes[a].key > nodes[b].key;\n        });\n\n        nextBeam.clear();\n        seen.clear();\n\n        for (int id : cand) {\n            uint64_t key = nodes[id].hash ^ (0x9e3779b97f4a7c15ull * (uint64_t)(nodes[id].lastDir + 1));\n            if (seen.insert(key).second) {\n                nextBeam.push_back(id);\n                if ((int)nextBeam.size() >= width) break;\n            }\n        }\n\n        if (nextBeam.empty()) break;\n        beam.swap(nextBeam);\n\n        if (nodes[bestId].S == FULLV) break;\n    }\n\n    SearchResult res;\n    res.S = nodes[bestId].S;\n    res.key = nodes[bestId].key;\n    res.board = nodes[bestId].b;\n    res.blank = nodes[bestId].blank;\n    res.lastDir = nodes[bestId].lastDir;\n\n    string p;\n    for (int cur = bestId; nodes[cur].parent != -1; cur = nodes[cur].parent) {\n        p.push_back(nodes[cur].mv);\n    }\n    reverse(p.begin(), p.end());\n    res.path = std::move(p);\n\n    return res;\n}\n\nSearchResult greedy_polish(\n    const SearchResult &base,\n    int cycleW,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng\n) {\n    SearchResult best = base;\n    if (best.S == FULLV) return best;\n\n    array<uint8_t, 100> board = base.board;\n    int blank = base.blank;\n    int lastDir = base.lastDir;\n    string curPath = base.path;\n\n    for (int step = (int)curPath.size(); step < T_global; step++) {\n        if ((step & 31) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        int br = blank / N_global;\n        int bc = blank % N_global;\n\n        long long bestVal = LLONG_MIN;\n        int bestDir = -1;\n        int bestNb = -1;\n        EvalInfo bestEi;\n        array<uint8_t, 100> bestBoard{};\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n\n            int nr = br + DR[d];\n            int nc = bc + DC[d];\n            if ((unsigned)nr >= (unsigned)N_global || (unsigned)nc >= (unsigned)N_global) continue;\n\n            int nb = nr * N_global + nc;\n\n            array<uint8_t, 100> nbBoard = board;\n            uint8_t tile = nbBoard[nb];\n            nbBoard[blank] = tile;\n            nbBoard[nb] = 0;\n\n            EvalInfo ei = evaluate_state(nbBoard, cycleW);\n            long long val = (long long)ei.S * 1'000'000'000LL + ei.key + (long long)(rng.next() & 1023ULL);\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestDir = d;\n                bestNb = nb;\n                bestEi = ei;\n                bestBoard = nbBoard;\n            }\n        }\n\n        if (bestDir == -1) break;\n\n        board = bestBoard;\n        blank = bestNb;\n        lastDir = bestDir;\n        curPath.push_back(OP[bestDir]);\n\n        if (bestEi.S > best.S || (bestEi.S == FULLV && (int)curPath.size() < (int)best.path.size())) {\n            best.S = bestEi.S;\n            best.key = bestEi.key;\n            best.board = board;\n            best.blank = blank;\n            best.lastDir = lastDir;\n            best.path = curPath;\n            if (best.S == FULLV) break;\n        }\n    }\n\n    return best;\n}\n\nint hex_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return 10 + (c - 'a');\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N_global >> T_global;\n    NN_global = N_global * N_global;\n    FULLV = NN_global - 1;\n\n    array<uint8_t, 100> init{};\n    int blank = -1;\n\n    for (int i = 0; i < N_global; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N_global; j++) {\n            int v = hex_to_int(s[j]);\n            init[i * N_global + j] = (uint8_t)v;\n            if (v == 0) blank = i * N_global + j;\n        }\n    }\n\n    g_edges.clear();\n    g_edges.reserve(2 * N_global * (N_global - 1));\n    for (int i = 0; i < N_global; i++) {\n        for (int j = 0; j < N_global; j++) {\n            int id = i * N_global + j;\n            if (j + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + 1), 4, 1});\n            if (i + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + N_global), 8, 2});\n        }\n    }\n\n    uint64_t seed = 0x123456789abcdef0ull;\n    for (int i = 0; i < NN_global; i++) {\n        seed ^= (uint64_t)init[i] + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n    }\n\n    uint64_t zseed = seed ^ 0xdeadbeefcafebabeull;\n    for (int i = 0; i < 100; i++) {\n        for (int v = 0; v < 16; v++) {\n            zobrist[i][v] = splitmix64(zseed);\n        }\n    }\n    XorShift64 rng(seed ^ 0x517cc1b727220a95ull);\n\n    EvalInfo e0 = evaluate_state(init, 3);\n    SearchResult globalBest;\n    globalBest.path = \"\";\n    globalBest.board = init;\n    globalBest.blank = blank;\n    globalBest.lastDir = 4;\n    globalBest.S = e0.S;\n    globalBest.key = e0.key;\n\n    auto start = chrono::steady_clock::now();\n    const long long TOTAL_MS = 2850;\n    auto globalDeadline = start + chrono::milliseconds(TOTAL_MS);\n\n    vector<pair<int, int>> params;\n    if (N_global <= 7) {\n        params = {{220, 2}, {260, 3}, {180, 4}};\n    } else if (N_global == 8) {\n        params = {{170, 2}, {210, 3}, {150, 4}};\n    } else if (N_global == 9) {\n        params = {{150, 2}, {190, 3}, {130, 4}};\n    } else {\n        params = {{130, 2}, {170, 3}, {110, 4}};\n    }\n    vector<int> percent = {65, 85, 100};\n\n    for (int i = 0; i < (int)params.size(); i++) {\n        auto now = chrono::steady_clock::now();\n        if (now >= globalDeadline) break;\n\n        auto runDeadline = start + chrono::milliseconds(TOTAL_MS * percent[i] / 100);\n        if (runDeadline > globalDeadline) runDeadline = globalDeadline;\n        if (now >= runDeadline) continue;\n\n        int width = params[i].first;\n        int cycleW = params[i].second;\n\n        SearchResult r = run_beam(init, blank, width, cycleW, runDeadline, rng);\n        r = greedy_polish(r, cycleW, runDeadline, rng);\n\n        if (better_result(r, globalBest)) globalBest = std::move(r);\n        if (globalBest.S == FULLV) break;\n    }\n\n    if ((int)globalBest.path.size() > T_global) {\n        globalBest.path.resize(T_global);\n    }\n    cout << globalBest.path << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct Line {\n    long long x1, y1, x2, y2;\n    long long dx, dy;\n};\n\nstruct EvalKey {\n    int F = 0;\n    int def2 = 0;\n    int active = 0;\n    int waste = 0;\n    long long over = 0;\n};\n\nstatic inline bool betterKey(const EvalKey& a, const EvalKey& b) {\n    if (a.F != b.F) return a.F > b.F;\n    if (a.def2 != b.def2) return a.def2 < b.def2;\n    if (a.active != b.active) return a.active > b.active;\n    if (a.waste != b.waste) return a.waste < b.waste;\n    return a.over < b.over;\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) {\n        x = seed ? seed : 88172645463325252ull;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct State {\n    vector<vector<int>> pieces;\n    vector<int> pieceSize;\n    vector<int> pieceOf;     // -1 deleted\n    vector<int> active;\n    array<int, 11> h{};\n    int F = 0;\n    int def2 = 0;\n    int waste = 0;\n    long long over = 0;\n    vector<Line> lines;\n};\n\nstruct RunResult {\n    vector<Line> lines;\n    EvalKey key;\n};\n\nclass Solver {\n    static constexpr double PI = 3.1415926535897932384626433832795;\n    static constexpr long long BIG = (1LL << 62);\n\n    int N, K;\n    array<int, 11> a{};\n    vector<Point> pts;\n    int totalA = 0;\n    vector<long long> pen;\n\n    chrono::steady_clock::time_point t0;\n    const double TL = 2.82;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline long long orient(const Line& ln, const Point& p) const {\n        return ln.dx * ((long long)p.y - ln.y1) - ln.dy * ((long long)p.x - ln.x1);\n    }\n\n    inline int calcF(const array<int, 11>& h) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], h[d]);\n        return s;\n    }\n\n    inline int calcDef2(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int sat = min(a[d], h[d]);\n            int def = a[d] - sat;\n            v += def * def;\n        }\n        return v;\n    }\n\n    inline int calcWaste(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int ex = max(0, h[d] - a[d]);\n            v += ex * ex;\n        }\n        return v;\n    }\n\n    inline EvalKey stateKey(const State& st) const {\n        return EvalKey{st.F, st.def2, (int)st.active.size(), st.waste, st.over};\n    }\n\n    inline void addPart(array<int, 11>& h, long long& over, int t, int delta) const {\n        if (t <= 0) return;\n        if (t <= 10) h[t] += delta;\n        over += (long long)delta * pen[t];\n    }\n\n    inline void addPieceState(array<int, 11>& h, long long& over, int s, int l, int delta) const {\n        if (l <= 0 || l >= s) {\n            addPart(h, over, s, delta);\n        } else {\n            addPart(h, over, l, delta);\n            addPart(h, over, s - l, delta);\n        }\n    }\n\n    inline double normTheta(double th) const {\n        while (th < 0) th += PI;\n        while (th >= PI) th -= PI;\n        return th;\n    }\n\n    Line makeLineFromNormal(double nx, double ny, double c) const {\n        const double S = 8.8e8;\n        double dx = -ny, dy = nx;\n        double cx = nx * c, cy = ny * c;\n\n        long long x1 = llround(cx + dx * S);\n        long long y1 = llround(cy + dy * S);\n        long long x2 = llround(cx - dx * S);\n        long long y2 = llround(cy - dy * S);\n\n        if (x1 == x2 && y1 == y2) x2++;\n\n        Line ln;\n        ln.x1 = x1; ln.y1 = y1;\n        ln.x2 = x2; ln.y2 = y2;\n        ln.dx = ln.x2 - ln.x1;\n        ln.dy = ln.y2 - ln.y1;\n        if (ln.dx == 0 && ln.dy == 0) {\n            ln.x2++;\n            ln.dx = 1;\n        }\n        return ln;\n    }\n\n    Line makeLine(double theta, double c) const {\n        return makeLineFromNormal(cos(theta), sin(theta), c);\n    }\n\n    Line randomGlobalLine(XorShift64& rng) const {\n        double theta = rng.nextDouble() * PI;\n        double c = (rng.nextDouble() * 2.0 - 1.0) * 9200.0;\n        return makeLine(theta, c);\n    }\n\n    EvalKey evalLine(const State& st, const Line& ln, vector<int>& L, vector<int>& R) const {\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) {\n            L[i] = 0;\n            R[i] = 0;\n        }\n\n        for (int idx : st.active) {\n            int pid = st.pieceOf[idx];\n            long long v = orient(ln, pts[idx]);\n            if (v > 0) L[pid]++;\n            else if (v < 0) R[pid]++;\n        }\n\n        array<int, 11> h2 = st.h;\n        long long over2 = st.over;\n        int removed = 0;\n\n        for (int pid = 0; pid < P; pid++) {\n            int s = st.pieceSize[pid];\n            int l = L[pid];\n            int r = R[pid];\n\n            if (l == s || r == s) continue;\n\n            removed += s - l - r;\n            over2 -= pen[s];\n            if (l > 0) over2 += pen[l];\n            if (r > 0) over2 += pen[r];\n\n            if (1 <= s && s <= 10) h2[s]--;\n            if (1 <= l && l <= 10) h2[l]++;\n            if (1 <= r && r <= 10) h2[r]++;\n        }\n\n        EvalKey key;\n        key.F = calcF(h2);\n        key.def2 = calcDef2(h2);\n        key.active = (int)st.active.size() - removed;\n        key.waste = calcWaste(h2);\n        key.over = over2;\n        return key;\n    }\n\n    void rebuildMetrics(State& st) const {\n        st.h.fill(0);\n        st.over = 0;\n        for (int s : st.pieceSize) {\n            if (1 <= s && s <= 10) st.h[s]++;\n            st.over += pen[s];\n        }\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n    }\n\n    void applyLine(State& st, const Line& ln) const {\n        vector<vector<int>> newPieces;\n        vector<int> newSizes;\n        vector<int> newActive;\n\n        newPieces.reserve(st.pieces.size() * 2 + 2);\n        newSizes.reserve(st.pieces.size() * 2 + 2);\n        newActive.reserve(st.active.size());\n\n        fill(st.pieceOf.begin(), st.pieceOf.end(), -1);\n\n        for (const auto& pc : st.pieces) {\n            vector<int> left, right;\n            left.reserve(pc.size());\n            right.reserve(pc.size());\n\n            for (int idx : pc) {\n                long long v = orient(ln, pts[idx]);\n                if (v > 0) left.push_back(idx);\n                else if (v < 0) right.push_back(idx);\n            }\n\n            if (!left.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : left) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)left.size());\n                newPieces.push_back(move(left));\n            }\n            if (!right.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : right) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)right.size());\n                newPieces.push_back(move(right));\n            }\n        }\n\n        st.pieces.swap(newPieces);\n        st.pieceSize.swap(newSizes);\n        st.active.swap(newActive);\n        st.lines.push_back(ln);\n        rebuildMetrics(st);\n    }\n\n    bool bestCutForTheta(const State& st, double theta, double& bestC, EvalKey& pred,\n                         vector<pair<double, int>>& ord, vector<int>& cntLeft) const {\n        int M = (int)st.active.size();\n        if (M < 2) return false;\n\n        double nx = cos(theta), ny = sin(theta);\n        ord.resize(M);\n        for (int i = 0; i < M; i++) {\n            int idx = st.active[i];\n            ord[i] = {nx * pts[idx].x + ny * pts[idx].y, idx};\n        }\n        sort(ord.begin(), ord.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) cntLeft[i] = 0;\n\n        array<int, 11> hcur = st.h;\n        long long overcur = st.over;\n\n        bool found = false;\n        EvalKey bestLocal{};\n        double cLocal = 0.0;\n\n        const double EPS = 1e-12;\n        int i = 0;\n        while (i < M) {\n            int j = i + 1;\n            while (j < M && fabs(ord[j].first - ord[i].first) <= EPS) j++;\n\n            for (int k = i; k < j; k++) {\n                int idx = ord[k].second;\n                int pid = st.pieceOf[idx];\n                int s = st.pieceSize[pid];\n                int oldL = cntLeft[pid];\n                int newL = oldL + 1;\n\n                addPieceState(hcur, overcur, s, oldL, -1);\n                addPieceState(hcur, overcur, s, newL, +1);\n                cntLeft[pid] = newL;\n            }\n\n            if (j < M) {\n                double lv = ord[j - 1].first;\n                double rv = ord[j].first;\n                if (rv - lv > EPS) {\n                    EvalKey key;\n                    key.F = calcF(hcur);\n                    key.def2 = calcDef2(hcur);\n                    key.active = M;\n                    key.waste = calcWaste(hcur);\n                    key.over = overcur;\n                    if (!found || betterKey(key, bestLocal)) {\n                        found = true;\n                        bestLocal = key;\n                        cLocal = (lv + rv) * 0.5;\n                    }\n                }\n            }\n            i = j;\n        }\n\n        if (!found) return false;\n        bestC = cLocal;\n        pred = bestLocal;\n        return true;\n    }\n\n    pair<Line, EvalKey> realizeThetaC(const State& st, double theta, double c,\n                                      vector<int>& L, vector<int>& R) const {\n        Line bestLn = makeLine(theta, c);\n        EvalKey bestEv = evalLine(st, bestLn, L, R);\n\n        int curAct = (int)st.active.size();\n        if (bestEv.active == curAct) return {bestLn, bestEv};\n\n        static const double off[6] = {1e-4, -1e-4, 5e-4, -5e-4, 2e-3, -2e-3};\n        for (double d : off) {\n            Line ln = makeLine(theta, c + d);\n            EvalKey ev = evalLine(st, ln, L, R);\n            if (betterKey(ev, bestEv)) {\n                bestEv = ev;\n                bestLn = ln;\n            }\n        }\n        return {bestLn, bestEv};\n    }\n\n    int pickPieceRandom(const State& st, XorShift64& rng, int minSize) const {\n        if (st.active.empty()) return -1;\n        int S = (int)st.active.size();\n        for (int t = 0; t < 30; t++) {\n            int idx = st.active[rng.nextInt(0, S - 1)];\n            int pid = st.pieceOf[idx];\n            if (st.pieceSize[pid] >= minSize) return pid;\n        }\n        int best = -1, bestSize = 0;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s >= minSize && s > bestSize) {\n                bestSize = s;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int chooseTargetPiece(const State& st) const {\n        int best = -1;\n        long long bestScore = -1;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s < 2) continue;\n\n            long long score;\n            if (s > 10) {\n                score = 1000000LL + 1000LL * s;\n            } else {\n                int overSup = max(0, st.h[s] - a[s]);\n                score = (long long)overSup * 10000LL + s;\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int pickDeficitSize(const State& st, XorShift64& rng) const {\n        int w[11];\n        int sumW = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - st.h[d]);\n            int wt = 1 + def * def * 3;\n            w[d] = wt;\n            sumW += wt;\n        }\n        int r = rng.nextInt(1, sumW);\n        for (int d = 1; d <= 10; d++) {\n            if (r <= w[d]) return d;\n            r -= w[d];\n        }\n        return 1;\n    }\n\n    bool calcPCA(const State& st, int pid, double& th1, double& th2) const {\n        const auto& pc = st.pieces[pid];\n        int s = (int)pc.size();\n        if (s < 2) return false;\n\n        long double mx = 0, my = 0;\n        for (int idx : pc) {\n            mx += pts[idx].x;\n            my += pts[idx].y;\n        }\n        mx /= s;\n        my /= s;\n\n        long double cxx = 0, cyy = 0, cxy = 0;\n        for (int idx : pc) {\n            long double dx = pts[idx].x - mx;\n            long double dy = pts[idx].y - my;\n            cxx += dx * dx;\n            cyy += dy * dy;\n            cxy += dx * dy;\n        }\n        if ((double)(cxx + cyy) < 1e-9) return false;\n\n        double ang = 0.5 * atan2((double)(2 * cxy), (double)(cxx - cyy));\n        th1 = normTheta(ang);\n        th2 = normTheta(ang + PI * 0.5);\n        return true;\n    }\n\n    Line lineByQuantile(const State& st, int pid, double theta, int t, vector<double>& buf) const {\n        const auto& vec = st.pieces[pid];\n        int s = (int)vec.size();\n        t = max(1, min(s - 1, t));\n\n        double nx = cos(theta), ny = sin(theta);\n        buf.clear();\n        buf.reserve(s);\n        for (int idx : vec) {\n            buf.push_back(nx * pts[idx].x + ny * pts[idx].y);\n        }\n\n        sort(buf.begin(), buf.end());\n        double l = buf[t - 1], r = buf[t];\n        double c = (l + r) * 0.5;\n        if (fabs(r - l) < 1e-12) c += 1e-6;\n        return makeLine(theta, c);\n    }\n\n    RunResult runOne(uint64_t seed, int runId, double runEnd) {\n        XorShift64 rng(seed);\n\n        State st;\n        st.pieceOf.assign(N, 0);\n        st.pieces.assign(1, {});\n        st.pieces[0].resize(N);\n        iota(st.pieces[0].begin(), st.pieces[0].end(), 0);\n        st.pieceSize.assign(1, N);\n        st.active = st.pieces[0];\n        st.h.fill(0);\n        if (1 <= N && N <= 10) st.h[N] = 1;\n        st.over = pen[N];\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n\n        int oriBase;\n        if (N >= 4500) oriBase = 8;\n        else if (N >= 3000) oriBase = 10;\n        else if (N >= 1800) oriBase = 12;\n        else oriBase = 14;\n\n        int qBase = (N >= 3500 ? 3 : 4);\n        int noImpLimit = (runId == 0 ? 13 : 10);\n        if (runId == 0) oriBase += 2;\n        if (runId >= 3) oriBase = max(6, oriBase - 2);\n\n        vector<int> L(max(1, N), 0), R(max(1, N), 0), cntLeft(max(1, N), 0);\n        vector<pair<double, int>> ord;\n        ord.reserve(max(1, N));\n        vector<double> projBuf;\n        projBuf.reserve(max(1, N));\n\n        int noImprove = 0;\n        double runBudget = runEnd - elapsed();\n\n        for (int iter = 0; iter < K * 3 && (int)st.lines.size() < K; iter++) {\n            if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n            if (st.active.empty()) break;\n            if (st.F >= totalA) break;\n\n            int step = (int)st.lines.size();\n            EvalKey cur = stateKey(st);\n\n            int targetPid = chooseTargetPiece(st);\n            bool hasPCA = false;\n            double pca1 = 0.0, pca2 = 0.0;\n            if (targetPid >= 0) hasPCA = calcPCA(st, targetPid, pca1, pca2);\n\n            double remRun = runEnd - elapsed();\n            int oriCnt = oriBase;\n            if (step < 6) oriCnt += 2;\n            if (noImprove >= 3) oriCnt += 3;\n            if (runBudget < 0.35 || remRun < 0.22) oriCnt = max(4, oriCnt - 4);\n            if (remRun < 0.12) oriCnt = max(3, oriCnt / 2);\n\n            int qCnt = qBase;\n            if (noImprove >= 3) qCnt += 1;\n            if (runBudget < 0.35 || remRun < 0.22) qCnt = max(1, qCnt - 2);\n            if (remRun < 0.12) qCnt = 1;\n\n            vector<double> thetas;\n            thetas.reserve(oriCnt + 10);\n\n            auto addTheta = [&](double th) {\n                thetas.push_back(normTheta(th));\n            };\n\n            if (hasPCA) {\n                addTheta(pca1);\n                addTheta(pca2);\n                addTheta(pca1 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n                addTheta(pca2 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n            }\n\n            int prevUse = min((int)st.lines.size(), 2);\n            for (int i = 0; i < prevUse; i++) {\n                const Line& pl = st.lines[(int)st.lines.size() - 1 - i];\n                double th = atan2((double)pl.dx, (double)(-pl.dy));\n                addTheta(th + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n                addTheta(th + PI * 0.5 + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n            }\n\n            while ((int)thetas.size() < oriCnt) {\n                addTheta(rng.nextDouble() * PI);\n            }\n            if ((int)thetas.size() > 24) thetas.resize(24);\n\n            EvalKey bestEv{-1, INT_MAX, -1, INT_MAX, BIG};\n            Line bestLn{};\n            bool found = false;\n\n            for (double th : thetas) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                double c = 0.0;\n                EvalKey pred;\n                if (!bestCutForTheta(st, th, c, pred, ord, cntLeft)) continue;\n                auto [ln, ev] = realizeThetaC(st, th, c, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int qi = 0; qi < qCnt; qi++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n\n                int pid = -1;\n                if (targetPid >= 0 && st.pieceSize[targetPid] >= 2 && rng.nextDouble() < 0.65) {\n                    pid = targetPid;\n                } else {\n                    pid = pickPieceRandom(st, rng, 2);\n                }\n                if (pid < 0) continue;\n\n                int s = st.pieceSize[pid];\n                if (s <= 1) continue;\n\n                int d = pickDeficitSize(st, rng);\n                vector<int> candT;\n                if (1 <= d && d < s) candT.push_back(d);\n                if (1 <= s - d && s - d < s) candT.push_back(s - d);\n\n                int mid = s / 2;\n                if (1 <= mid && mid < s) candT.push_back(mid);\n\n                int w = max(1, s / 6);\n                int tr = mid + rng.nextInt(-w, w);\n                tr = max(1, min(s - 1, tr));\n                candT.push_back(tr);\n\n                int t = candT[rng.nextInt(0, (int)candT.size() - 1)];\n\n                double th;\n                if (hasPCA && rng.nextDouble() < 0.55) {\n                    th = (rng.nextDouble() < 0.5 ? pca1 : pca2)\n                       + (rng.nextDouble() * 2.0 - 1.0) * 0.28;\n                } else {\n                    th = rng.nextDouble() * PI;\n                }\n                th = normTheta(th);\n\n                Line ln = lineByQuantile(st, pid, th, t, projBuf);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                Line ln = randomGlobalLine(rng);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            if (!found) break;\n\n            bool accept = betterKey(bestEv, cur);\n            if (!accept && noImprove >= 5) {\n                if (bestEv.F == cur.F &&\n                    bestEv.active == cur.active &&\n                    bestEv.def2 <= cur.def2 + 1 &&\n                    (bestEv.waste < cur.waste || bestEv.over < cur.over)) {\n                    accept = true;\n                }\n            }\n\n            if (accept) {\n                applyLine(st, bestLn);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= noImpLimit) break;\n            }\n        }\n\n        RunResult rr;\n        rr.lines = move(st.lines);\n        rr.key = stateKey(st);\n        return rr;\n    }\n\npublic:\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> K;\n        a.fill(0);\n        totalA = 0;\n        for (int d = 1; d <= 10; d++) {\n            cin >> a[d];\n            totalA += a[d];\n        }\n\n        pts.resize(N);\n        for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n        pen.assign(N + 1, 0);\n        for (int s = 0; s <= N; s++) {\n            if (s > 10) {\n                long long t = s - 10;\n                pen[s] = t * t;\n            }\n        }\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        uint64_t seedBase = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            v += 0x9e3779b97f4a7c15ULL;\n            v = (v ^ (v >> 30)) * 0xbf58476d1ce4e5b9ULL;\n            v = (v ^ (v >> 27)) * 0x94d049bb133111ebULL;\n            v ^= (v >> 31);\n            seedBase ^= v + 0x9e3779b97f4a7c15ULL + (seedBase << 6) + (seedBase >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)K);\n        for (int d = 1; d <= 10; d++) mix((uint64_t)a[d]);\n        for (const auto& p : pts) {\n            uint64_t v = ((uint64_t)(p.x + 20000) << 20) ^ (uint64_t)(p.y + 20000);\n            mix(v);\n        }\n\n        EvalKey bestKey{-1, INT_MAX, -1, INT_MAX, BIG};\n        vector<Line> bestLines;\n\n        int runId = 0;\n        while (true) {\n            double rem = TL - elapsed();\n            if (rem < 0.08) break;\n\n            double factor = (runId == 0 ? 0.58 : (runId < 3 ? 0.62 : 0.70));\n            double budget = rem * factor;\n            budget = max(0.14, budget);\n            budget = min(budget, rem - 0.03);\n            if (budget <= 0.02) break;\n\n            double runEnd = elapsed() + budget;\n            uint64_t seed = seedBase + 0x9e3779b97f4a7c15ULL * (uint64_t)(runId + 1);\n\n            RunResult rr = runOne(seed, runId, runEnd);\n            if (bestLines.empty() || betterKey(rr.key, bestKey)) {\n                bestKey = rr.key;\n                bestLines = move(rr.lines);\n            }\n\n            runId++;\n            if (bestKey.F >= totalA) break;\n        }\n\n        if (bestLines.empty()) {\n            cout << 0 << '\\n';\n            return;\n        }\n\n        cout << bestLines.size() << '\\n';\n        for (const auto& ln : bestLines) {\n            cout << ln.x1 << ' ' << ln.y1 << ' ' << ln.x2 << ' ' << ln.y2 << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(next() % (uint64_t)n); } // n > 0\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nclass Solver {\n    using Clock = chrono::steady_clock;\n\n    static constexpr int MAXN = 61;\n    static constexpr int MAXD = 121;\n\n    struct Point {\n        int x, y;\n    };\n    struct Move {\n        int x1, y1, x2, y2, x3, y3, x4, y4;\n    };\n    struct Candidate {\n        Move mv;\n        double val;\n        int w;\n        int L;\n    };\n    struct Core {\n        array<uint64_t, MAXN> row{}, col{}, usedH{}, usedV{};\n        array<uint64_t, MAXD> diagPos{}, diagNeg{}, usedPos{}, usedNeg{};\n        long long sumW = 0;\n        int dotCount = 0;\n    };\n\n    struct HeuParam {\n        double a0, a1; // linear length penalty\n        double b0, b1; // quadratic length penalty\n        double g0, g1; // connectivity bonus\n        bool stochastic;\n        int pickK;\n        int keep;\n    };\n    struct RunConfig {\n        HeuParam h;\n        bool lookahead;\n        int laSteps;\n        int laBranch;\n        double laCoef;\n    };\n    struct RunResult {\n        long long sumW;\n        vector<Move> ops;\n    };\n\n    int N = 0, M = 0;\n    int off = 0;\n    int diagCnt = 0;\n\n    vector<pair<int, int>> initDots;\n    int W[MAXN][MAXN]{};\n    vector<pair<int, int>> cellsByWeight;\n    uint64_t rangeMask[MAXN + 1][MAXN + 1]{};\n\n    inline static constexpr array<int, 8> pairU = {0, 1, 2, 3, 4, 5, 6, 7};\n    inline static constexpr array<int, 8> pairV = {1, 2, 3, 0, 5, 6, 7, 4};\n\n    static inline int ctz64(uint64_t v) { return __builtin_ctzll(v); }\n    static inline int msb64(uint64_t v) { return 63 - __builtin_clzll(v); }\n\n    void buildTables() {\n        off = N - 1;\n        diagCnt = 2 * N - 1;\n\n        int c = (N - 1) / 2;\n        cellsByWeight.clear();\n        cellsByWeight.reserve(N * N);\n\n        for (int y = 0; y < N; y++) {\n            for (int x = 0; x < N; x++) {\n                int dx = x - c;\n                int dy = y - c;\n                W[y][x] = dx * dx + dy * dy + 1;\n                cellsByWeight.emplace_back(x, y);\n            }\n        }\n\n        sort(cellsByWeight.begin(), cellsByWeight.end(), [&](const auto &a, const auto &b) {\n            int wa = W[a.second][a.first];\n            int wb = W[b.second][b.first];\n            if (wa != wb) return wa > wb;\n            if (a.second != b.second) return a.second < b.second;\n            return a.first < b.first;\n        });\n\n        for (int l = 0; l <= N; l++) for (int r = 0; r <= N; r++) rangeMask[l][r] = 0;\n        for (int l = 0; l <= N; l++) {\n            uint64_t m = 0;\n            for (int r = l + 1; r <= N; r++) {\n                m |= (1ULL << (r - 1)); // [l, r)\n                rangeMask[l][r] = m;\n            }\n        }\n    }\n\n    inline bool hasDot(const Core &st, int x, int y) const {\n        return ((st.row[y] >> x) & 1ULL) != 0;\n    }\n\n    inline void addDot(Core &st, int x, int y) const {\n        uint64_t bx = 1ULL << x;\n        st.row[y] |= bx;\n        st.col[x] |= (1ULL << y);\n        st.diagPos[x - y + off] |= bx; // keyed by x-bit\n        st.diagNeg[x + y] |= bx;       // keyed by x-bit\n        st.dotCount++;\n    }\n\n    Point nearestDot(const Core &st, int x, int y, int dir) const {\n        uint64_t m = 0;\n        switch (dir) {\n            case 0: // E\n                m = st.row[y] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                return {ctz64(m), y};\n            case 1: // N\n                m = st.col[x] & (~0ULL << (y + 1));\n                if (!m) return {-1, -1};\n                return {x, ctz64(m)};\n            case 2: // W\n                m = st.row[y] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                return {msb64(m), y};\n            case 3: // S\n                m = st.col[x] & ((1ULL << y) - 1);\n                if (!m) return {-1, -1};\n                return {x, msb64(m)};\n            case 4: { // NE (diag +, x++)\n                int d = x - y + off;\n                m = st.diagPos[d] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                int k = d - off; // x - y\n                return {nx, nx - k};\n            }\n            case 5: { // NW (diag -, x--)\n                int s = x + y;\n                m = st.diagNeg[s] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                return {nx, s - nx};\n            }\n            case 6: { // SW (diag +, x--)\n                int d = x - y + off;\n                m = st.diagPos[d] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                int k = d - off; // x - y\n                return {nx, nx - k};\n            }\n            default: { // 7: SE (diag -, x++)\n                int s = x + y;\n                m = st.diagNeg[s] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                return {nx, s - nx};\n            }\n        }\n    }\n\n    inline bool edgeFree(const Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) { // vertical\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            return (st.usedV[x] & rangeMask[l][r]) == 0;\n        }\n        if (y1 == y2) { // horizontal\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedH[y] & rangeMask[l][r]) == 0;\n        }\n        if ((x2 - x1) == (y2 - y1)) { // diag +\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedPos[d] & rangeMask[l][r]) == 0;\n        }\n        // diag -\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        return (st.usedNeg[s] & rangeMask[l][r]) == 0;\n    }\n\n    inline void useEdge(Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) { // vertical\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            st.usedV[x] |= rangeMask[l][r];\n            return;\n        }\n        if (y1 == y2) { // horizontal\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedH[y] |= rangeMask[l][r];\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) { // diag +\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedPos[d] |= rangeMask[l][r];\n            return;\n        }\n        // diag -\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        st.usedNeg[s] |= rangeMask[l][r];\n    }\n\n    inline void applyMove(Core &st, const Move &mv) const {\n        useEdge(st, mv.x1, mv.y1, mv.x2, mv.y2);\n        useEdge(st, mv.x2, mv.y2, mv.x3, mv.y3);\n        useEdge(st, mv.x3, mv.y3, mv.x4, mv.y4);\n        useEdge(st, mv.x4, mv.y4, mv.x1, mv.y1);\n        addDot(st, mv.x1, mv.y1);\n        st.sumW += W[mv.y1][mv.x1];\n    }\n\n    Core makeBaseState() const {\n        Core st;\n        for (auto [x, y] : initDots) {\n            if (!hasDot(st, x, y)) {\n                addDot(st, x, y);\n                st.sumW += W[y][x];\n            }\n        }\n        return st;\n    }\n\n    inline void evalCoeffs(const HeuParam &h, double progress, double &a, double &b, double &g) const {\n        a = h.a0 + (h.a1 - h.a0) * progress;\n        b = h.b0 + (h.b1 - h.b0) * progress;\n        g = h.g0 + (h.g1 - h.g0) * progress;\n        if (a < 0.0) a = 0.0;\n        if (b < 0.0) b = 0.0;\n        if (g < 0.0) g = 0.0;\n    }\n\n    inline bool betterCand(const Candidate &A, const Candidate &B) const {\n        if (A.val > B.val + 1e-9) return true;\n        if (A.val + 1e-9 < B.val) return false;\n        if (A.w != B.w) return A.w > B.w;\n        return A.L < B.L;\n    }\n\n    void findTopCandidates(const Core &st, double a, double b, double g, int keep, vector<Candidate> &out) const {\n        out.clear();\n        if (keep <= 0) return;\n        if ((int)out.capacity() < keep + 1) out.reserve(keep + 1);\n\n        array<Point, 8> near{};\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n            if ((int)out.size() == keep) {\n                double ub = (double)w - a * 2.0 - b * 4.0 + g * 8.0;\n                if (ub + 1e-9 < out.back().val) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du];\n                Point p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double val = (double)w - a * (double)L - b * (double)L * (double)L + g * (double)conn;\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                int pos = 0;\n                while (pos < (int)out.size() && !betterCand(cand, out[pos])) pos++;\n                if (pos >= keep) continue;\n\n                out.insert(out.begin() + pos, cand);\n                if ((int)out.size() > keep) out.pop_back();\n            }\n        }\n    }\n\n    double findBestValue(const Core &st, double a, double b, double g) const {\n        bool found = false;\n        double best = -1e100;\n        array<Point, 8> near{};\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n            if (found) {\n                double ub = (double)w - a * 2.0 - b * 4.0 + g * 8.0;\n                if (ub + 1e-9 < best) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du];\n                Point p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n                double val = (double)w - a * (double)L - b * (double)L * (double)L + g * (double)conn;\n\n                if (!found || val > best) {\n                    best = val;\n                    found = true;\n                }\n            }\n        }\n\n        return found ? best : -1e100;\n    }\n\n    int pickRankedIndex(int k, XorShift64 &rng) const {\n        if (k <= 1) return 0;\n        int total = k * (k + 1) / 2; // rank-weighted\n        int r = rng.nextInt(total);\n        for (int i = 0; i < k; i++) {\n            int wt = k - i;\n            if (r < wt) return i;\n            r -= wt;\n        }\n        return k - 1;\n    }\n\n    bool selectMove(const Core &st, const RunConfig &cfg, int moveCnt, int baseDotCount, int totalAddable,\n                    XorShift64 &rng, Clock::time_point deadline, Move &out,\n                    vector<Candidate> &cands) const {\n        double progress = (double)(st.dotCount - baseDotCount) / (double)max(1, totalAddable);\n\n        double a, b, g;\n        evalCoeffs(cfg.h, progress, a, b, g);\n\n        bool laPossible = cfg.lookahead && (moveCnt < cfg.laSteps);\n\n        int keep = cfg.h.keep;\n        if (!cfg.h.stochastic && !laPossible) keep = 1;\n        keep = max(keep, max(1, cfg.h.pickK));\n        if (laPossible) keep = max(keep, max(2, cfg.laBranch));\n\n        findTopCandidates(st, a, b, g, keep, cands);\n        if (cands.empty()) return false;\n\n        int idx = 0;\n\n        bool doLA = laPossible && (int)cands.size() >= 2;\n        if (doLA) {\n            if (Clock::now() + chrono::milliseconds(3) >= deadline) doLA = false;\n            if ((int)cands.size() >= 2 && cands[0].val - cands[1].val > 90.0) doLA = false;\n        }\n\n        if (doLA) {\n            int B = min(cfg.laBranch, (int)cands.size());\n            double bestComb = -1e100;\n            vector<int> bestIdx;\n            bestIdx.reserve(B);\n\n            for (int i = 0; i < B; i++) {\n                if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n                Core tmp = st;\n                applyMove(tmp, cands[i].mv);\n\n                double p2 = (double)(tmp.dotCount - baseDotCount) / (double)max(1, totalAddable);\n                double a2, b2, g2;\n                evalCoeffs(cfg.h, p2, a2, b2, g2);\n\n                double nxt = findBestValue(tmp, a2, b2, g2);\n                if (nxt < -1e90) nxt = 0.0;\n\n                double comb = cands[i].val + cfg.laCoef * nxt;\n                if (comb > bestComb + 1e-9) {\n                    bestComb = comb;\n                    bestIdx.clear();\n                    bestIdx.push_back(i);\n                } else if (fabs(comb - bestComb) <= 1e-9) {\n                    bestIdx.push_back(i);\n                }\n            }\n\n            if (!bestIdx.empty()) {\n                if (cfg.h.stochastic && (int)bestIdx.size() >= 2) idx = bestIdx[rng.nextInt((int)bestIdx.size())];\n                else idx = bestIdx[0];\n            } else {\n                idx = 0;\n            }\n        } else {\n            if (cfg.h.stochastic) {\n                int k = min(cfg.h.pickK, (int)cands.size());\n                idx = pickRankedIndex(max(1, k), rng);\n            } else {\n                idx = 0;\n            }\n        }\n\n        out = cands[idx].mv;\n        return true;\n    }\n\n    RunResult runOne(const Core &base, const RunConfig &cfg, XorShift64 &rng, Clock::time_point deadline) const {\n        Core st = base;\n        vector<Move> ops;\n        ops.reserve(max(0, N * N - base.dotCount));\n\n        vector<Candidate> cands;\n        cands.reserve(48);\n\n        int baseDotCount = base.dotCount;\n        int totalAddable = max(1, N * N - baseDotCount);\n\n        int moveCnt = 0;\n        while (true) {\n            if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n            Move mv;\n            if (!selectMove(st, cfg, moveCnt, baseDotCount, totalAddable, rng, deadline, mv, cands)) break;\n\n            applyMove(st, mv);\n            ops.push_back(mv);\n            moveCnt++;\n        }\n\n        return {st.sumW, move(ops)};\n    }\n\n    double randRange(XorShift64 &rng, double l, double r) const {\n        return l + (r - l) * rng.nextDouble();\n    }\n\n    RunConfig randomConfig(XorShift64 &rng, int remainMs) const {\n        RunConfig cfg;\n\n        cfg.h.a0 = randRange(rng, 0.0, 6.5);\n        cfg.h.a1 = randRange(rng, 0.0, 2.8);\n        cfg.h.b0 = randRange(rng, 0.0, 0.055);\n        cfg.h.b1 = randRange(rng, 0.0, 0.03);\n        cfg.h.g0 = randRange(rng, 0.0, 2.5);\n        cfg.h.g1 = randRange(rng, 0.0, 1.5);\n\n        if (rng.nextInt(5) == 0) swap(cfg.h.a0, cfg.h.a1);\n        if (rng.nextInt(6) == 0) swap(cfg.h.b0, cfg.h.b1);\n        if (rng.nextInt(5) == 0) swap(cfg.h.g0, cfg.h.g1);\n\n        cfg.h.stochastic = (rng.nextInt(100) < 88);\n        cfg.h.pickK = 2 + rng.nextInt(8);   // 2..9\n        cfg.h.keep = 10 + rng.nextInt(22);  // 10..31\n\n        if (!cfg.h.stochastic) {\n            cfg.h.pickK = 1;\n            if (rng.nextInt(2) == 0) cfg.h.keep = 1;\n        }\n\n        bool allowLA = (remainMs > 350 && rng.nextInt(100) < 22);\n        if (allowLA) {\n            cfg.lookahead = true;\n            cfg.laSteps = 45 + rng.nextInt(110); // 45..154\n            cfg.laBranch = 3 + rng.nextInt(4);   // 3..6\n            cfg.laCoef = randRange(rng, 0.45, 1.05);\n            cfg.h.keep = max(cfg.h.keep, cfg.laBranch);\n            cfg.h.keep = min(cfg.h.keep, 18);\n        } else {\n            cfg.lookahead = false;\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laCoef = 0.0;\n        }\n\n        return cfg;\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t seed = 1469598103934665603ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v;\n            seed *= 1099511628211ULL;\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        for (auto [x, y] : initDots) {\n            mix(((uint64_t)(uint32_t)x << 32) | (uint32_t)y);\n        }\n        return seed ? seed : 1ULL;\n    }\n\npublic:\n    void readInput() {\n        cin >> N >> M;\n        initDots.resize(M);\n        for (int i = 0; i < M; i++) {\n            int x, y;\n            cin >> x >> y;\n            initDots[i] = {x, y};\n        }\n        buildTables();\n    }\n\n    void solve() {\n        Core base = makeBaseState();\n\n        long long bestSum = base.sumW;\n        vector<Move> bestOps;\n\n        XorShift64 rng(makeSeed());\n        auto deadline = Clock::now() + chrono::milliseconds(4800);\n\n        vector<RunConfig> presets;\n        // short-rectangle oriented (safe expansion)\n        presets.push_back({{5.2, 1.2, 0.033, 0.006, 2.2, 0.4, false, 1, 12}, false, 0, 0, 0.0});\n        presets.push_back({{3.8, 0.7, 0.018, 0.003, 1.6, 0.2, false, 1, 14}, false, 0, 0, 0.0});\n        // balanced stochastic\n        presets.push_back({{2.5, 0.3, 0.010, 0.001, 1.2, 0.1, true, 4, 20}, false, 0, 0, 0.0});\n        // weight-focused\n        presets.push_back({{0.9, 0.0, 0.001, 0.0, 0.5, 0.0, true, 6, 24}, false, 0, 0, 0.0});\n        // lookahead\n        presets.push_back({{4.4, 0.9, 0.020, 0.002, 1.8, 0.2, false, 1, 12}, true, 90, 4, 0.78});\n        presets.push_back({{3.2, 0.6, 0.013, 0.002, 1.1, 0.1, true, 3, 14}, true, 70, 4, 0.68});\n\n        for (const auto &cfg : presets) {\n            if (Clock::now() + chrono::milliseconds(10) >= deadline) break;\n            RunResult rr = runOne(base, cfg, rng, deadline);\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = move(rr.ops);\n            }\n        }\n\n        while (Clock::now() + chrono::milliseconds(25) < deadline) {\n            int rem = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            RunConfig cfg = randomConfig(rng, rem);\n            RunResult rr = runOne(base, cfg, rng, deadline);\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = move(rr.ops);\n            }\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (const auto &m : bestOps) {\n            cout << m.x1 << ' ' << m.y1 << ' '\n                 << m.x2 << ' ' << m.y2 << ' '\n                 << m.x3 << ' ' << m.y3 << ' '\n                 << m.x4 << ' ' << m.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int CELLS = 100;\nstatic constexpr double TIME_LIMIT = 1.90;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Board {\n    uint8_t a[CELLS];\n    int filled;\n};\n\nint F[101];\nint SUF[102][4]; // SUF[t][c] = count of flavor c in [t..100]\nint NEI[CELLS][4];\n\ninline void init_neighbors() {\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int id = r * N + c;\n            NEI[id][0] = (r > 0) ? id - N : -1;      // F (up)\n            NEI[id][1] = (r + 1 < N) ? id + N : -1;  // B (down)\n            NEI[id][2] = (c > 0) ? id - 1 : -1;      // L\n            NEI[id][3] = (c + 1 < N) ? id + 1 : -1;  // R\n        }\n    }\n}\n\ninline void tilt(const Board& src, Board& dst, int dir) {\n    dst.filled = src.filled;\n    if (dir == 2) { // L\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = 0;\n            for (int c = 0; c < N; ++c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w++)] = v;\n            }\n            while (w < N) dst.a[base + (w++)] = 0;\n        }\n    } else if (dir == 3) { // R\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w--)] = v;\n            }\n            while (w >= 0) dst.a[base + (w--)] = 0;\n        }\n    } else if (dir == 0) { // F\n        for (int c = 0; c < N; ++c) {\n            int w = 0;\n            for (int r = 0; r < N; ++r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w++) * N + c] = v;\n            }\n            while (w < N) dst.a[(w++) * N + c] = 0;\n        }\n    } else { // B\n        for (int c = 0; c < N; ++c) {\n            int w = N - 1;\n            for (int r = N - 1; r >= 0; --r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w--) * N + c] = v;\n            }\n            while (w >= 0) dst.a[(w--) * N + c] = 0;\n        }\n    }\n}\n\ninline void place_by_rank(Board& b, int rank, uint8_t flavor) {\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            if (--rank == 0) {\n                b.a[i] = flavor;\n                ++b.filled;\n                return;\n            }\n        }\n    }\n    // Fallback (shouldn't happen)\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            b.a[i] = flavor;\n            ++b.filled;\n            return;\n        }\n    }\n}\n\ninline void comp_sq_by_flavor(const Board& b, int out[4]) {\n    out[0] = out[1] = out[2] = out[3] = 0;\n\n    static uint32_t seen[CELLS];\n    static uint32_t stamp = 1;\n    ++stamp;\n    if (stamp == 0) {\n        memset(seen, 0, sizeof(seen));\n        stamp = 1;\n    }\n\n    int q[CELLS];\n    for (int i = 0; i < CELLS; ++i) {\n        uint8_t col = b.a[i];\n        if (col == 0 || seen[i] == stamp) continue;\n\n        seen[i] = stamp;\n        int head = 0, tail = 0;\n        q[tail++] = i;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            ++sz;\n            int to;\n\n            to = NEI[v][0];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n            to = NEI[v][1];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n            to = NEI[v][2];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n            to = NEI[v][3];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n        }\n        out[col] += sz * sz;\n    }\n}\n\ninline int comp_sq_total(const Board& b) {\n    int c[4];\n    comp_sq_by_flavor(b, c);\n    return c[1] + c[2] + c[3];\n}\n\n// Heuristic score used in rollout / lookahead.\n// nextTurn: first future turn index not yet processed (1..101).\ninline long long state_score(const Board& b, int nextTurn) {\n    if (nextTurn > 101) nextTurn = 101;\n    int c[4];\n    comp_sq_by_flavor(b, c);\n\n    long long total = static_cast<long long>(c[1] + c[2] + c[3]);\n\n    // Main objective + mild bias to flavors with many future candies.\n    long long score = total * 96LL;\n    score += 1LL * c[1] * SUF[nextTurn][1];\n    score += 1LL * c[2] * SUF[nextTurn][2];\n    score += 1LL * c[3] * SUF[nextTurn][3];\n    return score;\n}\n\ninline void greedy_tilt_rollout(Board& b, int turn) {\n    // turn = current turn u (after placing candy u), choose tilt for u\n    Board tmp, bestB;\n    long long bestVal = LLONG_MIN;\n    int nextTurn = turn + 1;\n\n    for (int d = 0; d < 4; ++d) {\n        tilt(b, tmp, d);\n        long long v = state_score(tmp, nextTurn);\n        if (v > bestVal) {\n            bestVal = v;\n            bestB = tmp;\n        }\n    }\n    b = bestB;\n}\n\ndouble exact_expect(const Board& b, int nextTurn) {\n    // State: board after previous tilt, before placing candy nextTurn.\n    if (nextTurn == 101) {\n        return static_cast<double>(comp_sq_total(b));\n    }\n\n    int empties = 101 - nextTurn;\n    double sum = 0.0;\n\n    for (int p = 1; p <= empties; ++p) {\n        Board placed = b;\n        place_by_rank(placed, p, static_cast<uint8_t>(F[nextTurn]));\n\n        if (nextTurn == 100) {\n            // Last candy: final tilt has no effect.\n            sum += static_cast<double>(comp_sq_total(placed));\n        } else {\n            double best = -1e100;\n            Board nxt;\n            for (int d = 0; d < 4; ++d) {\n                tilt(placed, nxt, d);\n                double v = exact_expect(nxt, nextTurn + 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n    }\n    return sum / static_cast<double>(empties);\n}\n\nint choose_move(const Board& cur, int t, XorShift& rng, const Timer& timer) {\n    int rem = 100 - t;\n    if (rem <= 0) return 0;\n\n    Board first[4];\n    long long firstScore[4];\n    for (int d = 0; d < 4; ++d) {\n        tilt(cur, first[d], d);\n        firstScore[d] = state_score(first[d], t + 1);\n    }\n\n    int bestImmediate = 0;\n    for (int d = 1; d < 4; ++d) {\n        if (firstScore[d] > firstScore[bestImmediate]) bestImmediate = d;\n    }\n\n    double timeLeft = TIME_LIMIT - timer.elapsed();\n    if (timeLeft < 0.010) return bestImmediate;\n\n    // Exact endgame optimization.\n    if (rem <= 5 && timeLeft > 0.050) {\n        int bestDir = bestImmediate;\n        double bestVal = -1e100;\n        for (int d = 0; d < 4; ++d) {\n            double v = exact_expect(first[d], t + 1);\n            if (v > bestVal + 1e-12 ||\n                (fabs(v - bestVal) <= 1e-12 && firstScore[d] > firstScore[bestDir])) {\n                bestVal = v;\n                bestDir = d;\n            }\n        }\n        return bestDir;\n    }\n\n    // Adaptive horizon.\n    int H;\n    if (rem >= 70) H = 10;\n    else if (rem >= 50) H = 14;\n    else if (rem >= 35) H = 18;\n    else if (rem >= 22) H = 24;\n    else H = rem;\n\n    H = min(H, rem);\n    int endTurn = t + H;\n    int evalNextTurn = min(101, endTurn + 1);\n\n    // Adaptive per-turn time budget.\n    double reserve = 0.050;\n    double budget = timeLeft / (rem + 1) * 1.35;\n    if (rem <= 15) budget *= 1.20;\n\n    budget = min(budget, 0.040);\n    budget = max(budget, 0.0015);\n    if (timeLeft - reserve < budget) budget = max(0.0008, timeLeft - reserve);\n\n    if (budget <= 0.0009) return bestImmediate;\n\n    long long total[4] = {0, 0, 0, 0};\n    int cnt = 0;\n    uint8_t ranks[101];\n\n    double deadline = timer.elapsed() + budget;\n    const int MAX_SCENARIOS = 96;\n    int minScen = (budget < 0.0035 ? 1 : 2);\n\n    while (cnt < MAX_SCENARIOS) {\n        if (cnt >= minScen && timer.elapsed() > deadline) break;\n\n        // Common random numbers across 4 candidate first moves.\n        for (int u = t + 1; u <= endTurn; ++u) {\n            ranks[u] = static_cast<uint8_t>(rng.next_int(1, 101 - u));\n        }\n\n        for (int d = 0; d < 4; ++d) {\n            Board b = first[d];\n\n            for (int u = t + 1; u <= endTurn; ++u) {\n                place_by_rank(b, static_cast<int>(ranks[u]), static_cast<uint8_t>(F[u]));\n                if (u < 100) {\n                    greedy_tilt_rollout(b, u);\n                }\n            }\n            total[d] += state_score(b, evalNextTurn);\n        }\n\n        ++cnt;\n    }\n\n    if (cnt == 0) return bestImmediate;\n\n    int bestDir = 0;\n    for (int d = 1; d < 4; ++d) {\n        if (total[d] > total[bestDir] ||\n            (total[d] == total[bestDir] && firstScore[d] > firstScore[bestDir])) {\n            bestDir = d;\n        }\n    }\n    return bestDir;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 1; i <= 100; ++i) {\n        if (!(cin >> F[i])) return 0;\n    }\n\n    for (int c = 1; c <= 3; ++c) SUF[101][c] = 0;\n    for (int t = 100; t >= 1; --t) {\n        for (int c = 1; c <= 3; ++c) SUF[t][c] = SUF[t + 1][c];\n        SUF[t][F[t]]++;\n    }\n\n    init_neighbors();\n\n    uint64_t seed = 1469598103934665603ull;\n    for (int i = 1; i <= 100; ++i) {\n        seed ^= static_cast<uint64_t>(F[i] + 131 * i);\n        seed *= 1099511628211ull;\n    }\n    XorShift rng(seed);\n    Timer timer;\n\n    Board cur{};\n    memset(cur.a, 0, sizeof(cur.a));\n    cur.filled = 0;\n\n    for (int t = 1; t <= 100; ++t) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        place_by_rank(cur, p, static_cast<uint8_t>(F[t]));\n\n        int dir = 0; // F\n        if (t < 100) {\n            dir = choose_move(cur, t, rng, timer);\n            Board nxt;\n            tilt(cur, nxt, dir);\n            cur = nxt;\n        }\n\n        cout << DIR_CH[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    inline 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    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline uint64_t prob_to_u64(double p) {\n    if (p <= 0.0) return 0ULL;\n    if (p >= 1.0) return numeric_limits<uint64_t>::max();\n    long double v = p * (long double)numeric_limits<uint64_t>::max();\n    if (v < 0) v = 0;\n    if (v > (long double)numeric_limits<uint64_t>::max()) v = (long double)numeric_limits<uint64_t>::max();\n    return (uint64_t)v;\n}\n\nstruct Sig3 {\n    int d, n1, n2;\n    bool operator<(const Sig3& o) const {\n        if (d != o.d) return d < o.d;\n        if (n1 != o.n1) return n1 < o.n1;\n        return n2 < o.n2;\n    }\n};\n\nstruct Weights {\n    double w1 = 0.0;\n    double w2 = 0.0;\n};\n\nstatic inline Weights compute_weights(double eps, int N) {\n    double a = max(0.0, 1.0 - 2.0 * eps);\n    double n2 = (double)N * N;\n    double n4 = n2 * n2;\n    Weights w;\n    // tuned: degree base + 2nd/3rd order with epsilon attenuation\n    w.w1 = (0.08 + 1.20 * a * a) / n2;\n    w.w2 = (0.005 + 0.80 * a * a * a * a) / n4;\n    return w;\n}\n\nstruct Graph {\n    vector<uint8_t> bits; // length L\n    vector<int> deg_sorted;\n    vector<int> nd_sorted;\n    vector<int> nd2_sorted;\n    int edges = 0;\n};\n\nstruct Codebook {\n    int N = 0;\n    int L = 0;\n    int distinct = 0; // unique signatures in selected set\n    vector<int> eu, ev;\n    vector<Graph> graphs;\n};\n\nstruct FeatureWork {\n    vector<int> deg, nd, nd2;\n    vector<Sig3> sig;\n    vector<uint8_t> bits; // for noisy sampling\n    FeatureWork() {}\n    FeatureWork(int N, int L) { init(N, L); }\n    void init(int N, int L) {\n        deg.assign(N, 0);\n        nd.assign(N, 0);\n        nd2.assign(N, 0);\n        sig.assign(N, {0, 0, 0});\n        bits.assign(L, 0);\n    }\n};\n\nstruct ProtoBank {\n    int M = 0, N = 0, S = 0;\n    Weights w;\n    vector<int16_t> deg;   // size M*S*N\n    vector<int32_t> nd;    // size M*S*N\n    vector<int32_t> nd2;   // size M*S*N\n\n    vector<float> cdeg;    // size M*N\n    vector<float> cnd;     // size M*N\n    vector<float> cnd2;    // size M*N\n};\n\nvoid build_edges(int N, vector<int>& eu, vector<int>& ev) {\n    eu.clear();\n    ev.clear();\n    eu.reserve(N * (N - 1) / 2);\n    ev.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            eu.push_back(i);\n            ev.push_back(j);\n        }\n    }\n}\n\nGraph make_graph_from_bits(vector<uint8_t>&& bits, int N, const vector<int>& eu, const vector<int>& ev) {\n    Graph g;\n    g.bits = std::move(bits);\n    int L = (int)eu.size();\n\n    vector<int> deg(N, 0), nd(N, 0), nd2(N, 0);\n    g.edges = 0;\n\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            g.edges++;\n            int u = eu[e], v = ev[e];\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd[u] += deg[v];\n            nd[v] += deg[u];\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd2[u] += nd[v];\n            nd2[v] += nd[u];\n        }\n    }\n\n    vector<Sig3> sig(N);\n    for (int i = 0; i < N; i++) sig[i] = {deg[i], nd[i], nd2[i]};\n    sort(sig.begin(), sig.end());\n\n    g.deg_sorted.resize(N);\n    g.nd_sorted.resize(N);\n    g.nd2_sorted.resize(N);\n    for (int i = 0; i < N; i++) {\n        g.deg_sorted[i] = sig[i].d;\n        g.nd_sorted[i] = sig[i].n1;\n        g.nd2_sorted[i] = sig[i].n2;\n    }\n    return g;\n}\n\nuint64_t hash_feature_arrays(const vector<int>& a, const vector<int>& b, const vector<int>& c) {\n    uint64_t h = 1469598103934665603ULL;\n    int N = (int)a.size();\n    for (int i = 0; i < N; i++) {\n        h ^= (uint64_t)(a[i] + 1);\n        h *= 1099511628211ULL;\n        h ^= (uint64_t)(b[i] + 10007);\n        h *= 1099511628211ULL;\n        h ^= (uint64_t)(c[i] + 1000003);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nuint64_t hash_signature(const Graph& g) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)(g.edges + 1);\n    h *= 1099511628211ULL;\n    int N = (int)g.deg_sorted.size();\n    for (int i = 0; i < N; i++) {\n        h ^= (uint64_t)(g.deg_sorted[i] + 1);\n        h *= 1099511628211ULL;\n        h ^= (uint64_t)(g.nd_sorted[i] + 10007);\n        h *= 1099511628211ULL;\n        h ^= (uint64_t)(g.nd2_sorted[i] + 1000003);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvector<int> random_group_ids(int N, int K, RNG& rng) {\n    K = min(K, N);\n    vector<int> sz(K, 1);\n    int rem = N - K;\n    for (int i = 0; i < rem; i++) sz[rng.next_int(0, K - 1)]++;\n\n    vector<int> gid;\n    gid.reserve(N);\n    for (int g = 0; g < K; g++) {\n        for (int c = 0; c < sz[g]; c++) gid.push_back(g);\n    }\n    for (int i = N - 1; i >= 1; i--) {\n        int j = rng.next_int(0, i);\n        swap(gid[i], gid[j]);\n    }\n    return gid;\n}\n\nGraph generate_candidate_graph(int N, const vector<int>& eu, const vector<int>& ev, RNG& rng, double eps) {\n    int L = (int)eu.size();\n    vector<uint8_t> bits(L, 0);\n    int mode = rng.next_int(0, 7);\n\n    if (mode == 0) {\n        // Erdos-Renyi with bias to extremes\n        double u = rng.next_double();\n        double p = (rng.next_double() < 0.5) ? (u * u) : (1.0 - (1.0 - u) * (1.0 - u));\n        uint64_t th = prob_to_u64(p);\n        for (int e = 0; e < L; e++) bits[e] = (rng.next_u64() < th);\n    } else if (mode == 1) {\n        // Binary SBM\n        int K = rng.next_int(2, min(8, N));\n        auto gid = random_group_ids(N, K, rng);\n        vector<vector<uint8_t>> B(K, vector<uint8_t>(K, 0));\n        for (int i = 0; i < K; i++) {\n            for (int j = i; j < K; j++) {\n                uint8_t x = (uint8_t)(rng.next_u64() & 1ULL);\n                B[i][j] = B[j][i] = x;\n            }\n        }\n        for (int e = 0; e < L; e++) {\n            bits[e] = B[gid[eu[e]]][gid[ev[e]]];\n        }\n    } else if (mode == 2) {\n        // Union of cliques\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] == gid[ev[e]]);\n    } else if (mode == 3) {\n        // Complete multipartite\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] != gid[ev[e]]);\n    } else if (mode == 4) {\n        // Product threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000000);\n        for (int e = 0; e < L; e++) {\n            long long v = 1LL * w[eu[e]] * w[ev[e]];\n            bits[e] = (v >= th);\n        }\n    } else if (mode == 5) {\n        // Sum threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 2000);\n        for (int e = 0; e < L; e++) bits[e] = (w[eu[e]] + w[ev[e]] >= th);\n    } else if (mode == 6) {\n        // Geometric interval graph\n        vector<double> x(N);\n        for (int i = 0; i < N; i++) x[i] = rng.next_double();\n        double th = rng.next_double() * 0.8;\n        bool circle = (rng.next_u64() & 1ULL);\n        for (int e = 0; e < L; e++) {\n            double d = fabs(x[eu[e]] - x[ev[e]]);\n            if (circle) d = min(d, 1.0 - d);\n            bits[e] = (d <= th);\n        }\n    } else {\n        // XOR of two partitions\n        int K1 = rng.next_int(2, min(7, N));\n        int K2 = rng.next_int(2, min(7, N));\n        auto g1 = random_group_ids(N, K1, rng);\n        auto g2 = random_group_ids(N, K2, rng);\n        for (int e = 0; e < L; e++) {\n            bool a = (g1[eu[e]] == g1[ev[e]]);\n            bool b = (g2[eu[e]] == g2[ev[e]]);\n            bits[e] = (uint8_t)(a ^ b);\n        }\n    }\n\n    // occasional complement for diversity\n    if (rng.next_double() < 0.10) {\n        for (int e = 0; e < L; e++) bits[e] ^= 1;\n    }\n\n    // small random perturbation\n    if (rng.next_double() < 0.85) {\n        double pmax = (mode == 0 ? 0.02 : 0.06);\n        if (eps > 0.25) pmax += 0.02;\n        double pf = rng.next_double() * pmax;\n        uint64_t th = prob_to_u64(pf);\n        for (int e = 0; e < L; e++) {\n            if (rng.next_u64() < th) bits[e] ^= 1;\n        }\n    }\n\n    return make_graph_from_bits(std::move(bits), N, eu, ev);\n}\n\nCodebook build_codebook(int N, int M, double eps, int C, RNG& rng) {\n    Codebook cb;\n    cb.N = N;\n    build_edges(N, cb.eu, cb.ev);\n    cb.L = (int)cb.eu.size();\n\n    vector<Graph> cand;\n    cand.reserve(C);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve((size_t)C * 3);\n\n    int attempts = 0;\n    int maxAttempts = C * 25;\n\n    while ((int)cand.size() < C && attempts < maxAttempts) {\n        Graph g = generate_candidate_graph(N, cb.eu, cb.ev, rng, eps);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        attempts++;\n    }\n\n    // fallback: edge-prefix family\n    for (int m = 0; (int)cand.size() < C && m <= cb.L; m++) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < m; e++) bits[e] = 1;\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n    }\n\n    // fallback: random bits\n    int extra = 0;\n    while ((int)cand.size() < C && extra < C * 6) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < cb.L; e++) bits[e] = (uint8_t)(rng.next_u64() & 1ULL);\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        extra++;\n    }\n\n    if (cand.empty()) {\n        vector<uint8_t> bits(cb.L, 0);\n        cand.push_back(make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev));\n    }\n\n    int Cn = (int)cand.size();\n    Weights w = compute_weights(eps, N);\n\n    auto dist_idx = [&](int a, int b) -> double {\n        const auto& A = cand[a];\n        const auto& B = cand[b];\n        double s = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)A.deg_sorted[i] - (double)B.deg_sorted[i];\n            s += d * d;\n        }\n        if (w.w1 > 0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd_sorted[i] - (double)B.nd_sorted[i];\n                s += w.w1 * d * d;\n            }\n        }\n        if (w.w2 > 0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd2_sorted[i] - (double)B.nd2_sorted[i];\n                s += w.w2 * d * d;\n            }\n        }\n        return s;\n    };\n\n    vector<int> selected;\n    selected.reserve(M);\n    vector<char> used(Cn, false);\n\n    int imin = 0, imax = 0;\n    for (int i = 1; i < Cn; i++) {\n        if (cand[i].edges < cand[imin].edges) imin = i;\n        if (cand[i].edges > cand[imax].edges) imax = i;\n    }\n\n    selected.push_back(imin);\n    used[imin] = true;\n    if ((int)selected.size() < M && imax != imin) {\n        selected.push_back(imax);\n        used[imax] = true;\n    }\n\n    vector<double> minDist(Cn, 1e300);\n    for (int i = 0; i < Cn; i++) {\n        double d = 1e300;\n        for (int s : selected) d = min(d, dist_idx(i, s));\n        minDist[i] = d;\n    }\n\n    while ((int)selected.size() < M && (int)selected.size() < Cn) {\n        int best = -1;\n        double bestVal = -1.0;\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i] && minDist[i] > bestVal) {\n                bestVal = minDist[i];\n                best = i;\n            }\n        }\n        if (best == -1) break;\n        selected.push_back(best);\n        used[best] = true;\n\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i]) {\n                double d = dist_idx(i, best);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    int uniqueSel = (int)selected.size();\n    if (uniqueSel == 0) {\n        selected.push_back(0);\n        uniqueSel = 1;\n    }\n    while ((int)selected.size() < M) {\n        selected.push_back(selected[(int)selected.size() % uniqueSel]);\n    }\n\n    cb.distinct = min(uniqueSel, M);\n    cb.graphs.reserve(M);\n    for (int i = 0; i < M; i++) cb.graphs.push_back(cand[selected[i]]);\n    return cb;\n}\n\nvoid extract_sorted_features_from_string(\n    const string& H, const Codebook& cb, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2\n) {\n    int N = cb.N, L = cb.L;\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.sig[i] = {w.deg[i], w.nd[i], w.nd2[i]};\n    sort(w.sig.begin(), w.sig.end());\n\n    if ((int)outDeg.size() != N) {\n        outDeg.resize(N);\n        outNd.resize(N);\n        outNd2.resize(N);\n    }\n    for (int i = 0; i < N; i++) {\n        outDeg[i] = w.sig[i].d;\n        outNd[i] = w.sig[i].n1;\n        outNd2[i] = w.sig[i].n2;\n    }\n}\n\nvoid sample_noisy_sorted_features(\n    const Graph& g, const Codebook& cb, double eps, uint64_t flipThr,\n    RNG& rng, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2\n) {\n    int N = cb.N, L = cb.L;\n    if (eps <= 0.0) {\n        outDeg = g.deg_sorted;\n        outNd = g.nd_sorted;\n        outNd2 = g.nd2_sorted;\n        return;\n    }\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    for (int e = 0; e < L; e++) {\n        uint8_t b = g.bits[e];\n        if (rng.next_u64() < flipThr) b ^= 1;\n        w.bits[e] = b;\n        if (b) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.sig[i] = {w.deg[i], w.nd[i], w.nd2[i]};\n    sort(w.sig.begin(), w.sig.end());\n\n    if ((int)outDeg.size() != N) {\n        outDeg.resize(N);\n        outNd.resize(N);\n        outNd2.resize(N);\n    }\n    for (int i = 0; i < N; i++) {\n        outDeg[i] = w.sig[i].d;\n        outNd[i] = w.sig[i].n1;\n        outNd2[i] = w.sig[i].n2;\n    }\n}\n\nProtoBank calibrate_prototypes(const Codebook& cb, double eps, int S, const Weights& wt, RNG& rng) {\n    ProtoBank pb;\n    pb.M = (int)cb.graphs.size();\n    pb.N = cb.N;\n    pb.S = (eps <= 0.0 ? 1 : max(1, S));\n    pb.w = wt;\n\n    size_t total = (size_t)pb.M * pb.S * pb.N;\n    pb.deg.assign(total, 0);\n    pb.nd.assign(total, 0);\n    pb.nd2.assign(total, 0);\n\n    pb.cdeg.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd2.assign((size_t)pb.M * pb.N, 0.0f);\n\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N);\n    vector<double> sumD(cb.N), sumN(cb.N), sumN2(cb.N);\n\n    uint64_t flipThr = prob_to_u64(eps);\n    bool includeClean = (eps > 0.0 && eps < 0.015 && pb.S >= 2);\n\n    for (int k = 0; k < pb.M; k++) {\n        fill(sumD.begin(), sumD.end(), 0.0);\n        fill(sumN.begin(), sumN.end(), 0.0);\n        fill(sumN2.begin(), sumN2.end(), 0.0);\n\n        for (int s = 0; s < pb.S; s++) {\n            if (eps <= 0.0 || (includeClean && s == 0)) {\n                od = cb.graphs[k].deg_sorted;\n                on = cb.graphs[k].nd_sorted;\n                on2 = cb.graphs[k].nd2_sorted;\n            } else {\n                sample_noisy_sorted_features(cb.graphs[k], cb, eps, flipThr, rng, w, od, on, on2);\n            }\n\n            size_t base = ((size_t)k * pb.S + s) * pb.N;\n            for (int i = 0; i < pb.N; i++) {\n                pb.deg[base + i] = (int16_t)od[i];\n                pb.nd[base + i] = (int32_t)on[i];\n                pb.nd2[base + i] = (int32_t)on2[i];\n                sumD[i] += od[i];\n                sumN[i] += on[i];\n                sumN2[i] += on2[i];\n            }\n        }\n\n        for (int i = 0; i < pb.N; i++) {\n            pb.cdeg[(size_t)k * pb.N + i] = (float)(sumD[i] / pb.S);\n            pb.cnd[(size_t)k * pb.N + i] = (float)(sumN[i] / pb.S);\n            pb.cnd2[(size_t)k * pb.N + i] = (float)(sumN2[i] / pb.S);\n        }\n    }\n\n    return pb;\n}\n\nint decode_with_prototypes(\n    const vector<int>& od, const vector<int>& on, const vector<int>& on2,\n    const ProtoBank& pb\n) {\n    int M = pb.M, N = pb.N, S = pb.S;\n    double w1 = pb.w.w1, w2 = pb.w.w2;\n\n    int best = 0;\n    double bestScore = 1e300;\n\n    for (int k = 0; k < M; k++) {\n        // center distance\n        const float* cd = pb.cdeg.data() + (size_t)k * N;\n        const float* cn = pb.cnd.data() + (size_t)k * N;\n        const float* c2 = pb.cnd2.data() + (size_t)k * N;\n\n        double cdist = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)od[i] - (double)cd[i];\n            cdist += d * d;\n        }\n        if (w1 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on[i] - (double)cn[i];\n                cdist += w1 * d * d;\n            }\n        }\n        if (w2 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on2[i] - (double)c2[i];\n                cdist += w2 * d * d;\n            }\n        }\n\n        double lim = 1e300;\n        if (bestScore < 1e299) {\n            lim = (bestScore - 0.25 * cdist) / 0.75;\n            if (lim <= 0.0) continue;\n        }\n\n        double md = 1e300;\n        for (int s = 0; s < S; s++) {\n            size_t base = ((size_t)k * S + s) * N;\n            const int16_t* pd = pb.deg.data() + base;\n            const int32_t* pn = pb.nd.data() + base;\n            const int32_t* p2 = pb.nd2.data() + base;\n\n            double cutoff = min(lim, md);\n            double dsum = 0.0;\n\n            for (int i = 0; i < N; i++) {\n                double d = (double)od[i] - (double)pd[i];\n                dsum += d * d;\n                if (dsum >= cutoff) break;\n            }\n            if (dsum >= cutoff) continue;\n\n            if (w1 > 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on[i] - (double)pn[i];\n                    dsum += w1 * d * d;\n                    if (dsum >= cutoff) break;\n                }\n                if (dsum >= cutoff) continue;\n            }\n\n            if (w2 > 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on2[i] - (double)p2[i];\n                    dsum += w2 * d * d;\n                    if (dsum >= cutoff) break;\n                }\n                if (dsum >= cutoff) continue;\n            }\n\n            if (dsum < md) md = dsum;\n        }\n\n        double score = 0.75 * md + 0.25 * cdist;\n        if (score < bestScore) {\n            bestScore = score;\n            best = k;\n        }\n    }\n\n    return best;\n}\n\ndouble evaluate_codebook(const Codebook& cb, const ProtoBank& pb, double eps, int T, RNG& rng) {\n    if (cb.distinct < pb.M) return -1e100;\n    if (T <= 0) return -1e100;\n\n    int err = 0;\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N);\n\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int t = 0; t < T; t++) {\n        int s = rng.next_int(0, pb.M - 1);\n        sample_noisy_sorted_features(cb.graphs[s], cb, eps, flipThr, rng, w, od, on, on2);\n        int pred = decode_with_prototypes(od, on, on2, pb);\n        if (pred != s) err++;\n    }\n\n    double q = (double)err / (double)T;\n    double st = sqrt(max(1e-12, q * (1.0 - q) / T));\n    // conservative estimate to avoid overfitting in selection\n    double qu = min(1.0, q + 1.2 * st + 1.0 / T);\n    double survive = max(0.0, 1.0 - 0.1 * qu);\n    return pow(survive, 100.0) / (double)cb.N;\n}\n\nvector<int> choose_candidate_Ns(int M, double eps) {\n    // unlabeled graph counts A000088 (n=0..10)\n    static const vector<long long> unl = {\n        0LL, 1LL, 1LL, 2LL, 4LL, 11LL, 34LL, 156LL, 1044LL, 12346LL, 274668LL\n    };\n\n    int nlb = 4;\n    while (nlb + 1 < (int)unl.size() && unl[nlb] < M) nlb++;\n\n    vector<int> Ns;\n    auto add = [&](int n) {\n        n = max(4, min(100, n));\n        if (find(Ns.begin(), Ns.end(), n) == Ns.end()) Ns.push_back(n);\n    };\n\n    if (eps < 0.05) {\n        add(nlb);\n        add(nlb + 2);\n        add(10);\n        add(14);\n        add(20);\n        add(28);\n    } else if (eps < 0.12) {\n        add(max(nlb, 8));\n        add(14);\n        add(22);\n        add(32);\n        add(44);\n        add(58);\n    } else if (eps < 0.22) {\n        add(max(nlb, 10));\n        add(20);\n        add(32);\n        add(46);\n        add(62);\n        add(80);\n    } else if (eps < 0.32) {\n        add(max(nlb, 14));\n        add(28);\n        add(42);\n        add(60);\n        add(80);\n        add(100);\n    } else {\n        add(max(nlb, 18));\n        add(36);\n        add(56);\n        add(76);\n        add(92);\n        add(100);\n    }\n\n    sort(Ns.begin(), Ns.end());\n    Ns.erase(unique(Ns.begin(), Ns.end()), Ns.end());\n    return Ns;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count();\n    };\n\n    uint64_t epsInt = (uint64_t)llround(eps * 100.0);\n    uint64_t baseSeed = 0x3141592653589793ULL ^ (uint64_t)M * 10007ULL ^ (epsInt * 1000003ULL);\n\n    vector<int> Ns = choose_candidate_Ns(M, eps);\n    if (eps >= 0.22) reverse(Ns.begin(), Ns.end()); // high noise: try larger N first\n\n    double bestEst = -1e100;\n    Codebook bestCb;\n    Weights bestWt;\n    bool haveBest = false;\n\n    const long long searchDeadline = 2600;\n    bool stop = false;\n\n    for (int ni = 0; ni < (int)Ns.size() && !stop; ni++) {\n        int N = Ns[ni];\n        int attempts = 1;\n        if (M >= 70 || eps >= 0.12) attempts = 2;\n\n        for (int att = 0; att < attempts; att++) {\n            if (elapsed_ms() > searchDeadline) {\n                stop = true;\n                break;\n            }\n\n            int C = max(500, M * 12);\n            if (eps > 0.25) C = max(C, M * 14);\n            if (N <= 10) C = max(C, 900);\n            if (M > 80) C += 120;\n            C = min(C, 1600);\n\n            RNG rngBuild(baseSeed + 1000003ULL * (uint64_t)N + 911ULL * (uint64_t)att + 97ULL * (uint64_t)ni + 17ULL);\n            Codebook cb = build_codebook(N, M, eps, C, rngBuild);\n\n            if (cb.distinct < M) continue;\n\n            Weights wt = compute_weights(eps, N);\n\n            int Se = (eps < 0.08 ? 3 : (eps < 0.20 ? 4 : 5));\n            if (M > 80 && Se < 5) Se++;\n\n            RNG rngCal(baseSeed + 2000003ULL * (uint64_t)N + 1237ULL * (uint64_t)att + 23ULL);\n            ProtoBank pb = calibrate_prototypes(cb, eps, Se, wt, rngCal);\n\n            int Te = (eps < 0.08 ? 180 : (eps < 0.20 ? 220 : 260));\n            if (M > 80) Te += 40;\n            if (elapsed_ms() > 1800) Te = max(120, Te - 80);\n\n            RNG rngEval(baseSeed + 3000017ULL * (uint64_t)N + 37ULL * (uint64_t)att + 131ULL);\n            double est = evaluate_codebook(cb, pb, eps, Te, rngEval);\n\n            if (est > bestEst) {\n                bestEst = est;\n                bestCb = std::move(cb);\n                bestWt = wt;\n                haveBest = true;\n            }\n        }\n    }\n\n    if (!haveBest || bestCb.graphs.empty()) {\n        int Nfb = 40;\n        if (!Ns.empty()) Nfb = *max_element(Ns.begin(), Ns.end());\n        Nfb = max(4, min(100, Nfb));\n\n        int C = max(700, M * 14);\n        C = min(C, 1600);\n\n        RNG rngBuild(baseSeed + 0x9e3779b97f4a7c15ULL);\n        bestCb = build_codebook(Nfb, M, eps, C, rngBuild);\n        bestWt = compute_weights(eps, bestCb.N);\n    }\n\n    int Sf;\n    if (eps < 0.05) Sf = 10;\n    else if (eps < 0.15) Sf = 14;\n    else if (eps < 0.30) Sf = 18;\n    else Sf = 22;\n    if (M > 80) Sf += 2;\n\n    if (elapsed_ms() > 3300) Sf = max(6, Sf - 4);\n    if (elapsed_ms() > 4000) Sf = max(4, Sf / 2);\n\n    RNG rngFinal(baseSeed ^ 0x123456789abcdef0ULL);\n    ProtoBank protoFinal = calibrate_prototypes(bestCb, eps, Sf, bestWt, rngFinal);\n\n    // output codebook\n    cout << bestCb.N << '\\n';\n    for (int k = 0; k < M; k++) {\n        string s(bestCb.L, '0');\n        const auto& bits = bestCb.graphs[k].bits;\n        for (int e = 0; e < bestCb.L; e++) {\n            if (bits[e]) s[e] = '1';\n        }\n        cout << s << '\\n';\n    }\n    cout.flush();\n\n    // exact hash map for eps==0\n    bool useExact = (eps <= 0.0);\n    unordered_map<uint64_t, int> exactMap;\n    if (useExact) {\n        exactMap.reserve((size_t)M * 2);\n        for (int k = 0; k < M; k++) {\n            uint64_t h = hash_feature_arrays(\n                bestCb.graphs[k].deg_sorted,\n                bestCb.graphs[k].nd_sorted,\n                bestCb.graphs[k].nd2_sorted\n            );\n            if (!exactMap.count(h)) exactMap[h] = k;\n        }\n    }\n\n    FeatureWork qwork(bestCb.N, bestCb.L);\n    vector<int> od(bestCb.N), on(bestCb.N), on2(bestCb.N);\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) return 0;\n\n        extract_sorted_features_from_string(H, bestCb, qwork, od, on, on2);\n\n        int ans = 0;\n        if (useExact) {\n            uint64_t h = hash_feature_arrays(od, on, on2);\n            auto it = exactMap.find(h);\n            if (it != exactMap.end()) ans = it->second;\n            else ans = decode_with_prototypes(od, on, on2, protoFinal);\n        } else {\n            ans = decode_with_prototypes(od, on, on2, protoFinal);\n        }\n\n        if (ans < 0) ans = 0;\n        if (ans >= M) ans = M - 1;\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;\nstatic constexpr int UNREACH = 1'000'000'000;\nstatic constexpr ll DISCONNECT_UNIT = 100'000'000LL;\n\nstruct Edge {\n    int u, v, w;\n    int cell = 0;\n    double imp = 0.0;\n};\n\nint N, M, D, K;\nint GRID = 10;\n\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj; // (to, edge id)\nvector<int> X, Y, degv;\n\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\nvector<int> samples;\nint S = 0;\nvector<vector<int>> baseDist;\nvector<int> tmpDist;\n\n// current solution state\nvector<int> dayOf;               // edge -> day [0..D-1]\nvector<int> cntDay;              // day -> count\nvector<vector<int>> incCnt;      // vertex, day -> #incident edges repaired that day\nvector<vector<int>> dayEdges;    // day -> edge list\nvector<int> posInDay;            // edge -> position in dayEdges[dayOf[edge]]\nvector<ll> dayScore;             // approximate score per day\n\nvector<int> seen;\nint seenToken = 1;\n\ninline int rnd_int(int n) {\n    return (int)(rng() % (uint32_t)n);\n}\ninline double rnd01() {\n    return (rng() + 0.5) * (1.0 / 4294967296.0);\n}\n\nvoid dijkstra_full_parent(int src, vector<int>& dist, vector<int>& parent) {\n    fill(dist.begin(), dist.end(), UNREACH);\n    fill(parent.begin(), parent.end(), -1);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                parent[to] = eid;\n                pq.push({nd, to});\n            } else if (nd == dist[to] && parent[to] != -1) {\n                // deterministic tie-break\n                if (eid < parent[to]) parent[to] = eid;\n            }\n        }\n    }\n}\n\nvoid dijkstra_ban_day(int src, int banDay, vector<int>& dist) {\n    fill(dist.begin(), dist.end(), UNREACH);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            if (dayOf[eid] == banDay) continue;\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                pq.push({nd, to});\n            }\n        }\n    }\n}\n\n// ordered pairs across different connected components after removing banDay edges.\n// 0 means connected.\nll disconnected_cross_pairs(int banDay) {\n    static vector<int> q;\n    if ((int)q.size() < N) q.resize(N);\n\n    ll sameOrdered = 0;\n    for (int st = 0; st < N; st++) {\n        if (seen[st] == seenToken) continue;\n        int head = 0, tail = 0;\n        q[tail++] = st;\n        seen[st] = seenToken;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (auto [to, eid] : adj[v]) {\n                if (dayOf[eid] == banDay) continue;\n                if (seen[to] == seenToken) continue;\n                seen[to] = seenToken;\n                q[tail++] = to;\n            }\n        }\n        sameOrdered += 1LL * sz * (sz - 1);\n    }\n\n    seenToken++;\n    if (seenToken == INT_MAX) {\n        fill(seen.begin(), seen.end(), 0);\n        seenToken = 1;\n    }\n\n    ll totalOrdered = 1LL * N * (N - 1);\n    return totalOrdered - sameOrdered;\n}\n\nll compute_day_score(int day) {\n    // Strong connectivity penalty to avoid hidden catastrophic solutions.\n    ll crossPairs = disconnected_cross_pairs(day);\n    if (crossPairs > 0) {\n        return crossPairs * DISCONNECT_UNIT;\n    }\n\n    ll sum = 0;\n    for (int si = 0; si < S; si++) {\n        dijkstra_ban_day(samples[si], day, tmpDist);\n        const auto& b = baseDist[si];\n        for (int v = 0; v < N; v++) {\n            sum += (ll)tmpDist[v] - b[v];\n        }\n    }\n    return sum;\n}\n\nll evaluate_total(vector<ll>& outDayScore) {\n    outDayScore.assign(D, 0);\n    ll tot = 0;\n    for (int d = 0; d < D; d++) {\n        outDayScore[d] = compute_day_score(d);\n        tot += outDayScore[d];\n    }\n    return tot;\n}\n\nvector<int> select_samples(int cnt) {\n    cnt = min(cnt, N);\n    vector<int> res;\n    vector<double> minD2(N, 1e100);\n    vector<char> used(N, false);\n\n    int first = 0;\n    for (int i = 1; i < N; i++) {\n        if (degv[i] > degv[first]) first = i;\n    }\n\n    for (int it = 0; it < cnt; it++) {\n        int cur = -1;\n        if (it == 0) {\n            cur = first;\n        } else {\n            double best = -1.0;\n            for (int v = 0; v < N; v++) {\n                if (used[v]) continue;\n                if (minD2[v] > best) {\n                    best = minD2[v];\n                    cur = v;\n                }\n            }\n        }\n        used[cur] = true;\n        res.push_back(cur);\n\n        for (int v = 0; v < N; v++) {\n            if (used[v]) continue;\n            double dx = (double)X[v] - X[cur];\n            double dy = (double)Y[v] - Y[cur];\n            double d2 = dx * dx + dy * dy;\n            if (d2 < minD2[v]) minD2[v] = d2;\n        }\n    }\n\n    return res;\n}\n\nvector<int> build_initial_schedule(double alpha, double beta, double gamma) {\n    vector<int> assign(M, -1);\n    vector<int> cnt(D, 0);\n    vector<vector<int>> inc(N, vector<int>(D, 0));\n    int C = GRID * GRID;\n    vector<vector<int>> cellCnt(C, vector<int>(D, 0));\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n\n    vector<double> key(M);\n    for (int e = 0; e < M; e++) {\n        key[e] = edges[e].imp + (double)(rng() & 2047) * 1e-6;\n    }\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (key[a] != key[b]) return key[a] > key[b];\n        return a < b;\n    });\n\n    double maxImp = 1e-9;\n    for (int e = 0; e < M; e++) maxImp = max(maxImp, edges[e].imp);\n\n    for (int eid : order) {\n        const Edge& E = edges[eid];\n        int u = E.u, v = E.v, c = E.cell;\n        double impf = 1.0 + E.imp / maxImp;\n\n        int bestDay = -1;\n        double bestP = 1e100;\n\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] >= K) continue;\n            if (inc[u][d] >= degv[u] - 1) continue;\n            if (inc[v][d] >= degv[v] - 1) continue;\n\n            double p = alpha * cnt[d]\n                     + beta * impf * (inc[u][d] + inc[v][d])\n                     + gamma * cellCnt[c][d];\n            if (p < bestP) {\n                bestP = p;\n                bestDay = d;\n            }\n        }\n\n        // If hard constraints block all days, relax slightly with heavy penalty.\n        if (bestDay == -1) {\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] >= K) continue;\n                double viol = 0.0;\n                if (inc[u][d] >= degv[u] - 1) viol += 1000.0;\n                if (inc[v][d] >= degv[v] - 1) viol += 1000.0;\n                double p = alpha * cnt[d]\n                         + beta * impf * (inc[u][d] + inc[v][d])\n                         + gamma * cellCnt[c][d]\n                         + viol;\n                if (p < bestP) {\n                    bestP = p;\n                    bestDay = d;\n                }\n            }\n        }\n\n        if (bestDay == -1) {\n            // very defensive fallback\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] < K) {\n                    bestDay = d;\n                    break;\n                }\n            }\n            if (bestDay == -1) bestDay = 0;\n        }\n\n        assign[eid] = bestDay;\n        cnt[bestDay]++;\n        inc[u][bestDay]++;\n        inc[v][bestDay]++;\n        cellCnt[c][bestDay]++;\n    }\n\n    return assign;\n}\n\nvoid build_state_from_assignment() {\n    cntDay.assign(D, 0);\n    incCnt.assign(N, vector<int>(D, 0));\n    dayEdges.assign(D, vector<int>());\n    posInDay.assign(M, -1);\n\n    for (int e = 0; e < M; e++) {\n        int d = dayOf[e];\n        cntDay[d]++;\n        int u = edges[e].u, v = edges[e].v;\n        incCnt[u][d]++;\n        incCnt[v][d]++;\n        posInDay[e] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(e);\n    }\n}\n\ninline void day_remove_edge(int e, int d) {\n    int p = posInDay[e];\n    int last = dayEdges[d].back();\n    dayEdges[d][p] = last;\n    posInDay[last] = p;\n    dayEdges[d].pop_back();\n}\n\ninline void day_add_edge(int e, int d) {\n    posInDay[e] = (int)dayEdges[d].size();\n    dayEdges[d].push_back(e);\n}\n\nvoid apply_move(int e, int from, int to) {\n    day_remove_edge(e, from);\n    day_add_edge(e, to);\n\n    dayOf[e] = to;\n    cntDay[from]--;\n    cntDay[to]++;\n\n    int u = edges[e].u, v = edges[e].v;\n    incCnt[u][from]--;\n    incCnt[v][from]--;\n    incCnt[u][to]++;\n    incCnt[v][to]++;\n}\n\nvoid apply_swap(int e, int f, int d1, int d2) {\n    // e: d1 -> d2, f: d2 -> d1\n    int pe = posInDay[e];\n    int pf = posInDay[f];\n\n    dayEdges[d1][pe] = f;\n    posInDay[f] = pe;\n    dayEdges[d2][pf] = e;\n    posInDay[e] = pf;\n\n    dayOf[e] = d2;\n    dayOf[f] = d1;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    incCnt[eu][d1]--;\n    incCnt[ev][d1]--;\n    incCnt[eu][d2]++;\n    incCnt[ev][d2]++;\n\n    incCnt[fu][d2]--;\n    incCnt[fv][d2]--;\n    incCnt[fu][d1]++;\n    incCnt[fv][d1]++;\n}\n\nbool can_move_edge(int e, int to) {\n    int from = dayOf[e];\n    if (from == to) return false;\n    if (cntDay[to] >= K) return false;\n    int u = edges[e].u, v = edges[e].v;\n    if (incCnt[u][to] + 1 > degv[u] - 1) return false;\n    if (incCnt[v][to] + 1 > degv[v] - 1) return false;\n    return true;\n}\n\nbool can_swap_edges(int e, int f) {\n    int d1 = dayOf[e];\n    int d2 = dayOf[f];\n    if (d1 == d2) return false;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    int vv[4] = {eu, ev, fu, fv};\n    sort(vv, vv + 4);\n    int m = (int)(unique(vv, vv + 4) - vv);\n\n    for (int i = 0; i < m; i++) {\n        int x = vv[i];\n        int nd1 = incCnt[x][d1] - (eu == x) - (ev == x) + (fu == x) + (fv == x);\n        int nd2 = incCnt[x][d2] - (fu == x) - (fv == x) + (eu == x) + (ev == x);\n        if (nd1 > degv[x] - 1) return false;\n        if (nd2 > degv[x] - 1) return false;\n    }\n    return true;\n}\n\nint day_with_max_score() {\n    int id = 0;\n    for (int d = 1; d < D; d++) {\n        if (dayScore[d] > dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_move(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (cntDay[d] >= K) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_swap(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (dayEdges[d].empty()) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    adj.assign(N, {});\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        adj[u].push_back({v, i});\n        adj[v].push_back({u, i});\n    }\n\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n    }\n\n    degv.assign(N, 0);\n    for (int v = 0; v < N; v++) degv[v] = (int)adj[v].size();\n\n    // edge cell id\n    for (int e = 0; e < M; e++) {\n        int mx = X[edges[e].u] + X[edges[e].v]; // [0,2000]\n        int my = Y[edges[e].u] + Y[edges[e].v];\n        int gx = min(GRID - 1, mx * GRID / 2001);\n        int gy = min(GRID - 1, my * GRID / 2001);\n        edges[e].cell = gx * GRID + gy;\n    }\n\n    int sampleTarget = 14;\n    if (N > 850 || M > 2500) sampleTarget = 12;\n    S = min(N, sampleTarget);\n\n    samples = select_samples(S);\n\n    baseDist.assign(S, vector<int>(N, UNREACH));\n    vector<double> imp(M, 0.0);\n\n    vector<int> dist(N), parent(N);\n    for (int si = 0; si < S; si++) {\n        int src = samples[si];\n        dijkstra_full_parent(src, dist, parent);\n        baseDist[si] = dist;\n        for (int v = 0; v < N; v++) {\n            if (v == src) continue;\n            int pe = parent[v];\n            if (pe >= 0) imp[pe] += 1.0;\n        }\n    }\n\n    for (int e = 0; e < M; e++) {\n        imp[e] += 1000.0 / edges[e].w;\n        imp[e] += 0.1 * (1.0 / degv[edges[e].u] + 1.0 / degv[edges[e].v]);\n        edges[e].imp = imp[e];\n    }\n\n    dayOf.assign(M, 0);\n    tmpDist.assign(N, UNREACH);\n    seen.assign(N, 0);\n    seenToken = 1;\n\n    vector<array<double,3>> params = {\n        {1.0, 4.0, 1.8},\n        {0.8, 5.0, 0.7},\n        {1.2, 3.2, 2.6}\n    };\n\n    vector<int> bestAssignInit;\n    vector<ll> bestDayScoreInit;\n    ll bestTotInit = (1LL << 62);\n\n    for (auto p : params) {\n        auto initAssign = build_initial_schedule(p[0], p[1], p[2]);\n        dayOf = initAssign;\n        vector<ll> ds;\n        ll tot = evaluate_total(ds);\n        if (tot < bestTotInit) {\n            bestTotInit = tot;\n            bestAssignInit = move(initAssign);\n            bestDayScoreInit = move(ds);\n        }\n    }\n\n    dayOf = bestAssignInit;\n    dayScore = bestDayScoreInit;\n    ll currentTotal = bestTotInit;\n\n    build_state_from_assignment();\n\n    vector<int> bestAssign = dayOf;\n    ll bestTotal = currentTotal;\n\n    const double TIME_LIMIT = 5.60;\n    const double T0 = 5e6;\n    const double T1 = 1e3;\n    const double logT0 = log(T0);\n    const double logT1 = log(T1);\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= TIME_LIMIT) break;\n        }\n        iter++;\n\n        bool generated = false;\n        bool isMove = false;\n        int e = -1, f = -1, toDay = -1;\n\n        for (int tr = 0; tr < 25 && !generated; tr++) {\n            int mode = rnd_int(100);\n\n            if (mode < 35) {\n                // targeted move: bad day -> good day\n                int d1 = day_with_max_score();\n                if (dayEdges[d1].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                int d2 = day_with_min_score_move(d1);\n                if (d2 < 0) continue;\n                if (!can_move_edge(e, d2)) continue;\n                isMove = true;\n                toDay = d2;\n                generated = true;\n\n            } else if (mode < 65) {\n                // targeted swap: bad day <-> good day\n                int d1 = day_with_max_score();\n                int d2 = day_with_min_score_swap(d1);\n                if (d2 < 0) continue;\n                if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                f = dayEdges[d2][rnd_int((int)dayEdges[d2].size())];\n                if (!can_swap_edges(e, f)) continue;\n                isMove = false;\n                generated = true;\n\n            } else {\n                // random\n                e = rnd_int(M);\n                if (rnd_int(2) == 0) {\n                    int d2 = rnd_int(D);\n                    if (!can_move_edge(e, d2)) continue;\n                    isMove = true;\n                    toDay = d2;\n                    generated = true;\n                } else {\n                    f = rnd_int(M);\n                    if (e == f) continue;\n                    if (!can_swap_edges(e, f)) continue;\n                    isMove = false;\n                    generated = true;\n                }\n            }\n        }\n\n        if (!generated) continue;\n\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        double temp = exp(logT0 + (logT1 - logT0) * progress);\n\n        if (isMove) {\n            int from = dayOf[e];\n            int to = toDay;\n\n            ll oldA = dayScore[from];\n            ll oldB = dayScore[to];\n\n            apply_move(e, from, to);\n\n            ll newA = compute_day_score(from);\n            ll newB = compute_day_score(to);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[from] = newA;\n                dayScore[to] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_move(e, to, from); // revert\n            }\n\n        } else {\n            int d1 = dayOf[e];\n            int d2 = dayOf[f];\n\n            ll oldA = dayScore[d1];\n            ll oldB = dayScore[d2];\n\n            apply_swap(e, f, d1, d2);\n\n            ll newA = compute_day_score(d1);\n            ll newB = compute_day_score(d2);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[d1] = newA;\n                dayScore[d2] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_swap(e, f, d2, d1); // revert\n            }\n        }\n    }\n\n    dayOf = bestAssign;\n\n    // defensive validity check\n    bool ok = true;\n    vector<int> checkCnt(D, 0);\n    for (int e = 0; e < M; e++) {\n        if (dayOf[e] < 0 || dayOf[e] >= D) ok = false;\n        else checkCnt[dayOf[e]]++;\n    }\n    for (int d = 0; d < D; d++) if (checkCnt[d] > K) ok = false;\n\n    if (!ok) {\n        // guaranteed feasible fallback\n        for (int e = 0; e < M; e++) dayOf[e] = e % D;\n    }\n\n    for (int e = 0; e < M; e++) {\n        if (e) cout << ' ';\n        cout << (dayOf[e] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seg { int s, stride; };\nstruct Occupancy {\n    vector<char> occ;\n    int vol = 0;\n};\nstruct Solution {\n    long double score = 1e100L;\n    int n = 0;\n    vector<int> b1, b2;\n};\nstruct LayerData {\n    vector<int> X, Y;      // active x/y indices at this z\n    vector<int> allowed;   // all allowed (x*D+y) pairs\n    int base = 0;          // minimal #voxels at this z = max(|X|,|Y|)\n    int cap = 0;           // extra capacity = |X|*|Y|-base\n};\n\nint D, N;\nint SX, SY, SZ;\n\narray<vector<string>, 2> F, Rv;\narray<vector<LayerData>, 2> LAY;\narray<int, 2> VminObj, VmaxObj;\n\nvector<vector<Seg>> allSegs;      // allSegs[L], L>=3\nvector<vector<int>> neighbors;    // 6-neighbors\nvector<int> parityCell;\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\nvoid precompute() {\n    SX = D * D;\n    SY = D;\n    SZ = 1;\n    N = D * D * D;\n\n    for (int obj = 0; obj < 2; obj++) {\n        LAY[obj].assign(D, LayerData{});\n        int vmin = 0, vmax = 0;\n        for (int z = 0; z < D; z++) {\n            LayerData ld;\n            for (int x = 0; x < D; x++) if (F[obj][z][x] == '1') ld.X.push_back(x);\n            for (int y = 0; y < D; y++) if (Rv[obj][z][y] == '1') ld.Y.push_back(y);\n\n            int a = (int)ld.X.size();\n            int b = (int)ld.Y.size();\n            ld.base = max(a, b);\n            ld.cap = a * b - ld.base;\n            ld.allowed.reserve(a * b);\n            for (int x : ld.X) for (int y : ld.Y) ld.allowed.push_back(x * D + y);\n\n            vmin += ld.base;\n            vmax += a * b;\n            LAY[obj][z] = move(ld);\n        }\n        VminObj[obj] = vmin;\n        VmaxObj[obj] = vmax;\n    }\n\n    parityCell.assign(N, 0);\n    neighbors.assign(N, {});\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        parityCell[id] = (x + y + z) & 1;\n        auto &nb = neighbors[id];\n        if (x > 0) nb.push_back(id - SX);\n        if (x + 1 < D) nb.push_back(id + SX);\n        if (y > 0) nb.push_back(id - SY);\n        if (y + 1 < D) nb.push_back(id + SY);\n        if (z > 0) nb.push_back(id - SZ);\n        if (z + 1 < D) nb.push_back(id + SZ);\n    }\n\n    allSegs.assign(D + 1, {});\n    for (int L = 3; L <= D; L++) {\n        auto &v = allSegs[L];\n        v.reserve(3 * (D - L + 1) * D * D);\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int s = idx3(x, y, z);\n            if (x + L <= D) v.push_back({s, SX});\n            if (y + L <= D) v.push_back({s, SY});\n            if (z + L <= D) v.push_back({s, SZ});\n        }\n    }\n}\n\n// Allocate per-layer extras add[z] so that:\n// sum(base[z] + add[z]) = target (clamped into [Vmin, Vmax]), 0<=add[z]<=cap[z].\nvector<int> allocate_add(int obj, int target, int mode, mt19937_64& rng) {\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    target = max(lo, min(hi, target));\n\n    int need = target - lo;\n    vector<int> add(D, 0);\n    if (need <= 0) return add;\n\n    int totalCap = hi - lo;\n    if (totalCap <= 0) return add;\n\n    // mode 1: fully random exact allocation via slots\n    if (mode == 1) {\n        vector<int> slots;\n        slots.reserve(totalCap);\n        for (int z = 0; z < D; z++) {\n            int cap = LAY[obj][z].cap;\n            for (int t = 0; t < cap; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < need; i++) add[slots[i]]++;\n        return add;\n    }\n\n    // mode 0: proportional + randomized tie-breaking\n    vector<long double> frac(D, -1.0L);\n    int used = 0;\n    for (int z = 0; z < D; z++) {\n        int cap = LAY[obj][z].cap;\n        if (cap == 0) continue;\n        long double ex = (long double)need * (long double)cap / (long double)totalCap;\n        int a = (int)floor(ex);\n        if (a > cap) a = cap;\n        add[z] = a;\n        used += a;\n        frac[z] = ex - a + (long double)(rng() % 1000) * 1e-12L;\n    }\n\n    int rem = need - used;\n    vector<int> ord(D);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int p, int q) {\n        return frac[p] > frac[q];\n    });\n\n    while (rem > 0) {\n        bool any = false;\n        for (int z : ord) {\n            if (rem == 0) break;\n            int cap = LAY[obj][z].cap;\n            if (add[z] < cap) {\n                add[z]++;\n                rem--;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n\n    if (rem > 0) {\n        vector<int> slots;\n        for (int z = 0; z < D; z++) {\n            int cap = LAY[obj][z].cap;\n            for (int t = add[z]; t < cap; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < rem && i < (int)slots.size(); i++) add[slots[i]]++;\n    }\n\n    return add;\n}\n\n// style:\n// 0 = grouped base with previous-layer continuity + greedy extras\n// 1 = randomized grouped base + random extras\n// 2 = random surjection base + greedy extras\nOccupancy build_occ_target(int obj, int target, int style, mt19937_64& rng) {\n    Occupancy oc;\n    oc.occ.assign(N, 0);\n    oc.vol = 0;\n\n    int allocMode = (style == 1 ? 1 : 0);\n    vector<int> addz = allocate_add(obj, target, allocMode, rng);\n\n    vector<char> prevXY(D * D, 0);\n\n    for (int z = 0; z < D; z++) {\n        const auto &ld = LAY[obj][z];\n        int a = (int)ld.X.size();\n        int b = (int)ld.Y.size();\n\n        int m = ld.base + addz[z];\n        vector<char> usedXY(D * D, 0);\n\n        auto put_edge = [&](int x, int y) {\n            int idxy = x * D + y;\n            if (usedXY[idxy]) return;\n            usedXY[idxy] = 1;\n            int id = idx3(x, y, z);\n            if (!oc.occ[id]) {\n                oc.occ[id] = 1;\n                oc.vol++;\n            }\n        };\n\n        // --- build minimal cover (base) ---\n        if (style == 2) {\n            // random surjection\n            if (a >= b) {\n                vector<int> Xv = ld.X;\n                shuffle(Xv.begin(), Xv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(a);\n                for (int y : ld.Y) pool.push_back(y);\n                for (int t = 0; t < a - b; t++) pool.push_back(ld.Y[(int)(rng() % b)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < a; j++) put_edge(Xv[j], pool[j]);\n            } else {\n                vector<int> Yv = ld.Y;\n                shuffle(Yv.begin(), Yv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(b);\n                for (int x : ld.X) pool.push_back(x);\n                for (int t = 0; t < b - a; t++) pool.push_back(ld.X[(int)(rng() % a)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < b; j++) put_edge(pool[j], Yv[j]);\n            }\n        } else {\n            // grouped mapping\n            if (a >= b) {\n                vector<int> Xv = ld.X;\n                vector<int> Yv = ld.Y;\n                if (style == 1) {\n                    if (rng() & 1ULL) reverse(Xv.begin(), Xv.end());\n                    if (rng() & 1ULL) reverse(Yv.begin(), Yv.end());\n                }\n\n                int shift = 0;\n                if (style == 0) {\n                    int best = -1;\n                    vector<int> bestShifts;\n                    for (int sh = 0; sh < b; sh++) {\n                        int mat = 0;\n                        for (int j = 0; j < a; j++) {\n                            int g = (int)((long long)j * b / a);\n                            int y = Yv[(g + sh) % b];\n                            int x = Xv[j];\n                            if (prevXY[x * D + y]) mat++;\n                        }\n                        if (mat > best) {\n                            best = mat;\n                            bestShifts.clear();\n                            bestShifts.push_back(sh);\n                        } else if (mat == best) {\n                            bestShifts.push_back(sh);\n                        }\n                    }\n                    shift = bestShifts[(size_t)(rng() % bestShifts.size())];\n                } else {\n                    shift = (int)(rng() % b);\n                }\n\n                for (int j = 0; j < a; j++) {\n                    int g = (int)((long long)j * b / a);\n                    int x = Xv[j];\n                    int y = Yv[(g + shift) % b];\n                    put_edge(x, y);\n                }\n            } else {\n                vector<int> Xv = ld.X;\n                vector<int> Yv = ld.Y;\n                if (style == 1) {\n                    if (rng() & 1ULL) reverse(Xv.begin(), Xv.end());\n                    if (rng() & 1ULL) reverse(Yv.begin(), Yv.end());\n                }\n\n                int shift = 0;\n                if (style == 0) {\n                    int best = -1;\n                    vector<int> bestShifts;\n                    for (int sh = 0; sh < a; sh++) {\n                        int mat = 0;\n                        for (int j = 0; j < b; j++) {\n                            int g = (int)((long long)j * a / b);\n                            int x = Xv[(g + sh) % a];\n                            int y = Yv[j];\n                            if (prevXY[x * D + y]) mat++;\n                        }\n                        if (mat > best) {\n                            best = mat;\n                            bestShifts.clear();\n                            bestShifts.push_back(sh);\n                        } else if (mat == best) {\n                            bestShifts.push_back(sh);\n                        }\n                    }\n                    shift = bestShifts[(size_t)(rng() % bestShifts.size())];\n                } else {\n                    shift = (int)(rng() % a);\n                }\n\n                for (int j = 0; j < b; j++) {\n                    int g = (int)((long long)j * a / b);\n                    int x = Xv[(g + shift) % a];\n                    int y = Yv[j];\n                    put_edge(x, y);\n                }\n            }\n        }\n\n        int cur = 0;\n        for (int idxy : ld.allowed) if (usedXY[idxy]) cur++;\n        int extra = m - cur;\n\n        // --- add extras ---\n        if (extra > 0) {\n            vector<int> cand;\n            cand.reserve(ld.allowed.size());\n            for (int idxy : ld.allowed) {\n                if (!usedXY[idxy]) cand.push_back(idxy);\n            }\n\n            if (extra >= (int)cand.size()) {\n                for (int idxy : cand) put_edge(idxy / D, idxy % D);\n            } else if (style == 1) {\n                shuffle(cand.begin(), cand.end(), rng);\n                for (int t = 0; t < extra; t++) {\n                    int idxy = cand[t];\n                    put_edge(idxy / D, idxy % D);\n                }\n            } else {\n                int wPrev = (style == 0 ? 5 : 3);\n                for (int t = 0; t < extra; t++) {\n                    int bestId = -1;\n                    int bestVal = -1;\n\n                    for (int idxy : cand) {\n                        if (usedXY[idxy]) continue;\n                        int x = idxy / D;\n                        int y = idxy % D;\n\n                        int sc = 0;\n                        if (prevXY[idxy]) sc += wPrev;\n                        if (x > 0   && usedXY[(x - 1) * D + y]) sc++;\n                        if (x + 1 < D && usedXY[(x + 1) * D + y]) sc++;\n                        if (y > 0   && usedXY[x * D + (y - 1)]) sc++;\n                        if (y + 1 < D && usedXY[x * D + (y + 1)]) sc++;\n\n                        int val = sc * 100 + (int)(rng() % 100);\n                        if (val > bestVal) {\n                            bestVal = val;\n                            bestId = idxy;\n                        }\n                    }\n\n                    if (bestId == -1) break;\n                    put_edge(bestId / D, bestId % D);\n                }\n            }\n        }\n\n        prevXY.swap(usedXY);\n    }\n\n    return oc;\n}\n\nvector<Occupancy> generate_candidates(int obj, mt19937_64& rng) {\n    vector<Occupancy> cands;\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    int span = hi - lo;\n\n    for (int q = 0; q <= 10; q++) {\n        int T = lo + (long long)span * q / 10;\n        for (int style = 0; style < 3; style++) {\n            cands.push_back(build_occ_target(obj, T, style, rng));\n        }\n    }\n\n    int extraCnt = 16;\n    for (int t = 0; t < extraCnt; t++) {\n        int T = lo + (int)(rng() % (span + 1));\n        int style = (int)(rng() % 3);\n        cands.push_back(build_occ_target(obj, T, style, rng));\n    }\n\n    return cands;\n}\n\nvector<Seg> pack_segments(const vector<char>& freeCells, int L, mt19937_64& rng) {\n    const auto &segs = allSegs[L];\n    vector<int> cand;\n    cand.reserve(segs.size());\n\n    for (int i = 0; i < (int)segs.size(); i++) {\n        const auto &sg = segs[i];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!freeCells[p]) { ok = false; break; }\n        }\n        if (ok) cand.push_back(i);\n    }\n\n    shuffle(cand.begin(), cand.end(), rng);\n\n    vector<char> tmp = freeCells;\n    vector<Seg> selected;\n    selected.reserve(cand.size() / max(1, L) + 1);\n\n    for (int id : cand) {\n        const auto &sg = segs[id];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!tmp[p]) { ok = false; break; }\n        }\n        if (!ok) continue;\n\n        selected.push_back(sg);\n        p = sg.s;\n        for (int t = 0; t < L; t++, p += sg.stride) tmp[p] = 0;\n    }\n\n    return selected;\n}\n\nvector<pair<int,int>> max_domino_matching(const vector<char>& freeCells) {\n    vector<int> lid(N, -1), rid(N, -1);\n    vector<int> leftCells, rightCells;\n    leftCells.reserve(N);\n    rightCells.reserve(N);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i]) continue;\n        if (parityCell[i] == 0) {\n            lid[i] = (int)leftCells.size();\n            leftCells.push_back(i);\n        } else {\n            rid[i] = (int)rightCells.size();\n            rightCells.push_back(i);\n        }\n    }\n\n    int Ls = (int)leftCells.size();\n    int Rs = (int)rightCells.size();\n\n    vector<vector<int>> g(Ls);\n    for (int u = 0; u < Ls; u++) {\n        int cell = leftCells[u];\n        auto &adj = g[u];\n        for (int nb : neighbors[cell]) {\n            if (!freeCells[nb]) continue;\n            int v = rid[nb];\n            if (v != -1) adj.push_back(v);\n        }\n    }\n\n    vector<int> dist(Ls), matchL(Ls, -1), matchR(Rs, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(dist.begin(), dist.end(), -1);\n        bool found = false;\n\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                int u2 = matchR[v];\n                if (u2 == -1) {\n                    found = true;\n                } else if (dist[u2] == -1) {\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n            }\n        }\n        return found;\n    };\n\n    auto dfs = [&](auto&& self, int u) -> bool {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && self(self, u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) dfs(dfs, u);\n        }\n    }\n\n    vector<pair<int,int>> pairs;\n    pairs.reserve(Ls);\n    for (int u = 0; u < Ls; u++) {\n        if (matchL[u] != -1) {\n            pairs.push_back({leftCells[u], rightCells[matchL[u]]});\n        }\n    }\n    return pairs;\n}\n\nSolution make_solution(const Occupancy& o1, const Occupancy& o2, mt19937_64& rng) {\n    vector<char> free1 = o1.occ;\n    vector<char> free2 = o2.occ;\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int id = 0;\n    int sharedVol = 0;\n    long double sharedTerm = 0.0L;\n\n    for (int L = D; L >= 3; L--) {\n        auto segs1 = pack_segments(free1, L, rng);\n        auto segs2 = pack_segments(free2, L, rng);\n\n        int s = min((int)segs1.size(), (int)segs2.size());\n        if (s == 0) continue;\n\n        if ((int)segs1.size() > s) {\n            shuffle(segs1.begin(), segs1.end(), rng);\n            segs1.resize(s);\n        }\n        if ((int)segs2.size() > s) {\n            shuffle(segs2.begin(), segs2.end(), rng);\n            segs2.resize(s);\n        }\n\n        for (int i = 0; i < s; i++) {\n            ++id;\n            int p = segs1[i].s;\n            for (int t = 0; t < L; t++, p += segs1[i].stride) {\n                b1[p] = id;\n                free1[p] = 0;\n            }\n\n            p = segs2[i].s;\n            for (int t = 0; t < L; t++, p += segs2[i].stride) {\n                b2[p] = id;\n                free2[p] = 0;\n            }\n\n            sharedVol += L;\n            sharedTerm += 1.0L / (long double)L;\n        }\n    }\n\n    auto dom1 = max_domino_matching(free1);\n    auto dom2 = max_domino_matching(free2);\n    int sd = min((int)dom1.size(), (int)dom2.size());\n\n    if (sd > 0) {\n        if ((int)dom1.size() > sd) {\n            shuffle(dom1.begin(), dom1.end(), rng);\n            dom1.resize(sd);\n        }\n        if ((int)dom2.size() > sd) {\n            shuffle(dom2.begin(), dom2.end(), rng);\n            dom2.resize(sd);\n        }\n\n        for (int i = 0; i < sd; i++) {\n            ++id;\n            auto [a, b] = dom1[i];\n            b1[a] = id; b1[b] = id;\n            free1[a] = 0; free1[b] = 0;\n\n            auto [c, d] = dom2[i];\n            b2[c] = id; b2[d] = id;\n            free2[c] = 0; free2[d] = 0;\n\n            sharedVol += 2;\n            sharedTerm += 0.5L;\n        }\n    }\n\n    vector<int> rem1, rem2;\n    rem1.reserve(o1.vol - sharedVol);\n    rem2.reserve(o2.vol - sharedVol);\n\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) rem1.push_back(i);\n        if (free2[i]) rem2.push_back(i);\n    }\n\n    shuffle(rem1.begin(), rem1.end(), rng);\n    shuffle(rem2.begin(), rem2.end(), rng);\n\n    int sm = min((int)rem1.size(), (int)rem2.size());\n    for (int i = 0; i < sm; i++) {\n        ++id;\n        b1[rem1[i]] = id;\n        b2[rem2[i]] = id;\n\n        sharedVol += 1;\n        sharedTerm += 1.0L;\n    }\n    for (int i = sm; i < (int)rem1.size(); i++) {\n        ++id;\n        b1[rem1[i]] = id;\n    }\n    for (int i = sm; i < (int)rem2.size(); i++) {\n        ++id;\n        b2[rem2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = (long double)(o1.vol + o2.vol - 2 * sharedVol) + sharedTerm;\n    return sol;\n}\n\nbool check_silhouette_one(const vector<int>& b, int obj) {\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) {\n            bool seen = false;\n            for (int y = 0; y < D; y++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (F[obj][z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; y++) {\n            bool seen = false;\n            for (int x = 0; x < D; x++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (Rv[obj][z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nbool check_silhouette(const Solution& sol) {\n    if ((int)sol.b1.size() != N || (int)sol.b2.size() != N) return false;\n    return check_silhouette_one(sol.b1, 0) && check_silhouette_one(sol.b2, 1);\n}\n\nSolution fallback_simple() {\n    vector<int> b1(N, 0), b2(N, 0);\n    vector<int> c1, c2;\n    c1.reserve(N);\n    c2.reserve(N);\n\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (F[0][z][x] == '1' && Rv[0][z][y] == '1') c1.push_back(idx3(x, y, z));\n        if (F[1][z][x] == '1' && Rv[1][z][y] == '1') c2.push_back(idx3(x, y, z));\n    }\n\n    int id = 0;\n    int m = min((int)c1.size(), (int)c2.size());\n    for (int i = 0; i < m; i++) {\n        ++id;\n        b1[c1[i]] = id;\n        b2[c2[i]] = id;\n    }\n    for (int i = m; i < (int)c1.size(); i++) {\n        ++id;\n        b1[c1[i]] = id;\n    }\n    for (int i = m; i < (int)c2.size(); i++) {\n        ++id;\n        b2[c2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = 1e99L;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        Rv[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> Rv[i][z];\n    }\n\n    precompute();\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count()\n        ^ (uint64_t)D * 1000003ULL\n    );\n\n    const double TL = 5.6;\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    int overlapL = max(VminObj[0], VminObj[1]);\n    int overlapU = min(VmaxObj[0], VmaxObj[1]);\n    bool hasOverlap = (overlapL <= overlapU);\n\n    int globalL = min(VminObj[0], VminObj[1]);\n    int globalU = max(VmaxObj[0], VmaxObj[1]);\n\n    Solution best;\n\n    // Initial feasible solution\n    {\n        int t1, t2;\n        if (hasOverlap) {\n            t1 = t2 = overlapL;\n        } else {\n            t1 = (VminObj[0] + VmaxObj[0]) / 2;\n            t2 = (VminObj[1] + VmaxObj[1]) / 2;\n        }\n        Occupancy o1 = build_occ_target(0, t1, 0, rng);\n        Occupancy o2 = build_occ_target(1, t2, 0, rng);\n        best = make_solution(o1, o2, rng);\n    }\n\n    const long double INF = 1e100L;\n\n    auto try_pair = [&](const Occupancy& o1, const Occupancy& o2, int reps) -> long double {\n        int mn = min(o1.vol, o2.vol);\n        long double lb = fabsl((long double)o1.vol - (long double)o2.vol) + 1.0L / (long double)mn;\n        if (lb + 1e-12L >= best.score) return INF;\n\n        long double localBest = INF;\n        for (int t = 0; t < reps; t++) {\n            if (elapsed() >= TL) break;\n            Solution cur = make_solution(o1, o2, rng);\n            localBest = min(localBest, cur.score);\n            if (cur.score < best.score) best = move(cur);\n        }\n        return localBest;\n    };\n\n    // Candidate pool + pair screening\n    vector<Occupancy> cand1 = generate_candidates(0, rng);\n    vector<Occupancy> cand2 = generate_candidates(1, rng);\n\n    struct PairCand {\n        int i, j;\n        int diff;\n        uint64_t tie;\n    };\n\n    vector<PairCand> plist;\n    plist.reserve((int)cand1.size() * (int)cand2.size());\n    for (int i = 0; i < (int)cand1.size(); i++) {\n        for (int j = 0; j < (int)cand2.size(); j++) {\n            int diff = abs(cand1[i].vol - cand2[j].vol);\n            plist.push_back({i, j, diff, rng()});\n        }\n    }\n    sort(plist.begin(), plist.end(), [](const PairCand& a, const PairCand& b) {\n        if (a.diff != b.diff) return a.diff < b.diff;\n        return a.tie < b.tie;\n    });\n\n    vector<tuple<long double,int,int>> tried; // score, i, j\n    int maxInitPairs = min((int)plist.size(), 320);\n    for (int p = 0; p < maxInitPairs && elapsed() < TL * 0.70; p++) {\n        const auto &pc = plist[p];\n        int reps = (p < 50 ? 2 : 1);\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], reps);\n        if (sc < INF / 10) tried.emplace_back(sc, pc.i, pc.j);\n    }\n\n    if (tried.empty() && !plist.empty() && elapsed() < TL) {\n        const auto &pc = plist[0];\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], 1);\n        if (sc < INF / 10) tried.emplace_back(sc, pc.i, pc.j);\n    }\n\n    sort(tried.begin(), tried.end(), [](const auto& A, const auto& B) {\n        return get<0>(A) < get<0>(B);\n    });\n\n    vector<pair<int,int>> pool;\n    int poolSize = min((int)tried.size(), 40);\n    for (int i = 0; i < poolSize; i++) {\n        pool.push_back({get<1>(tried[i]), get<2>(tried[i])});\n    }\n\n    // Refinement loop\n    int it = 0;\n    while (elapsed() < TL) {\n        if (!pool.empty() && (rng() % 100) < 75) {\n            auto [i, j] = pool[it % pool.size()];\n            it++;\n            try_pair(cand1[i], cand2[j], 1);\n        } else {\n            int style1 = (int)(rng() % 3);\n            int style2 = (int)(rng() % 3);\n\n            int T1, T2;\n            if (hasOverlap && (rng() % 100) < 80) {\n                long double u = (long double)(rng() % 1000000) / 1000000.0L;\n                if ((rng() % 100) < 60) u = u * u; // bias to lower volume side\n                int T = overlapL + (int)llround((overlapU - overlapL) * u);\n                T1 = T2 = T;\n            } else if ((rng() % 100) < 50) {\n                int T = globalL + (int)(rng() % (globalU - globalL + 1));\n                T1 = T2 = T;\n            } else {\n                T1 = VminObj[0] + (int)(rng() % (VmaxObj[0] - VminObj[0] + 1));\n                T2 = VminObj[1] + (int)(rng() % (VmaxObj[1] - VminObj[1] + 1));\n            }\n\n            Occupancy o1 = build_occ_target(0, T1, style1, rng);\n            Occupancy o2 = build_occ_target(1, T2, style2, rng);\n            try_pair(o1, o2, 1);\n        }\n    }\n\n    if (best.n == 0 || !check_silhouette(best)) {\n        best = fallback_simple();\n    }\n\n    cout << best.n << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b2[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr long long INF = (1LL << 62);\n    static constexpr int MAXN = 105;\n    static constexpr int MAXM = 305;\n\n    int N, M, K;\n\n    struct Edge {\n        int u, v, w;\n    };\n\n    vector<int> x, y;\n    vector<Edge> edges;\n    vector<int> a, b;\n\n    vector<vector<pair<int,int>>> g;   // (to, edge_id)\n    vector<vector<int>> incident;      // incident edge ids\n    vector<int> edgeOrder;             // edges sorted by weight\n\n    // station-resident distances (ceil Euclid)\n    vector<vector<uint16_t>> distSR;   // [N][K]\n    // candidates within 5000 for each resident, sorted by distance asc\n    vector<vector<pair<uint16_t,int>>> cand; // [K] = (dist, station)\n\n    // APSP on station graph\n    vector<vector<long long>> spDist;  // [N][N]\n    vector<vector<int>> prevNode;      // [src][v]\n    vector<vector<int>> prevEdge;      // [src][v]\n\n    mt19937 rng{712367821};\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 int ceilDist(int x1, int y1, int x2, int y2) {\n        long long dx = 1LL * x1 - x2;\n        long long dy = 1LL * y1 - y2;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)std::sqrt((double)sq);\n        while (1LL * d * d < sq) ++d;\n        while (d > 0 && 1LL * (d - 1) * (d - 1) >= sq) --d;\n        return d;\n    }\n\n    void readInput() {\n        cin >> N >> M >> K;\n        x.resize(N); y.resize(N);\n        for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(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            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        }\n\n        a.resize(K); b.resize(K);\n        for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n        edgeOrder.resize(M);\n        iota(edgeOrder.begin(), edgeOrder.end(), 0);\n        sort(edgeOrder.begin(), edgeOrder.end(),\n             [&](int e1, int e2){ return edges[e1].w < edges[e2].w; });\n    }\n\n    void precomputeDistances() {\n        distSR.assign(N, vector<uint16_t>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                int d = ceilDist(x[i], y[i], a[k], b[k]);\n                if (d > 65535) d = 65535;\n                distSR[i][k] = (uint16_t)d;\n            }\n        }\n\n        cand.assign(K, {});\n        for (int k = 0; k < K; k++) {\n            auto &v = cand[k];\n            v.reserve(N);\n            for (int i = 0; i < N; i++) {\n                int d = distSR[i][k];\n                if (d <= 5000) v.push_back({(uint16_t)d, i});\n            }\n            sort(v.begin(), v.end(), [](auto &l, auto &r){\n                if (l.first != r.first) return l.first < r.first;\n                return l.second < r.second;\n            });\n            // safety (generator guarantee should avoid this)\n            if (v.empty()) {\n                int bestI = 0, bestD = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    int d = distSR[i][k];\n                    if (d < bestD) bestD = d, bestI = i;\n                }\n                v.push_back({(uint16_t)bestD, bestI});\n            }\n        }\n    }\n\n    void precomputeShortestPaths() {\n        spDist.assign(N, vector<long long>(N, INF));\n        prevNode.assign(N, vector<int>(N, -1));\n        prevEdge.assign(N, vector<int>(N, -1));\n\n        for (int s = 0; s < N; s++) {\n            vector<long long> d(N, INF);\n            priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n            d[s] = 0;\n            prevNode[s][s] = s;\n            prevEdge[s][s] = -1;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n                if (cd != d[v]) continue;\n                for (auto [to, eid] : g[v]) {\n                    long long nd = cd + edges[eid].w;\n                    if (nd < d[to]) {\n                        d[to] = nd;\n                        prevNode[s][to] = v;\n                        prevEdge[s][to] = eid;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            spDist[s] = std::move(d);\n        }\n    }\n\n    bool buildPNearest(const vector<char>& active, int P[]) {\n        for (int i = 0; i < N; i++) P[i] = 0;\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            int d = 0;\n            for (auto &pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return false;\n            if (d > P[chosen]) P[chosen] = d;\n        }\n        return true;\n    }\n\n    bool checkCoverageArray(const int P[]) {\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                if (P[st] >= d) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    }\n\n    void shrinkPArray(int P[]) {\n        vector<int> cnt(K, 0);\n\n        for (int i = 0; i < N; i++) {\n            int pi = P[i];\n            if (pi <= 0) continue;\n            for (int k = 0; k < K; k++) {\n                if (distSR[i][k] <= pi) cnt[k]++;\n            }\n        }\n\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int i = 0; i < N; i++) {\n                int old = P[i];\n                if (old <= 0) continue;\n\n                int req = 0;\n                for (int k = 0; k < K; k++) {\n                    int d = distSR[i][k];\n                    if (d <= old && cnt[k] == 1) {\n                        if (d > req) req = d;\n                    }\n                }\n\n                if (req < old) {\n                    for (int k = 0; k < K; k++) {\n                        int d = distSR[i][k];\n                        if (d <= old && d > req) cnt[k]--;\n                    }\n                    P[i] = req;\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    long long steinerKMB(const int terminals[], int t, vector<char>* outB) {\n        if (outB) outB->assign(M, 0);\n        if (t <= 1) return 0;\n\n        long long minD[MAXN];\n        int parent[MAXN];\n        bool used[MAXN];\n        for (int i = 0; i < t; i++) {\n            minD[i] = INF;\n            parent[i] = -1;\n            used[i] = false;\n        }\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 (!used[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            if (v == -1) return INF;\n            used[v] = true;\n\n            int tv = terminals[v];\n            for (int j = 0; j < t; j++) {\n                if (used[j]) continue;\n                long long nd = spDist[tv][terminals[j]];\n                if (nd < minD[j]) {\n                    minD[j] = nd;\n                    parent[j] = v;\n                }\n            }\n        }\n\n        char marked[MAXM], alive[MAXM];\n        for (int i = 0; i < M; i++) marked[i] = alive[i] = 0;\n\n        // expand MST edges in metric closure to original graph paths\n        for (int i = 1; i < t; i++) {\n            int s = terminals[parent[i]];\n            int cur = terminals[i];\n            while (cur != s) {\n                int eid = prevEdge[s][cur];\n                if (eid < 0) return INF;\n                marked[eid] = 1;\n                cur = prevNode[s][cur];\n            }\n        }\n\n        // MST on the induced subgraph\n        DSU dsu(N);\n        long long cost = 0;\n        for (int eid : edgeOrder) {\n            if (!marked[eid]) continue;\n            auto &e = edges[eid];\n            if (dsu.merge(e.u, e.v)) {\n                alive[eid] = 1;\n                cost += e.w;\n            }\n        }\n\n        // prune non-terminal leaves\n        int deg[MAXN];\n        char isTerm[MAXN];\n        for (int i = 0; i < N; i++) {\n            deg[i] = 0;\n            isTerm[i] = 0;\n        }\n        for (int i = 0; i < t; i++) isTerm[terminals[i]] = 1;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        if (outB) {\n            outB->assign(M, 0);\n            for (int eid = 0; eid < M; eid++) {\n                if (alive[eid]) (*outB)[eid] = 1;\n            }\n        }\n        return cost;\n    }\n\n    long long pruneAlive(vector<char>& alive, const vector<int>& terminals) {\n        vector<int> deg(N, 0);\n        vector<char> isTerm(N, 0);\n        for (int v : terminals) isTerm[v] = 1;\n\n        long long cost = 0;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            cost += edges[eid].w;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        return cost;\n    }\n\n    long long steinerRootUnion(const vector<int>& terminals, vector<char>& outB) {\n        outB.assign(M, 0);\n        for (int t : terminals) {\n            if (t == 0) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevEdge[0][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[0][cur];\n            }\n        }\n        return pruneAlive(outB, terminals);\n    }\n\n    long long steinerSPH(const vector<int>& terminals, vector<char>& outB) {\n        outB.assign(M, 0);\n        if (terminals.size() <= 1) return 0;\n\n        vector<char> inTree(N, 0);\n        inTree[0] = 1;\n\n        while (true) {\n            int remain = 0;\n            for (int t : terminals) if (!inTree[t]) remain++;\n            if (remain == 0) break;\n\n            long long bestD = INF;\n            int bestSrc = -1, bestTerm = -1;\n\n            for (int t : terminals) {\n                if (inTree[t]) continue;\n                for (int v = 0; v < N; v++) {\n                    if (!inTree[v]) continue;\n                    long long d = spDist[v][t];\n                    if (d < bestD) {\n                        bestD = d;\n                        bestSrc = v;\n                        bestTerm = t;\n                    }\n                }\n            }\n\n            if (bestSrc < 0) return INF;\n\n            int cur = bestTerm;\n            inTree[cur] = 1;\n            while (cur != bestSrc) {\n                int eid = prevEdge[bestSrc][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[bestSrc][cur];\n                inTree[cur] = 1;\n            }\n        }\n\n        return pruneAlive(outB, terminals);\n    }\n\n    long long steinerBestFinal(const int terminals[], int t, vector<char>& outB) {\n        outB.assign(M, 0);\n        if (t <= 1) return 0;\n\n        vector<char> b1;\n        long long c1 = steinerKMB(terminals, t, &b1);\n\n        vector<int> tv(terminals, terminals + t);\n\n        vector<char> b2;\n        long long c2 = steinerRootUnion(tv, b2);\n\n        vector<char> b3;\n        long long c3 = steinerSPH(tv, b3);\n\n        long long best = c1;\n        outB = b1;\n        if (c2 < best) {\n            best = c2;\n            outB = b2;\n        }\n        if (c3 < best) {\n            best = c3;\n            outB = b3;\n        }\n        return best;\n    }\n\n    long long evaluateFast(const vector<char>& active) {\n        int P[MAXN];\n        if (!buildPNearest(active, P)) return INF;\n\n        long long power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        long long edgeCost = steinerKMB(terminals, t, nullptr);\n        if (edgeCost >= INF / 2) return INF;\n        return power + edgeCost;\n    }\n\n    long long evaluateExact(const vector<char>& active) {\n        int P[MAXN];\n        if (!buildPNearest(active, P)) return INF;\n\n        shrinkPArray(P);\n        if (!checkCoverageArray(P)) return INF;\n\n        long long power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        long long edgeCost = steinerKMB(terminals, t, nullptr);\n        if (edgeCost >= INF / 2) return INF;\n        return power + edgeCost;\n    }\n\n    inline double initScore(int d, int st, double lambda) {\n        return 1.0 * d * d + lambda * (double)spDist[0][st];\n    }\n\n    vector<char> makeInitAssign(double lambda) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    vector<char> makeInitRepair(double lambda, const vector<int>& order) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            int k = order[idx];\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                if (active[pr.second]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    void repairActive(vector<char>& active, double lambda) {\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                if (active[pr.second]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n    }\n\n    pair<vector<char>, long long> hillClimb1(vector<char> active, int maxIter, double endTime) {\n        long long cur = evaluateFast(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateFast(active);\n        }\n\n        for (int it = 0; it < maxIter && elapsed() < endTime; it++) {\n            long long best = cur;\n            int bestFlip = -1;\n\n            for (int i = 1; i < N; i++) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                long long c = evaluateFast(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n\n            if (bestFlip == -1) break;\n            active[bestFlip] ^= 1;\n            cur = best;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, long long> localSearchWithSwap(vector<char> active, double endTime) {\n        long long cur = evaluateFast(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateFast(active);\n        }\n\n        while (elapsed() < endTime) {\n            bool improved = false;\n\n            // 1-flip steepest\n            long long best = cur;\n            int bestFlip = -1;\n            for (int i = 1; i < N; i++) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                long long c = evaluateFast(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n            if (bestFlip != -1) {\n                active[bestFlip] ^= 1;\n                cur = best;\n                improved = true;\n                continue;\n            }\n\n            // swap (on -> off and off -> on)\n            vector<int> on, off;\n            on.reserve(N);\n            off.reserve(N);\n            for (int i = 1; i < N; i++) {\n                if (active[i]) on.push_back(i);\n                else off.push_back(i);\n            }\n            if (on.empty() || off.empty()) break;\n\n            long long bestSwap = cur;\n            int bi = -1, bj = -1;\n            long long totalPairs = 1LL * on.size() * off.size();\n\n            if (totalPairs <= 3500) {\n                for (int i : on) {\n                    if (elapsed() >= endTime) break;\n                    for (int j : off) {\n                        if (elapsed() >= endTime) break;\n                        active[i] ^= 1;\n                        active[j] ^= 1;\n                        long long c = evaluateFast(active);\n                        active[i] ^= 1;\n                        active[j] ^= 1;\n                        if (c < bestSwap) {\n                            bestSwap = c;\n                            bi = i; bj = j;\n                        }\n                    }\n                }\n            } else {\n                int trials = 3500;\n                for (int tt = 0; tt < trials && elapsed() < endTime; tt++) {\n                    int i = on[rng() % on.size()];\n                    int j = off[rng() % off.size()];\n                    active[i] ^= 1;\n                    active[j] ^= 1;\n                    long long c = evaluateFast(active);\n                    active[i] ^= 1;\n                    active[j] ^= 1;\n                    if (c < bestSwap) {\n                        bestSwap = c;\n                        bi = i; bj = j;\n                    }\n                }\n            }\n\n            if (bi != -1) {\n                active[bi] ^= 1;\n                active[bj] ^= 1;\n                cur = bestSwap;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    vector<char> exactRefine(vector<char> active, double endTime) {\n        long long cur = evaluateExact(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateExact(active);\n        }\n        if (cur >= INF / 2) return active;\n\n        int iter = 0;\n        while (elapsed() < endTime && iter < 6) {\n            iter++;\n\n            long long best = cur;\n            int bestFlip = -1;\n\n            vector<int> ord;\n            ord.reserve(N - 1);\n            for (int i = 1; i < N; i++) ord.push_back(i);\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int i : ord) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                long long c = evaluateExact(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n\n            if (bestFlip != -1) {\n                active[bestFlip] ^= 1;\n                cur = best;\n                continue;\n            }\n\n            // random swap escape\n            vector<int> on, off;\n            for (int i = 1; i < N; i++) {\n                if (active[i]) on.push_back(i);\n                else off.push_back(i);\n            }\n            if (on.empty() || off.empty()) break;\n\n            bool improved = false;\n            int trials = min<int>(60, (int)(1LL * on.size() * off.size()));\n            for (int tt = 0; tt < trials && elapsed() < endTime; tt++) {\n                int i = on[rng() % on.size()];\n                int j = off[rng() % off.size()];\n                active[i] ^= 1;\n                active[j] ^= 1;\n                long long c = evaluateExact(active);\n                if (c < cur) {\n                    cur = c;\n                    improved = true;\n                    break; // keep toggled\n                }\n                active[i] ^= 1;\n                active[j] ^= 1;\n            }\n\n            if (!improved) break;\n        }\n\n        return active;\n    }\n\n    struct Solution {\n        bool feasible = false;\n        long long cost = INF;\n        vector<int> P;\n        vector<char> B;\n    };\n\n    Solution buildSolution(const vector<char>& active, bool doShrink, bool strongEdge) {\n        Solution sol;\n        sol.P.assign(N, 0);\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) return sol;\n\n        if (doShrink) {\n            int backup[MAXN];\n            for (int i = 0; i < N; i++) backup[i] = P[i];\n            shrinkPArray(P);\n            if (!checkCoverageArray(P)) {\n                for (int i = 0; i < N; i++) P[i] = backup[i];\n            }\n        }\n\n        long long power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            sol.P[i] = P[i];\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        long long edgeCost;\n        if (strongEdge) {\n            edgeCost = steinerBestFinal(terminals, t, sol.B);\n        } else {\n            edgeCost = steinerKMB(terminals, t, nullptr);\n        }\n        if (edgeCost >= INF / 2) return sol;\n\n        sol.feasible = true;\n        sol.cost = power + edgeCost;\n        return sol;\n    }\n\n    void solve() {\n        readInput();\n        st = chrono::steady_clock::now();\n\n        precomputeDistances();\n        precomputeShortestPaths();\n\n        vector<char> allOn(N, 1);\n        allOn[0] = 1;\n\n        vector<char> bestActive = allOn;\n        long long bestFast = evaluateFast(bestActive);\n\n        // Prepare initial sets\n        vector<int> ord(K), ordRev(K), ordRnd(K);\n        iota(ord.begin(), ord.end(), 0);\n        ordRev = ord;\n        reverse(ordRev.begin(), ordRev.end());\n        ordRnd = ord;\n        shuffle(ordRnd.begin(), ordRnd.end(), rng);\n\n        vector<vector<char>> inits;\n        inits.push_back(allOn);\n\n        for (double lam : {0.01, 0.03, 0.07, 0.15, 0.30}) {\n            inits.push_back(makeInitAssign(lam));\n        }\n        for (double lam : {0.00, 0.03, 0.10, 0.20}) {\n            inits.push_back(makeInitRepair(lam, ord));\n            inits.push_back(makeInitRepair(lam, ordRev));\n        }\n        inits.push_back(makeInitRepair(0.10, ordRnd));\n\n        const double FAST_END = 1.60;\n        const double INIT_END = 0.80;\n\n        // Multi-start quick hill climbing\n        for (auto act : inits) {\n            if (elapsed() >= INIT_END) break;\n            repairActive(act, 0.05);\n            auto res = hillClimb1(std::move(act), 14, INIT_END);\n            if (res.second < bestFast) {\n                bestFast = res.second;\n                bestActive = std::move(res.first);\n            }\n        }\n\n        // Intensify with swap neighborhood\n        if (elapsed() < 1.25) {\n            auto res = localSearchWithSwap(bestActive, 1.25);\n            if (res.second < bestFast) {\n                bestFast = res.second;\n                bestActive = std::move(res.first);\n            }\n        }\n\n        // Random kicks\n        while (elapsed() < FAST_END) {\n            vector<char> trial = bestActive;\n            int flips = 2 + (rng() % 4);\n            for (int t = 0; t < flips; t++) {\n                int idx = 1 + (rng() % (N - 1));\n                trial[idx] ^= 1;\n            }\n            repairActive(trial, 0.08);\n            auto res = hillClimb1(std::move(trial), 8, FAST_END);\n            if (res.second < bestFast) {\n                bestFast = res.second;\n                bestActive = std::move(res.first);\n            }\n        }\n\n        // Final fast local clean-up\n        auto resFast = localSearchWithSwap(bestActive, FAST_END);\n        if (resFast.second < bestFast) {\n            bestFast = resFast.second;\n            bestActive = std::move(resFast.first);\n        }\n\n        // Exact-ish refine (with shrink in objective)\n        const double EXACT_END = 1.90;\n        bestActive = exactRefine(bestActive, EXACT_END);\n\n        // Build final answer\n        auto ans = buildSolution(bestActive, true, true);\n        auto ansAll = buildSolution(allOn, true, true);\n        if (ansAll.feasible && (!ans.feasible || ansAll.cost < ans.cost)) ans = ansAll;\n        if (!ans.feasible) ans = buildSolution(allOn, false, true);\n\n        if (ans.B.empty()) ans.B.assign(M, 0);\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n\n        for (int j = 0; j < M; j++) {\n            if (j) cout << ' ';\n            cout << int(ans.B[j]);\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}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nusing Board = array<array<int, N>, N>;\n\nstruct Move { int x1, y1, x2, y2; };\nstruct Result {\n    vector<Move> ops;\n    int E = (int)1e9;\n};\n\nstruct Params {\n    int algo;       // 0: top-down(min pull-up), 1: bottom-up(max push-down)\n    bool mirror;    // reflect left-right before solving\n    int order_mode; // 0..4\n    int path_mode;  // 0..4\n};\n\nstatic inline bool same_unordered(const Move& a, const Move& b) {\n    return (a.x1 == b.x1 && a.y1 == b.y1 && a.x2 == b.x2 && a.y2 == b.y2) ||\n           (a.x1 == b.x2 && a.y1 == b.y2 && a.x2 == b.x1 && a.y2 == b.y1);\n}\n\nstatic vector<Move> compress_ops(const vector<Move>& ops) {\n    vector<Move> st;\n    st.reserve(ops.size());\n    for (const auto& mv : ops) {\n        if (!st.empty() && same_unordered(st.back(), mv)) st.pop_back();\n        else st.push_back(mv);\n    }\n    return st;\n}\n\nstatic inline int calcE(const Board& b) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v = b[x][y];\n            if (v > b[x + 1][y]) ++E;\n            if (v > b[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nstatic inline long long calcScore(const Result& r) {\n    if (r.E == 0) return 100000LL - 5LL * (long long)r.ops.size();\n    return 50000LL - 50LL * (long long)r.E;\n}\n\nstatic inline bool better(const Result& a, const Result& b) {\n    long long sa = calcScore(a), sb = calcScore(b);\n    if (sa != sb) return sa > sb;\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\n}\n\n// mode:\n// 0 asc, 1 desc, 2 edges-in, 3 center-out, 4 random shuffle\nstatic inline void build_order(int x, int mode, int ord[], mt19937& rng) {\n    if (mode == 0) {\n        for (int i = 0; i <= x; ++i) ord[i] = i;\n    } else if (mode == 1) {\n        for (int i = 0; i <= x; ++i) ord[i] = x - i;\n    } else if (mode == 2) {\n        int l = 0, r = x, k = 0;\n        while (l <= r) {\n            ord[k++] = l++;\n            if (l <= r) ord[k++] = r--;\n        }\n    } else if (mode == 3) {\n        int k = 0;\n        int mid = x / 2;\n        ord[k++] = mid;\n        for (int d = 1; k <= x; ++d) {\n            int L = mid - d;\n            int R = mid + d;\n            if (L >= 0) ord[k++] = L;\n            if (k > x) break;\n            if (R <= x) ord[k++] = R;\n        }\n    } else {\n        for (int i = 0; i <= x; ++i) ord[i] = i;\n        shuffle(ord, ord + x + 1, rng);\n    }\n}\n\nstatic Result run_variant(const Board& init, const Params& p, mt19937& rng) {\n    Board a{};\n    if (!p.mirror) {\n        a = init;\n    } else {\n        for (int x = 0; x < N; ++x) for (int y = 0; y <= x; ++y) a[x][y] = init[x][x - y];\n    }\n\n    vector<Move> ops;\n    ops.reserve(6000);\n\n    if (p.algo == 0) {\n        // Top-down: pull minimum in downward cone\n        for (int x = 0; x < N; ++x) {\n            int ord[30];\n            build_order(x, p.order_mode, ord, rng);\n\n            for (int ii = 0; ii <= x; ++ii) {\n                int y = ord[ii];\n\n                int bestv = INT_MAX, sx = x, sy = y;\n                for (int r = x; r < N; ++r) {\n                    int cmax = y + (r - x);\n                    for (int c = y; c <= cmax; ++c) {\n                        int v = a[r][c];\n                        if (v < bestv) {\n                            bestv = v;\n                            sx = r; sy = c;\n                        }\n                    }\n                }\n\n                int cx = sx, cy = sy;\n                while (cx > x) {\n                    int rem = cx - x;\n                    int delta = cy - y;\n\n                    bool canL = (delta > 0);     // up-left\n                    bool canR = (delta < rem);   // up-right\n\n                    bool goL;\n                    if (canL && !canR) goL = true;\n                    else if (!canL && canR) goL = false;\n                    else {\n                        int lv = a[cx - 1][cy - 1];\n                        int rv = a[cx - 1][cy];\n                        switch (p.path_mode) {\n                            case 0: goL = true; break;\n                            case 1: goL = false; break;\n                            case 2: goL = (lv == rv ? (rng() & 1) : (lv > rv)); break; // push larger down\n                            case 3: goL = (lv == rv ? (rng() & 1) : (lv < rv)); break; // push smaller down\n                            default: goL = (rng() & 1); break;\n                        }\n                    }\n\n                    int nx = cx - 1;\n                    int ny = goL ? (cy - 1) : cy;\n                    swap(a[cx][cy], a[nx][ny]);\n                    ops.push_back({cx, cy, nx, ny});\n                    cx = nx; cy = ny;\n                }\n            }\n        }\n    } else {\n        // Bottom-up: push maximum in upward cone\n        for (int x = N - 1; x >= 0; --x) {\n            int ord[30];\n            build_order(x, p.order_mode, ord, rng);\n\n            for (int ii = 0; ii <= x; ++ii) {\n                int y = ord[ii];\n\n                int bestv = -1, sx = x, sy = y;\n                for (int r = 0; r <= x; ++r) {\n                    int d = x - r;\n                    int cmin = max(0, y - d);\n                    int cmax = min(r, y);\n                    for (int c = cmin; c <= cmax; ++c) {\n                        int v = a[r][c];\n                        if (v > bestv) {\n                            bestv = v;\n                            sx = r; sy = c;\n                        }\n                    }\n                }\n\n                int cx = sx, cy = sy;\n                while (cx < x) {\n                    int rem = x - cx;\n                    int delta = y - cy;\n\n                    bool canS = (delta <= rem - 1); // (cx+1, cy)\n                    bool canP = (delta >= 1);       // (cx+1, cy+1)\n\n                    bool goPlus;\n                    if (canS && !canP) goPlus = false;\n                    else if (!canS && canP) goPlus = true;\n                    else {\n                        int sv = a[cx + 1][cy];\n                        int pv = a[cx + 1][cy + 1];\n                        switch (p.path_mode) {\n                            case 0: goPlus = false; break;\n                            case 1: goPlus = true; break;\n                            case 2: goPlus = (sv == pv ? (rng() & 1) : (pv < sv)); break; // smaller child up\n                            case 3: goPlus = (sv == pv ? (rng() & 1) : (pv > sv)); break;\n                            default: goPlus = (rng() & 1); break;\n                        }\n                    }\n\n                    int nx = cx + 1;\n                    int ny = goPlus ? (cy + 1) : cy;\n                    swap(a[cx][cy], a[nx][ny]);\n                    ops.push_back({cx, cy, nx, ny});\n                    cx = nx; cy = ny;\n                }\n            }\n        }\n    }\n\n    if (p.mirror) {\n        for (auto& mv : ops) {\n            mv.y1 = mv.x1 - mv.y1;\n            mv.y2 = mv.x2 - mv.y2;\n        }\n    }\n\n    ops = compress_ops(ops);\n\n    Result res;\n    res.E = calcE(a);\n    res.ops = std::move(ops);\n    return res;\n}\n\nstatic int calcE_ops(const Board& init, const vector<Move>& ops) {\n    Board b = init;\n    for (const auto& m : ops) {\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b);\n}\n\nstatic int calcE_skip1(const Board& init, const vector<Move>& ops, int skip) {\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == skip) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b);\n}\n\nstatic int calcE_skip2(const Board& init, const vector<Move>& ops, int s1, int s2) {\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == s1 || i == s2) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b);\n}\n\nstatic void prune_ops(\n    const Board& init,\n    vector<Move>& ops,\n    mt19937& rng,\n    const chrono::steady_clock::time_point& start,\n    double time_limit_sec\n) {\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    ops = compress_ops(ops);\n\n    // Greedy single deletion (2 passes)\n    for (int pass = 0; pass < 2; ++pass) {\n        bool any = false;\n        for (int i = 0; i < (int)ops.size(); ++i) {\n            if (elapsed() > time_limit_sec) return;\n            if (calcE_skip1(init, ops, i) == 0) {\n                ops.erase(ops.begin() + i);\n                --i;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n\n    // Random pair deletion\n    for (int t = 0; t < 600; ++t) {\n        if (elapsed() > time_limit_sec) return;\n        int n = (int)ops.size();\n        if (n < 2) break;\n        int i = (int)(rng() % n);\n        int j = (int)(rng() % n);\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n\n        if (calcE_skip2(init, ops, i, j) == 0) {\n            ops.erase(ops.begin() + j);\n            ops.erase(ops.begin() + i);\n        }\n    }\n\n    // One more single pass\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (elapsed() > time_limit_sec) break;\n        if (calcE_skip1(init, ops, i) == 0) {\n            ops.erase(ops.begin() + i);\n            --i;\n        }\n    }\n\n    ops = compress_ops(ops);\n}\n\nstatic void add_pool(vector<Result>& pool, Result&& r, int pool_max = 10) {\n    if (r.E != 0) return;\n    if ((int)r.ops.size() > 10000) return;\n\n    if ((int)pool.size() < pool_max) {\n        pool.push_back(std::move(r));\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < pool_max; ++i) {\n        if (pool[i].ops.size() > pool[worst].ops.size()) worst = i;\n    }\n\n    if (r.ops.size() < pool[worst].ops.size()) {\n        pool[worst] = std::move(r);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board init{};\n    uint64_t h = 1469598103934665603ULL;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n            h ^= (uint64_t)(init[x][y] + 1);\n            h *= 1099511628211ULL;\n        }\n    }\n\n    mt19937 rng((uint32_t)(h ^ 0x9e3779b97f4a7c15ULL));\n\n    using Clock = chrono::steady_clock;\n    const auto start = Clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(Clock::now() - start).count();\n    };\n\n    constexpr double SEARCH_T = 1.40;\n    constexpr double TOTAL_T  = 1.88;\n\n    vector<Result> pool;\n    pool.reserve(12);\n\n    // Safe baseline first\n    {\n        Params p{0, false, 0, 2};\n        add_pool(pool, run_variant(init, p, rng));\n    }\n\n    // Deterministic-ish grid search\n    bool stop = false;\n    for (int algo = 0; algo <= 1 && !stop; ++algo) {\n        for (int mir = 0; mir < 2 && !stop; ++mir) {\n            for (int order = 0; order < 5 && !stop; ++order) {\n                for (int path = 0; path < 5; ++path) {\n                    if (elapsed() > SEARCH_T) { stop = true; break; }\n                    Params p{algo, (bool)mir, order, path};\n                    add_pool(pool, run_variant(init, p, rng));\n                }\n            }\n        }\n    }\n\n    // Random multi-start\n    for (int it = 0; ; ++it) {\n        if ((it & 15) == 0 && elapsed() > SEARCH_T) break;\n\n        Params p;\n        p.algo = ((int)(rng() % 100) < 88) ? 0 : 1;\n        p.mirror = (rng() & 1);\n        p.order_mode = (int)(rng() % 5);\n        p.path_mode  = (int)(rng() % 5);\n\n        add_pool(pool, run_variant(init, p, rng));\n    }\n\n    // Fallback (should not happen)\n    if (pool.empty()) {\n        Params p{0, false, 0, 0};\n        pool.push_back(run_variant(init, p, rng));\n    }\n\n    sort(pool.begin(), pool.end(), [](const Result& a, const Result& b) {\n        return a.ops.size() < b.ops.size();\n    });\n\n    Result best;\n    bool has_best = false;\n\n    // Unpruned best among pool\n    for (const auto& c : pool) {\n        if (!has_best || better(c, best)) {\n            best = c;\n            has_best = true;\n        }\n    }\n\n    // Prune each top candidate\n    for (auto cand : pool) {\n        if (elapsed() > TOTAL_T) break;\n        prune_ops(init, cand.ops, rng, start, TOTAL_T);\n        cand.E = calcE_ops(init, cand.ops);\n        if (!has_best || better(cand, best)) {\n            best = std::move(cand);\n            has_best = true;\n        }\n    }\n\n    if (!has_best || best.E != 0) {\n        Params p{0, false, 0, 2};\n        best = run_variant(init, p, rng);\n        best.E = calcE_ops(init, best.ops);\n    }\n\n    if ((int)best.ops.size() > 10000) {\n        best.ops.resize(10000);\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& m : best.ops) {\n        cout << m.x1 << ' ' << m.y1 << ' ' << m.x2 << ' ' << m.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int r, c;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    if (!(cin >> D >> N)) return 0;\n\n    const int er = 0;\n    const int ec = (D - 1) / 2;\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    auto inb = [&](int r, int c) -> bool {\n        return (0 <= r && r < D && 0 <= c && c < D);\n    };\n\n    // Build free-cell list (excluding entrance and obstacles)\n    vector<vector<int>> id(D, vector<int>(D, -1));\n    vector<Pos> cells;\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            if (i == er && j == ec) continue;\n            if (obstacle[i][j]) continue;\n            id[i][j] = (int)cells.size();\n            cells.push_back({i, j});\n        }\n    }\n\n    const int M = (int)cells.size(); // number of containers\n    const int ENT = M;               // entrance node id\n\n    // Graph: free cells + entrance\n    vector<vector<int>> adj(M + 1);\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = cells[i];\n        for (int d = 0; d < 4; d++) {\n            int nr = r + dr[d], nc = c + dc[d];\n            if (!inb(nr, nc) || obstacle[nr][nc]) continue;\n            if (nr == er && nc == ec) {\n                adj[i].push_back(ENT);\n                adj[ENT].push_back(i);\n            } else {\n                int j = id[nr][nc];\n                if (j >= 0) adj[i].push_back(j);\n            }\n        }\n    }\n\n    // Count reachable free nodes from entrance in induced graph of alive nodes excluding ban.\n    auto reachable_count = [&](const vector<char>& alive, int ban) -> int {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        int cnt = 0;\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (v == ENT) continue;\n                if (v == ban || !alive[v] || vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    // BFS distance from entrance in induced alive graph.\n    auto compute_dist = [&](const vector<char>& alive) -> vector<int> {\n        vector<int> dist(M, -1);\n        queue<int> q;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            int du = (u == ENT ? 0 : dist[u]);\n\n            for (int v : adj[u]) {\n                if (v == ENT) continue;\n                if (!alive[v]) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du + 1;\n                q.push(v);\n            }\n        }\n        return dist;\n    };\n\n    // ---------- Precompute structural priorities by reverse peeling ----------\n    vector<char> alive(M, 1);\n    vector<int> peel_step(M, -1);\n\n    for (int step = 0; step < M; step++) {\n        int rem = M - step;\n        auto dist = compute_dist(alive);\n\n        int best = -1;\n        int bestD = -1;\n        int bestTie = -1;\n\n        for (int i = 0; i < M; i++) {\n            if (!alive[i]) continue;\n            // Must keep remaining empties connected to entrance.\n            if (reachable_count(alive, i) != rem - 1) continue;\n\n            int d = dist[i];\n            int tie = abs(cells[i].r - er) + abs(cells[i].c - ec); // farther first\n            if (best == -1 ||\n                d > bestD ||\n                (d == bestD && tie > bestTie) ||\n                (d == bestD && tie == bestTie &&\n                 (cells[i].r > cells[best].r ||\n                  (cells[i].r == cells[best].r && cells[i].c > cells[best].c)))) {\n                best = i;\n                bestD = d;\n                bestTie = tie;\n            }\n        }\n\n        if (best == -1) {\n            // Fallback (should not happen)\n            for (int i = 0; i < M; i++) {\n                if (alive[i]) {\n                    best = i;\n                    break;\n                }\n            }\n        }\n\n        peel_step[best] = step;\n        alive[best] = 0;\n    }\n\n    vector<int> prio(M);\n    for (int i = 0; i < M; i++) {\n        prio[i] = M - 1 - peel_step[i]; // smaller = earlier desired unloading\n    }\n\n    vector<char> allAlive(M, 1);\n    vector<int> distStatic = compute_dist(allAlive);\n\n    // ---------- Online insertion ----------\n    vector<char> inU(M, 1);       // still empty (not occupied yet)\n    vector<char> unseen(M, 1);    // unseen labels\n    vector<int> labelAt(M, -1);   // label placed at each cell\n    vector<int> assigned;\n    assigned.reserve(M);\n\n    for (int d = 0; d < M; d++) {\n        int t;\n        if (!(cin >> t)) return 0;\n\n        int rem = M - d;\n\n        // Rank of current label among remaining labels\n        int qrank = 0;\n        for (int x = 0; x < t; x++) {\n            if (unseen[x]) qrank++;\n        }\n\n        // Legal candidates: deleting this empty vertex keeps remaining empties connected\n        vector<int> safe;\n        safe.reserve(rem);\n        for (int i = 0; i < M; i++) {\n            if (!inU[i]) continue;\n            if (reachable_count(inU, i) == rem - 1) safe.push_back(i);\n        }\n\n        bool low = (2 * qrank < rem);\n\n        auto better_tie = [&](int a, int b) -> bool {\n            if (b == -1) return true;\n            if (low) {\n                if (prio[a] != prio[b]) return prio[a] < prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] < distStatic[b];\n            } else {\n                if (prio[a] != prio[b]) return prio[a] > prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] > distStatic[b];\n            }\n            if (cells[a].r != cells[b].r) return cells[a].r < cells[b].r;\n            return cells[a].c < cells[b].c;\n        };\n\n        int best = -1;\n        long long bestScore = (1LL << 60);\n\n        for (int c : safe) {\n            int p = prio[c];\n\n            // Rank of this priority among remaining priorities\n            int rrank = 0;\n            for (int j = 0; j < M; j++) {\n                if (inU[j] && prio[j] < p) rrank++;\n            }\n\n            // Exact inversions with already assigned containers\n            int invPast = 0;\n            for (int a : assigned) {\n                int pa = prio[a];\n                int la = labelAt[a];\n                if (pa < p && la > t) invPast++;\n                if (pa > p && la < t) invPast++;\n            }\n\n            // Proxy objective: past exact + future quantile mismatch\n            long long score = (long long)invPast + llabs((long long)rrank - qrank);\n\n            if (best == -1 || score < bestScore || (score == bestScore && better_tie(c, best))) {\n                best = c;\n                bestScore = score;\n            }\n        }\n\n        if (best == -1) {\n            // Fallback (should not happen)\n            for (int i = 0; i < M; i++) {\n                if (inU[i]) {\n                    best = i;\n                    break;\n                }\n            }\n        }\n\n        inU[best] = 0;\n        unseen[t] = 0;\n        labelAt[best] = t;\n        assigned.push_back(best);\n\n        cout << cells[best].r << ' ' << cells[best].c << '\\n' << flush;\n    }\n\n    // ---------- Offline unloading: beam search ----------\n    struct Node {\n        uint64_t lo, hi;   // removed cell mask\n        uint64_t llo, lhi; // removed label mask\n        int cost;          // inversion count accumulated\n        int parent;        // parent node index\n        int mv;            // removed cell at this step\n    };\n\n    auto getbit = [&](uint64_t lo, uint64_t hi, int b) -> bool {\n        if (b < 64) return ((lo >> b) & 1ULL) != 0ULL;\n        return ((hi >> (b - 64)) & 1ULL) != 0ULL;\n    };\n    auto setbit = [&](uint64_t& lo, uint64_t& hi, int b) {\n        if (b < 64) lo |= (1ULL << b);\n        else hi |= (1ULL << (b - 64));\n    };\n    auto popBelow = [&](uint64_t lo, uint64_t hi, int k) -> int {\n        if (k <= 0) return 0;\n        if (k < 64) {\n            uint64_t mask = (1ULL << k) - 1ULL;\n            return __builtin_popcountll(lo & mask);\n        } else if (k == 64) {\n            return __builtin_popcountll(lo);\n        } else {\n            int kk = k - 64; // <= 16\n            uint64_t mask = (1ULL << kk) - 1ULL;\n            return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n        }\n    };\n\n    auto accessible_from_mask = [&](uint64_t lo, uint64_t hi) -> vector<int> {\n        vector<int> cand;\n        cand.reserve(16);\n\n        vector<char> vis(M + 1, 0), inCand(M, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n\n            for (int v : adj[u]) {\n                if (v == ENT) continue;\n                if (getbit(lo, hi, v)) {\n                    if (!vis[v]) {\n                        vis[v] = 1;\n                        q.push(v);\n                    }\n                } else {\n                    if (!inCand[v]) {\n                        inCand[v] = 1;\n                        cand.push_back(v);\n                    }\n                }\n            }\n        }\n        return cand;\n    };\n\n    const int BEAM_WIDTH = 300;\n\n    vector<Node> nodes;\n    nodes.reserve(1 + BEAM_WIDTH * (M + 1));\n    nodes.push_back({0ULL, 0ULL, 0ULL, 0ULL, 0, -1, -1});\n\n    vector<int> beam = {0};\n\n    for (int depth = 0; depth < M; depth++) {\n        vector<Node> next;\n        next.reserve((int)beam.size() * 12);\n\n        for (int sid : beam) {\n            const Node& st = nodes[sid];\n            auto cand = accessible_from_mask(st.lo, st.hi);\n\n            for (int c : cand) {\n                Node nx = st;\n                setbit(nx.lo, nx.hi, c);\n\n                int lab = labelAt[c];\n                int removedSmaller = popBelow(st.llo, st.lhi, lab);\n                nx.cost = st.cost + (lab - removedSmaller);\n\n                setbit(nx.llo, nx.lhi, lab);\n                nx.parent = sid;\n                nx.mv = c;\n                next.push_back(nx);\n            }\n        }\n\n        if (next.empty()) break;\n\n        // Deduplicate by removed-cell mask: keep minimum cost\n        sort(next.begin(), next.end(), [](const Node& a, const Node& b) {\n            if (a.lo != b.lo) return a.lo < b.lo;\n            if (a.hi != b.hi) return a.hi < b.hi;\n            return a.cost < b.cost;\n        });\n\n        vector<Node> uniq;\n        uniq.reserve(next.size());\n        for (const auto& nd : next) {\n            if (uniq.empty() || nd.lo != uniq.back().lo || nd.hi != uniq.back().hi) {\n                uniq.push_back(nd);\n            }\n        }\n\n        if ((int)uniq.size() > BEAM_WIDTH) {\n            nth_element(uniq.begin(), uniq.begin() + BEAM_WIDTH, uniq.end(),\n                        [](const Node& a, const Node& b) { return a.cost < b.cost; });\n            uniq.resize(BEAM_WIDTH);\n        }\n\n        sort(uniq.begin(), uniq.end(), [](const Node& a, const Node& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.lo != b.lo) return a.lo < b.lo;\n            return a.hi < b.hi;\n        });\n\n        beam.clear();\n        beam.reserve(uniq.size());\n        for (const auto& nd : uniq) {\n            nodes.push_back(nd);\n            beam.push_back((int)nodes.size() - 1);\n        }\n    }\n\n    vector<int> order;\n    if (!beam.empty()) {\n        int bestState = beam[0];\n        for (int sid : beam) {\n            if (nodes[sid].cost < nodes[bestState].cost) bestState = sid;\n        }\n\n        while (bestState != -1 && nodes[bestState].parent != -1) {\n            order.push_back(nodes[bestState].mv);\n            bestState = nodes[bestState].parent;\n        }\n        reverse(order.begin(), order.end());\n    }\n\n    // Fallback (just in case beam ended abnormally)\n    if ((int)order.size() != M) {\n        order.clear();\n        order.reserve(M);\n        uint64_t lo = 0ULL, hi = 0ULL;\n\n        for (int step = 0; step < M; step++) {\n            auto cand = accessible_from_mask(lo, hi);\n            int best = -1;\n            for (int c : cand) {\n                if (best == -1 || labelAt[c] < labelAt[best]) best = c;\n            }\n            if (best == -1) {\n                for (int i = 0; i < M; i++) {\n                    if (!getbit(lo, hi, i)) {\n                        best = i;\n                        break;\n                    }\n                }\n            }\n            setbit(lo, hi, best);\n            order.push_back(best);\n        }\n    }\n\n    for (int c : order) {\n        cout << cells[c].r << ' ' << cells[c].c << '\\n';\n    }\n    cout.flush();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nconstexpr int NMAX = 50;\nconstexpr int CMAX = 101;\nconstexpr int INF = 1e9;\n\nstruct Problem {\n    int n = 0, m = 0;\n    array<array<int, NMAX>, NMAX> initGrid{};\n    array<int, CMAX> initCnt{};\n    array<array<int, CMAX>, CMAX> initEdgeCnt{};\n    array<array<bool, CMAX>, CMAX> targetAdj{};\n    array<bool, CMAX> canZero{};\n    array<int, CMAX> depth{};\n    array<int, CMAX> deg{};\n};\n\nstruct State {\n    const Problem* pb = nullptr;\n\n    array<array<int, NMAX>, NMAX> g{};\n    array<int, CMAX> cnt{};\n    array<array<int, CMAX>, CMAX> edgeCnt{};\n    int zeroCount = 0;\n\n    array<array<int, NMAX>, NMAX> vis{};\n    int visToken = 1;\n\n    vector<int> order;\n\n    State() = default;\n    explicit State(const Problem* p) { init(p); }\n\n    void init(const Problem* p) {\n        pb = p;\n        g = pb->initGrid;\n        cnt = pb->initCnt;\n        edgeCnt = pb->initEdgeCnt;\n        zeroCount = cnt[0];\n        for (auto& row : vis) row.fill(0);\n        visToken = 1;\n        order.resize(pb->n * pb->n);\n        iota(order.begin(), order.end(), 0);\n    }\n\n    inline bool in(int x, int y) const {\n        return (0 <= x && x < pb->n && 0 <= y && y < pb->n);\n    }\n\n    bool connected_after_remove(int ri, int rj, int color, int si, int sj) {\n        int need = cnt[color] - 1; // remaining cells after removal\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        vis[si][sj] = visToken;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        if (reached == need) return true;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != color) continue;\n                if (vis[nx][ny] == visToken) continue;\n\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n                if (reached == need) return true;\n            }\n        }\n        return reached == need;\n    }\n\n    bool try_change(int i, int j, int b) {\n        int a = g[i][j];\n        if (a == 0 || a == b) return false;\n\n        // Keep non-zero colors non-empty.\n        if (cnt[a] <= 1) return false;\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // New color connectivity local check\n        if (b == 0) {\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary) {\n                bool adj0 = false;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == 0) {\n                        adj0 = true;\n                        break;\n                    }\n                }\n                if (!adj0) return false;\n            }\n        } else {\n            // b is always present for non-zero colors, but keep safe:\n            if (cnt[b] > 0) {\n                bool adjb = false;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == b) {\n                        adjb = true;\n                        break;\n                    }\n                }\n                if (!adjb) return false;\n            }\n        }\n\n        // Edge count delta around (i, j)\n        int pu[8], pv[8], pd[8], psz = 0;\n\n        auto add_delta = [&](int x, int y, int d) {\n            if (x == y) return;\n            if (x > y) swap(x, y);\n            for (int t = 0; t < psz; t++) {\n                if (pu[t] == x && pv[t] == y) {\n                    pd[t] += d;\n                    return;\n                }\n            }\n            pu[psz] = x;\n            pv[psz] = y;\n            pd[psz] = d;\n            ++psz;\n        };\n\n        for (int dir = 0; dir < 4; dir++) {\n            int ni = i + dx[dir], nj = j + dy[dir];\n            int x = in(ni, nj) ? g[ni][nj] : 0; // outside is color 0\n            add_delta(a, x, -1);\n            add_delta(b, x, +1);\n        }\n\n        // Adjacency graph must match target exactly\n        for (int t = 0; t < psz; t++) {\n            int u = pu[t], v = pv[t];\n            int nc = edgeCnt[u][v] + pd[t];\n            if (nc < 0) return false;\n            bool present = (nc > 0);\n            if (present != pb->targetAdj[u][v]) return false;\n        }\n\n        // Old color connectivity check after removal\n        int same = 0, si = -1, sj = -1;\n        for (int dir = 0; dir < 4; dir++) {\n            int ni = i + dx[dir], nj = j + dy[dir];\n            if (in(ni, nj) && g[ni][nj] == a) {\n                ++same;\n                if (si == -1) {\n                    si = ni; sj = nj;\n                }\n            }\n        }\n        if (same == 0) return false; // should not happen if cnt[a] > 1 and connected\n        if (same >= 2 && (cnt[a] - 1) > 1) {\n            if (!connected_after_remove(i, j, a, si, sj)) return false;\n        }\n\n        // Apply\n        g[i][j] = b;\n        --cnt[a];\n        ++cnt[b];\n        if (b == 0) ++zeroCount;\n\n        for (int t = 0; t < psz; t++) {\n            edgeCnt[pu[t]][pv[t]] += pd[t];\n        }\n        return true;\n    }\n\n    // value[c] defines direction for recolor: only to lower value.\n    // if allowRecolor=false: delete-to-0 only.\n    int improve(const vector<int>& value, mt19937& rng, Clock::time_point deadline,\n                int maxPass, bool allowRecolor) {\n        int totalChanges = 0;\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 < maxPass; pass++) {\n            if (Clock::now() >= deadline) break;\n            bool changed = false;\n\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int t = 0; t < (int)order.size(); t++) {\n                if ((t & 127) == 0 && Clock::now() >= deadline) return totalChanges;\n\n                int idx = order[t];\n                int i = idx / pb->n;\n                int j = idx % pb->n;\n                int a = g[i][j];\n                if (a == 0) continue;\n\n                // Priority 1: delete to 0\n                if (pb->canZero[a]) {\n                    if (try_change(i, j, 0)) {\n                        changed = true;\n                        ++totalChanges;\n                        continue;\n                    }\n                }\n\n                if (!allowRecolor) continue;\n\n                // Priority 2: recolor to neighboring non-zero color with lower value\n                int cand[4], k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b <= 0 || b == a) continue;\n                    if (value[b] >= value[a]) continue;\n\n                    bool dup = false;\n                    for (int q = 0; q < k; q++) {\n                        if (cand[q] == b) { dup = true; break; }\n                    }\n                    if (!dup) cand[k++] = b;\n                }\n                if (k == 0) continue;\n\n                // random tie-shuffle then sort by value ascending\n                for (int x = 0; x < k; x++) {\n                    int r = x + (int)(rng() % (k - x));\n                    swap(cand[x], cand[r]);\n                }\n                for (int x = 1; x < k; x++) {\n                    int key = cand[x], y = x - 1;\n                    while (y >= 0 && value[cand[y]] > value[key]) {\n                        cand[y + 1] = cand[y];\n                        --y;\n                    }\n                    cand[y + 1] = key;\n                }\n\n                for (int q = 0; q < k; q++) {\n                    if (try_change(i, j, cand[q])) {\n                        changed = true;\n                        ++totalChanges;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return totalChanges;\n    }\n};\n\nstatic vector<int> make_value(const Problem& pb, int mode, mt19937& rng, int maxDepth) {\n    // mode:\n    // 0: depth-biased\n    // 1: pure random\n    // 2: reverse-depth shake\n    // 3: canZero-biased\n    // 4: degree-biased\n    vector<int> value(pb.m + 1, 0);\n\n    vector<int> cols(pb.m);\n    iota(cols.begin(), cols.end(), 1);\n    shuffle(cols.begin(), cols.end(), rng);\n\n    vector<int> prio(pb.m + 1, 0);\n    for (int i = 0; i < pb.m; i++) prio[cols[i]] = i;\n\n    for (int c = 1; c <= pb.m; c++) {\n        if (mode == 0) {\n            value[c] = pb.depth[c] * 1000 + prio[c];\n        } else if (mode == 1) {\n            value[c] = prio[c];\n        } else if (mode == 2) {\n            value[c] = (maxDepth - pb.depth[c]) * 1000 + prio[c];\n        } else if (mode == 3) {\n            value[c] = (pb.canZero[c] ? 0 : 100000) + pb.depth[c] * 200 + prio[c];\n        } else { // mode == 4\n            value[c] = (pb.m - pb.deg[c]) * 1000 + prio[c];\n        }\n    }\n    return value;\n}\n\nbool validate_solution(const State& st) {\n    const Problem& pb = *st.pb;\n    int n = pb.n, m = pb.m;\n\n    array<int, CMAX> realCnt{};\n    realCnt.fill(0);\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (c < 0 || c > m) return false;\n            ++realCnt[c];\n        }\n    }\n    if (realCnt != st.cnt) return false;\n\n    array<array<bool, CMAX>, CMAX> adj{};\n    for (auto& row : adj) row.fill(false);\n\n    auto add_adj = [&](int a, int b) {\n        if (a == b) return;\n        adj[a][b] = adj[b][a] = true;\n    };\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (i + 1 < n) add_adj(c, st.g[i + 1][j]);\n            if (j + 1 < n) add_adj(c, st.g[i][j + 1]);\n            if (i == 0) add_adj(0, c);\n            if (i == n - 1) add_adj(0, c);\n            if (j == 0) add_adj(0, c);\n            if (j == n - 1) add_adj(0, c);\n        }\n    }\n\n    for (int u = 0; u <= m; u++) {\n        for (int v = u + 1; v <= m; v++) {\n            if (adj[u][v] != pb.targetAdj[u][v]) return false;\n        }\n    }\n\n    static const int dx[4] = {-1, 1, 0, 0};\n    static const int dy[4] = {0, 0, -1, 1};\n\n    auto in = [&](int x, int y) {\n        return (0 <= x && x < n && 0 <= y && y < n);\n    };\n\n    array<array<int, NMAX>, NMAX> vis{};\n    for (auto& row : vis) row.fill(0);\n    int token = 1;\n\n    // Connectivity for colors 1..m\n    for (int color = 1; color <= m; color++) {\n        int si = -1, sj = -1;\n        for (int i = 0; i < n && si == -1; i++) {\n            for (int j = 0; j < n; j++) {\n                if (st.g[i][j] == color) {\n                    si = i; sj = j; break;\n                }\n            }\n        }\n        if (si == -1) return false;\n\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        vis[si][sj] = token;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != color) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[color]) return false;\n    }\n\n    // Connectivity for color 0 through outside\n    if (realCnt[0] > 0) {\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                if (i != 0 && i != n - 1 && j != 0 && j != n - 1) continue;\n                if (st.g[i][j] != 0) continue;\n                if (vis[i][j] == token) continue;\n                vis[i][j] = token;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n            }\n        }\n        if (tail == 0) return false;\n\n        int reached = tail;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != 0) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem pb;\n    cin >> pb.n >> pb.m;\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            cin >> pb.initGrid[i][j];\n        }\n    }\n\n    pb.initCnt.fill(0);\n    for (auto& row : pb.initEdgeCnt) row.fill(0);\n    for (auto& row : pb.targetAdj) row.fill(false);\n    pb.canZero.fill(false);\n    pb.depth.fill(INF);\n    pb.deg.fill(0);\n\n    auto add_edge_count = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        pb.initEdgeCnt[a][b]++;\n    };\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            int c = pb.initGrid[i][j];\n            ++pb.initCnt[c];\n\n            if (i + 1 < pb.n) add_edge_count(c, pb.initGrid[i + 1][j]);\n            if (j + 1 < pb.n) add_edge_count(c, pb.initGrid[i][j + 1]);\n\n            if (i == 0) add_edge_count(0, c);\n            if (i == pb.n - 1) add_edge_count(0, c);\n            if (j == 0) add_edge_count(0, c);\n            if (j == pb.n - 1) add_edge_count(0, c);\n        }\n    }\n\n    for (int u = 0; u <= pb.m; u++) {\n        for (int v = u + 1; v <= pb.m; v++) {\n            if (pb.initEdgeCnt[u][v] > 0) {\n                pb.targetAdj[u][v] = pb.targetAdj[v][u] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= pb.m; c++) {\n        pb.canZero[c] = pb.targetAdj[0][c];\n    }\n\n    for (int c = 0; c <= pb.m; c++) {\n        int d = 0;\n        for (int e = 0; e <= pb.m; e++) {\n            if (c != e && pb.targetAdj[c][e]) ++d;\n        }\n        pb.deg[c] = d;\n    }\n\n    // BFS depth from color 0 on target adjacency graph\n    queue<int> q;\n    pb.depth[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        for (int to = 0; to <= pb.m; to++) {\n            if (!pb.targetAdj[v][to]) continue;\n            if (pb.depth[to] != INF) continue;\n            pb.depth[to] = pb.depth[v] + 1;\n            q.push(to);\n        }\n    }\n    for (int c = 0; c <= pb.m; c++) {\n        if (pb.depth[c] == INF) pb.depth[c] = 50;\n    }\n\n    int maxDepth = 1;\n    for (int c = 1; c <= pb.m; c++) maxDepth = max(maxDepth, pb.depth[c]);\n\n    mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n\n    auto deadline = Clock::now() + chrono::milliseconds(1850);\n\n    State cur(&pb), best(&pb);\n    int bestScore = cur.zeroCount;\n\n    vector<int> dummy(pb.m + 1, 0);\n\n    // Initial strong contraction (depth-biased)\n    {\n        auto vInit = make_value(pb, 0, rng, maxDepth);\n        cur.improve(vInit, rng, deadline, 100, true);\n        cur.improve(dummy, rng, deadline, 8, false);\n        best = cur;\n        bestScore = cur.zeroCount;\n    }\n\n    int stagnation = 0;\n\n    while (Clock::now() < deadline) {\n        int roll = (int)(rng() % 100);\n        int mode = 0, passes = 10;\n\n        if (roll < 55) {          // main mode\n            mode = 0; passes = 14;\n        } else if (roll < 78) {   // random\n            mode = 1; passes = 10;\n        } else if (roll < 90) {   // canZero-biased\n            mode = 3; passes = 12;\n        } else if (roll < 97) {   // degree-biased\n            mode = 4; passes = 10;\n        } else {                  // reverse-depth shake\n            mode = 2; passes = 8;\n        }\n\n        auto v = make_value(pb, mode, rng, maxDepth);\n\n        int before = cur.zeroCount;\n        cur.improve(v, rng, deadline, passes, true);\n        cur.improve(dummy, rng, deadline, 3, false);\n\n        if (cur.zeroCount > bestScore) {\n            best = cur;\n            bestScore = cur.zeroCount;\n            stagnation = 0;\n        } else {\n            if (cur.zeroCount > before) stagnation = 0;\n            else stagnation++;\n        }\n\n        if (stagnation >= 10 && Clock::now() < deadline) {\n            if ((rng() & 1u) == 0u) {\n                // reset to best + small shake\n                cur = best;\n                auto shake = make_value(pb, 1, rng, maxDepth);\n                cur.improve(shake, rng, deadline, 6, true);\n                cur.improve(dummy, rng, deadline, 2, false);\n            } else {\n                // short restart from initial\n                State alt(&pb);\n                auto v1 = make_value(pb, 1, rng, maxDepth);\n                alt.improve(v1, rng, deadline, 14, true);\n                auto v2 = make_value(pb, 0, rng, maxDepth);\n                alt.improve(v2, rng, deadline, 14, true);\n                alt.improve(dummy, rng, deadline, 5, false);\n\n                if (alt.zeroCount > bestScore) {\n                    best = alt;\n                    bestScore = alt.zeroCount;\n                }\n                if (alt.zeroCount >= cur.zeroCount) cur = alt;\n                else cur = best;\n            }\n            stagnation = 0;\n        }\n    }\n\n    // Safety fallback (rare)\n    if (!validate_solution(best)) {\n        best.init(&pb);\n    }\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            if (j) cout << ' ';\n            cout << best.g[i][j];\n        }\n        cout << '\\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    mt19937 rng;\n\n    vector<int> assign;              // item -> bin\n    vector<vector<int>> bins;        // bin -> items\n    vector<double> w_est;            // estimated item weights\n    vector<double> bin_sum_est;      // estimated bin sums\n    vector<int> rank_pos;            // estimated rank: 0=heaviest\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    static int ceil_log2_int(int x) {\n        int p = 1, c = 0;\n        while (p < x) p <<= 1, ++c;\n        return c;\n    }\n\n    static int insertion_cost(int n) {\n        int c = 0;\n        for (int m = 1; m < n; ++m) c += ceil_log2_int(m + 1);\n        return c;\n    }\n\n    char ask(const vector<int>& L, const vector<int>& R) {\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n';\n        cout.flush();\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        if (s == \"-1\") exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char ask_single(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask(L, R);\n    }\n\n    // Full ranking by binary insertion sort (descending: heavy first).\n    vector<int> full_sort_items() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        shuffle(items.begin(), items.end(), rng);\n\n        vector<int> ord;\n        ord.reserve(N);\n        ord.push_back(items[0]);\n\n        for (int idx = 1; idx < N; ++idx) {\n            int x = items[idx];\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                char c = ask_single(x, ord[mid]);\n                if (c == '>') {\n                    hi = mid;        // x heavier -> left side\n                } else if (c == '<') {\n                    lo = mid + 1;    // x lighter -> right side\n                } else {\n                    lo = mid;\n                    hi = mid;\n                    break;\n                }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    // Budgeted coarse ranking for low-Q cases.\n    vector<int> partial_rank_budget(int budget) {\n        vector<int> score(N, 0);\n        vector<vector<int>> seen(N, vector<int>(N, 0));\n\n        auto cmp_and_update = [&](int a, int b) -> char {\n            char c = ask_single(a, b);\n            int x = min(a, b), y = max(a, b);\n            seen[x][y] = 1;\n            if (c == '>') {\n                score[a]++; score[b]--;\n            } else if (c == '<') {\n                score[a]--; score[b]++;\n            }\n            return c;\n        };\n\n        // Groups are kept in coarse descending order.\n        vector<vector<int>> groups(1, vector<int>(N));\n        iota(groups[0].begin(), groups[0].end(), 0);\n        shuffle(groups[0].begin(), groups[0].end(), rng);\n\n        // Split largest splittable group.\n        while (used < budget) {\n            int rem = budget - used;\n            int idx = -1, best = 0;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m >= 2 && m - 1 <= rem && m > best) {\n                    best = m;\n                    idx = g;\n                }\n            }\n            if (idx == -1) break;\n\n            vector<int> cur = groups[idx];\n            int m = (int)cur.size();\n            int pv = cur[uniform_int_distribution<int>(0, m - 1)(rng)];\n\n            vector<int> heavy, equalv, light;\n            equalv.push_back(pv);\n\n            for (int v : cur) {\n                if (v == pv) continue;\n                char c = cmp_and_update(v, pv);\n                if (c == '>') heavy.push_back(v);\n                else if (c == '<') light.push_back(v);\n                else equalv.push_back(v);\n            }\n\n            vector<vector<int>> repl;\n            if (!heavy.empty()) repl.push_back(move(heavy));\n            if (!equalv.empty()) repl.push_back(move(equalv));\n            if (!light.empty()) repl.push_back(move(light));\n\n            groups.erase(groups.begin() + idx);\n            groups.insert(groups.begin() + idx, repl.begin(), repl.end());\n        }\n\n        // Remaining budget: random comparisons, mainly within largest unresolved group.\n        while (used < budget) {\n            int idx = -1, best = 1;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m > best) best = m, idx = g;\n            }\n\n            int a, b;\n            if (idx != -1) {\n                auto& grp = groups[idx];\n                uniform_int_distribution<int> dist(0, (int)grp.size() - 1);\n\n                bool found_unseen = false;\n                for (int t = 0; t < 40; ++t) {\n                    a = grp[dist(rng)];\n                    do b = grp[dist(rng)]; while (b == a);\n                    int x = min(a, b), y = max(a, b);\n                    if (!seen[x][y]) {\n                        found_unseen = true;\n                        break;\n                    }\n                }\n                if (!found_unseen) {\n                    a = grp[dist(rng)];\n                    do b = grp[dist(rng)]; while (b == a);\n                }\n            } else {\n                uniform_int_distribution<int> dist(0, N - 1);\n                a = dist(rng);\n                do b = dist(rng); while (b == a);\n            }\n\n            cmp_and_update(a, b);\n        }\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto& grp : groups) {\n            sort(grp.begin(), grp.end(), [&](int x, int y) {\n                if (score[x] != score[y]) return score[x] > score[y];\n                return x < y;\n            });\n            for (int x : grp) ord.push_back(x);\n        }\n        return ord;\n    }\n\n    void build_est_weight_from_order(const vector<int>& order) {\n        vector<double> H(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) H[i] = H[i - 1] + 1.0 / i;\n\n        w_est.assign(N, 0.0);\n        rank_pos.assign(N, N - 1);\n\n        for (int pos = 0; pos < N; ++pos) {\n            int id = order[pos];\n            rank_pos[id] = pos;\n            // Exponential order-stat expectation shape\n            w_est[id] = H[N] - H[pos];\n        }\n    }\n\n    void init_partition_lpt(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        for (int id : order) {\n            int best = 0;\n            for (int b = 1; b < D; ++b) {\n                if (bin_sum_est[b] < bin_sum_est[best]) best = b;\n            }\n            assign[id] = best;\n            bins[best].push_back(id);\n            bin_sum_est[best] += w_est[id];\n        }\n    }\n\n    void move_item(int item, int to) {\n        int from = assign[item];\n        if (from == to) return;\n\n        auto& vf = bins[from];\n        for (int k = 0; k < (int)vf.size(); ++k) {\n            if (vf[k] == item) {\n                vf[k] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n        bins[to].push_back(item);\n        assign[item] = to;\n\n        bin_sum_est[from] -= w_est[item];\n        bin_sum_est[to] += w_est[item];\n    }\n\n    void swap_items(int i, int j) {\n        int a = assign[i], b = assign[j];\n        if (a == b) return;\n\n        auto& va = bins[a];\n        auto& vb = bins[b];\n        for (int& x : va) if (x == i) { x = j; break; }\n        for (int& x : vb) if (x == j) { x = i; break; }\n\n        assign[i] = b;\n        assign[j] = a;\n\n        double wi = w_est[i], wj = w_est[j];\n        bin_sum_est[a] += wj - wi;\n        bin_sum_est[b] += wi - wj;\n    }\n\n    inline double sq(double x) const { return x * x; }\n\n    void estimated_local_search() {\n        double total = 0.0;\n        for (double w : w_est) total += w;\n        double mean = total / D;\n\n        for (int iter = 0; iter < 300; ++iter) {\n            double best_delta = -1e-12;\n            int best_type = 0;\n            int bi = -1, bj = -1, bb = -1;\n\n            // Move\n            for (int i = 0; i < N; ++i) {\n                int a = assign[i];\n                if ((int)bins[a].size() <= 1) continue; // keep bins non-empty\n                double wi = w_est[i];\n                for (int b = 0; b < D; ++b) {\n                    if (b == a) continue;\n                    double delta =\n                        sq(bin_sum_est[a] - wi - mean) +\n                        sq(bin_sum_est[b] + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        best_type = 1;\n                        bi = i;\n                        bb = b;\n                    }\n                }\n            }\n\n            // Swap\n            for (int i = 0; i < N; ++i) {\n                for (int j = i + 1; j < N; ++j) {\n                    int a = assign[i], b = assign[j];\n                    if (a == b) continue;\n                    double wi = w_est[i], wj = w_est[j];\n                    double delta =\n                        sq(bin_sum_est[a] - wi + wj - mean) +\n                        sq(bin_sum_est[b] - wj + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        best_type = 2;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (best_type == 0) break;\n            if (best_type == 1) move_item(bi, bb);\n            else swap_items(bi, bj);\n        }\n    }\n\n    char cmp_bins(int a, int b) {\n        return ask(bins[a], bins[b]);\n    }\n\n    char cmp_after_move(int h, int l, int x) {\n        vector<int> L;\n        L.reserve(max(0, (int)bins[h].size() - 1));\n        for (int v : bins[h]) if (v != x) L.push_back(v);\n        vector<int> R = bins[l];\n        R.push_back(x);\n        return ask(L, R);\n    }\n\n    void reinsert_bin(vector<int>& ord, int b) {\n        int lo = 0, hi = (int)ord.size();\n        while (lo < hi && used < Q) {\n            int mid = (lo + hi) / 2;\n            char c = cmp_bins(b, ord[mid]);\n            if (c == '>') hi = mid;     // b heavier\n            else lo = mid + 1;\n        }\n        ord.insert(ord.begin() + lo, b);\n    }\n\n    void refine_with_queries() {\n        int rem = Q - used;\n        int sort_cost_bins = insertion_cost(D);\n        if (rem < sort_cost_bins + 18) return;\n\n        // Actual bin order (descending).\n        vector<int> ord;\n        ord.reserve(D);\n        for (int b = 0; b < D; ++b) {\n            reinsert_bin(ord, b);\n            if (used >= Q) return;\n        }\n\n        int guard = 0;\n        while (used < Q && guard < 10000) {\n            ++guard;\n\n            int h = -1;\n            for (int id : ord) {\n                if ((int)bins[id].size() > 1) { h = id; break; }\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int i = (int)ord.size() - 1; i >= 0; --i) {\n                if (ord[i] != h) { l = ord[i]; break; }\n            }\n            if (l == -1) break;\n\n            if (used >= Q) break;\n            char base = cmp_bins(h, l);\n            if (base == '=') break;\n            if (base == '<') swap(h, l); // ensure h heavier\n\n            // Candidate items in h: light -> heavy\n            vector<int> cand = bins[h];\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (rank_pos[a] != rank_pos[b]) return rank_pos[a] > rank_pos[b];\n                return a < b;\n            });\n\n            int m = (int)cand.size();\n            int lo = -1, hi = m; // lo: too light ('>'), hi: heavy enough ('<'/'=')\n            while (hi - lo > 1 && used < Q) {\n                int mid = (lo + hi) / 2;\n                int x = cand[mid];\n                char c = cmp_after_move(h, l, x);\n                if (c == '>') lo = mid;\n                else hi = mid;\n            }\n\n            if (lo == -1 && hi == m) break;\n            int chosen = (lo >= 0 ? cand[lo] : cand[hi]); // safe preference\n\n            move_item(chosen, l);\n\n            auto it = find(ord.begin(), ord.end(), h);\n            if (it != ord.end()) ord.erase(it);\n            it = find(ord.begin(), ord.end(), l);\n            if (it != ord.end()) ord.erase(it);\n\n            reinsert_bin(ord, h);\n            if (used >= Q) break;\n            reinsert_bin(ord, l);\n        }\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_single(0, 1);\n        }\n    }\n\n    void solve() {\n        if (!(cin >> N >> D >> Q)) return;\n\n        int full_cost = insertion_cost(N);\n        vector<int> order;\n\n        if (Q >= full_cost) order = full_sort_items();\n        else order = partial_rank_budget(Q);\n\n        if ((int)order.size() != N) {\n            vector<int> seen(N, 0);\n            for (int x : order) if (0 <= x && x < N) seen[x] = 1;\n            for (int i = 0; i < N; ++i) if (!seen[i]) order.push_back(i);\n        }\n\n        build_est_weight_from_order(order);\n        init_partition_lpt(order);\n        estimated_local_search();\n\n        if (Q >= full_cost) refine_with_queries();\n\n        fill_dummy_queries();\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << assign[i];\n        }\n        cout << '\\n';\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 200;\nconstexpr int MAXM = 10;\nconstexpr long long INF64 = (1LL << 60);\n\nstruct Params {\n    int w_cross;\n    int w_near;\n    int near_th;\n    int w_height;\n    int w_top;\n    int w_empty;\n    int w_boundary;\n    int horizon;\n};\n\nstruct State {\n    int len[MAXM];\n    int box[MAXM][MAXN]; // bottom -> top\n};\n\nstruct SegmentStats {\n    int total;\n    int segBottom;\n    int pref[MAXN + 1];\n};\n\nstruct Result {\n    long long energy = INF64;\n    vector<pair<int, int>> ops;\n    Params param{};\n};\n\ninline pair<int, int> find_box(const State& st, int m, int target) {\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < st.len[i]; ++j) {\n            if (st.box[i][j] == target) return {i, j};\n        }\n    }\n    return {-1, -1};\n}\n\ninline void move_segment(State& st, int src, int start, int dst) {\n    int k = st.len[src] - start;\n    for (int t = 0; t < k; ++t) {\n        st.box[dst][st.len[dst] + t] = st.box[src][start + t];\n    }\n    st.len[dst] += k;\n    st.len[src] = start;\n}\n\ninline SegmentStats build_segment_stats(const State& st, int n, int src, int start) {\n    SegmentStats ss{};\n    ss.total = st.len[src] - start;\n    ss.segBottom = st.box[src][start];\n\n    int freq[MAXN + 1];\n    fill(freq, freq + MAXN + 1, 0);\n    for (int i = start; i < st.len[src]; ++i) {\n        ++freq[st.box[src][i]];\n    }\n\n    ss.pref[0] = 0;\n    for (int v = 1; v <= n; ++v) ss.pref[v] = ss.pref[v - 1] + freq[v];\n    return ss;\n}\n\ninline long long heuristic_dest_score(\n    const State& st, int dst, int x,\n    const Params& p, const SegmentStats& ss\n) {\n    long long cross = 0;\n    long long near = 0;\n\n    for (int j = 0; j < st.len[dst]; ++j) {\n        int z = st.box[dst][j];\n        int cnt = ss.total - ss.pref[z]; // #moved boxes > z\n        if (cnt <= 0) continue;\n        cross += cnt;\n        int delta = z - x;\n        if (delta <= p.near_th) {\n            near += 1LL * cnt * (p.near_th + 1 - delta);\n        }\n    }\n\n    long long score = 0;\n    score += 1LL * p.w_cross * cross;\n    score += 1LL * p.w_near * near;\n    score += 1LL * p.w_height * st.len[dst];\n\n    if (st.len[dst] == 0) {\n        score -= p.w_empty;\n    } else {\n        int top = st.box[dst][st.len[dst] - 1];\n        score -= 1LL * p.w_top * top;\n        if (ss.segBottom > top) {\n            score += 1LL * p.w_boundary * (ss.segBottom - top);\n        }\n    }\n    return score;\n}\n\ninline int choose_dest(\n    const State& st, int n, int m,\n    int src, int start, int x, const Params& p\n) {\n    SegmentStats ss = build_segment_stats(st, n, src, start);\n\n    long long bestScore = INF64;\n    int bestD = -1;\n    for (int d = 0; d < m; ++d) {\n        if (d == src) continue;\n        long long sc = heuristic_dest_score(st, d, x, p, ss);\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestD = d;\n        } else if (sc == bestScore) {\n            if (bestD == -1 || st.len[d] < st.len[bestD] || (st.len[d] == st.len[bestD] && d < bestD)) {\n                bestD = d;\n            }\n        }\n    }\n    return bestD;\n}\n\nlong long rollout_energy(\n    State st, int n, int m,\n    int nextBox, int steps, const Params& p\n) {\n    long long energy = 0;\n\n    for (int t = 0; t < steps && nextBox <= n; ++t, ++nextBox) {\n        auto [s, pos] = find_box(st, m, nextBox);\n        if (s < 0) break; // should not happen\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int d = choose_dest(st, n, m, s, start, nextBox, p);\n            move_segment(st, s, start, d);\n            energy += k + 1;\n        }\n        st.len[s]--; // pop nextBox\n    }\n    return energy;\n}\n\nResult solve_with_params(const State& init, int n, int m, const Params& p) {\n    State st = init;\n\n    Result res;\n    res.energy = 0;\n    res.ops.reserve(600);\n    res.param = p;\n\n    for (int x = 1; x <= n; ++x) {\n        auto [s, pos] = find_box(st, m, x);\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int bestDest = -1;\n\n            if (p.horizon <= 1) {\n                bestDest = choose_dest(st, n, m, s, start, x, p);\n            } else {\n                SegmentStats ss = build_segment_stats(st, n, s, start);\n                long long bestEst = INF64;\n                long long bestHScore = INF64;\n\n                for (int d = 0; d < m; ++d) {\n                    if (d == s) continue;\n\n                    State tmp = st;\n                    move_segment(tmp, s, start, d);\n                    tmp.len[s]--; // pop x\n                    int steps = min(p.horizon - 1, n - x);\n                    long long est = 1LL * (k + 1) + rollout_energy(tmp, n, m, x + 1, steps, p);\n\n                    long long hscore = heuristic_dest_score(st, d, x, p, ss);\n\n                    if (est < bestEst ||\n                        (est == bestEst && hscore < bestHScore) ||\n                        (est == bestEst && hscore == bestHScore && d < bestDest)) {\n                        bestEst = est;\n                        bestHScore = hscore;\n                        bestDest = d;\n                    }\n                }\n            }\n\n            int v = st.box[s][start];\n            move_segment(st, s, start, bestDest);\n            res.energy += k + 1;\n            res.ops.push_back({v, bestDest + 1});\n        }\n\n        st.len[s]--; // pop x\n        res.ops.push_back({x, 0});\n    }\n\n    return res;\n}\n\nParams mutate_params(const Params& base, const vector<Params>& presets, mt19937& rng) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    Params p = base;\n\n    if (rnd(0, 4) == 0) {\n        p = presets[rnd(0, (int)presets.size() - 1)];\n    }\n\n    if (rnd(0, 9) == 0) {\n        p.w_cross    = rnd(500, 2000);\n        p.w_near     = rnd(0, 100);\n        p.near_th    = rnd(8, 55);\n        p.w_height   = rnd(-3, 15);\n        p.w_top      = rnd(0, 12);\n        p.w_empty    = rnd(200, 3500);\n        p.w_boundary = rnd(0, 80);\n        p.horizon    = rnd(1, 24);\n        return p;\n    }\n\n    p.w_cross    = clamp(p.w_cross + rnd(-250, 250), 400, 2200);\n    p.w_near     = clamp(p.w_near + rnd(-20, 20), 0, 120);\n    p.near_th    = clamp(p.near_th + rnd(-8, 8), 5, 70);\n    p.w_height   = clamp(p.w_height + rnd(-3, 3), -5, 20);\n    p.w_top      = clamp(p.w_top + rnd(-3, 3), 0, 20);\n    p.w_empty    = clamp(p.w_empty + rnd(-400, 400), 0, 5000);\n    p.w_boundary = clamp(p.w_boundary + rnd(-12, 12), 0, 120);\n    p.horizon    = clamp(p.horizon + rnd(-3, 3), 1, 24);\n\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n, m;\n    cin >> n >> m;\n\n    State init{};\n    for (int i = 0; i < MAXM; ++i) init.len[i] = 0;\n\n    int h = n / m;\n    uint64_t seed = 1469598103934665603ULL;\n\n    for (int i = 0; i < m; ++i) {\n        init.len[i] = h;\n        for (int j = 0; j < h; ++j) {\n            cin >> init.box[i][j];\n            seed ^= (uint64_t)init.box[i][j] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    vector<Params> presets = {\n        {1000, 10, 20, 1, 1,  800, 10,  1},\n        {1000, 20, 24, 2, 1, 1200, 15,  8},\n        {1050, 30, 28, 2, 2, 1500, 20, 12},\n        {1100, 35, 32, 3, 2, 1700, 25, 16},\n        { 900, 45, 20, 1, 3, 1300, 15, 16},\n        {1200, 25, 40, 4, 1, 2000, 30, 20},\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    Result best;\n    best.energy = INF64;\n\n    // Deterministic presets\n    for (const auto& p : presets) {\n        Result r = solve_with_params(init, n, m, p);\n        if (r.energy < best.energy || (r.energy == best.energy && r.ops.size() < best.ops.size())) {\n            best = move(r);\n        }\n    }\n\n    // Small random parameter search under safe budget\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n    const double TIME_BUDGET = 1.65; // keep margin for 2.0 sec limit\n\n    while (elapsed() < TIME_BUDGET) {\n        Params cand = mutate_params(best.param, presets, rng);\n        Result r = solve_with_params(init, n, m, cand);\n        if (r.energy < best.energy || (r.energy == best.energy && r.ops.size() < best.ops.size())) {\n            best = move(r);\n        }\n    }\n\n    for (auto [v, i] : best.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Metric {\n    long long total = 0;\n    int L = 0;\n    bool valid = false;\n};\n\nclass Solver {\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void read_input() {\n        cin >> N;\n        hWall.resize(N - 1);\n        for (int i = 0; i < N - 1; i++) cin >> hWall[i];\n        vWall.resize(N);\n        for (int i = 0; i < N; i++) cin >> vWall[i];\n\n        V = N * N;\n        dirt.resize(V);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int x;\n                cin >> x;\n                dirt[i * N + j] = x;\n            }\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        build_graph();\n        precompute_apsp();\n\n        firstVisit.assign(V, -1);\n        prevVisit.assign(V, -1);\n        tri.assign(V, 0LL);\n\n        logd.resize(V);\n        for (int i = 0; i < V; i++) logd[i] = log(1.0 + (double)dirt[i]);\n\n        string dfsRoute = build_dfs_route();\n        Metric bestM = evaluate(dfsRoute);\n        string bestRoute = dfsRoute;\n\n        // ---- Phase 0: initial route sampling ----\n        const double T_INIT = 0.25;\n        int trial = 0;\n        while (elapsed() < T_INIT) {\n            double a, b, g;\n            switch (trial % 7) {\n                case 0: a = 0.2; b = 1.6; g = 0.0; break;\n                case 1: a = 0.8; b = 1.3; g = 0.1; break;\n                case 2: a = 1.2; b = 1.0; g = 0.2; break;\n                case 3: a = 1.6; b = 0.8; g = 0.3; break;\n                default:\n                    a = rnd01() * 1.8;\n                    b = 0.5 + rnd01() * 1.8;\n                    g = rnd01() * 0.5;\n                    break;\n            }\n\n            string r = build_random_route(a, b, g);\n            if (!r.empty()) {\n                Metric m = evaluate(r);\n                if (better(m, bestM)) {\n                    bestM = m;\n                    bestRoute = std::move(r);\n                }\n            }\n            trial++;\n        }\n\n        string curRoute = bestRoute;\n        Metric curM = bestM;\n\n        const int MAXLEN = 40000;\n\n        // ---- Phase 1: deterministic gap-driven insertion ----\n        const double T_INS = 1.00;\n        while (elapsed() < T_INS) {\n            if (!improve_gap_once(curRoute, curM, T_INS, MAXLEN)) break;\n        }\n\n        // High-d candidate list\n        vector<int> highIds(V);\n        iota(highIds.begin(), highIds.end(), 0);\n        sort(highIds.begin(), highIds.end(), [&](int a, int b) {\n            if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n            return a < b;\n        });\n        if ((int)highIds.size() > 450) highIds.resize(450);\n\n        vector<int> pos = decode_positions(curRoute);\n        if (pos.empty()) {\n            curRoute = dfsRoute;\n            curM = evaluate(curRoute);\n            pos = decode_positions(curRoute);\n        }\n        vector<int> cnt = build_counts(pos);\n\n        // ---- Phase 2: random local search (insert/remove/shortcut) ----\n        const double T_RAND = 1.70;\n        while (elapsed() < T_RAND) {\n            string cand;\n            bool made = false;\n\n            int op = (int)(rng() % 100);\n            if (op < 48) {\n                made = make_random_loop_insert(curRoute, pos, highIds, cand, MAXLEN);\n            } else if (op < 72) {\n                made = make_random_edge_insert(curRoute, pos, highIds, cand, MAXLEN);\n            } else if (op < 88) {\n                made = make_random_loop_remove(curRoute, pos, cnt, cand);\n            } else {\n                made = make_random_shortcut(curRoute, pos, cnt, cand);\n            }\n\n            if (!made) continue;\n\n            Metric m = evaluate(cand);\n            if (better(m, curM)) {\n                curRoute.swap(cand);\n                curM = m;\n                pos = decode_positions(curRoute);\n                if (pos.empty()) break;\n                cnt = build_counts(pos);\n            }\n        }\n\n        // ---- Phase 3: final deterministic polish ----\n        const double T_FINAL = 1.85;\n        while (elapsed() < T_FINAL) {\n            if (!improve_gap_once(curRoute, curM, T_FINAL, MAXLEN)) break;\n        }\n\n        Metric fin = evaluate(curRoute);\n        if (!fin.valid || (int)curRoute.size() > 100000) {\n            curRoute = dfsRoute; // guaranteed fallback\n        }\n\n        cout << curRoute << '\\n';\n    }\n\nprivate:\n    int N = 0, V = 0;\n    vector<string> hWall, vWall;\n    vector<int> dirt;\n    vector<double> logd;\n\n    vector<int> row, col;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> nxtMove; // U D L R\n\n    vector<vector<int16_t>> distMat, nextHop;\n    int dirMap[256]{};\n\n    vector<int> firstVisit, prevVisit;\n    vector<long long> tri;\n\n    mt19937_64 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    double rnd01() {\n        return (rng() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    void build_graph() {\n        fill(begin(dirMap), end(dirMap), -1);\n        dirMap[(unsigned char)'U'] = 0;\n        dirMap[(unsigned char)'D'] = 1;\n        dirMap[(unsigned char)'L'] = 2;\n        dirMap[(unsigned char)'R'] = 3;\n\n        row.resize(V);\n        col.resize(V);\n        adj.assign(V, {});\n        nxtMove.assign(V, array<int, 4>{-1, -1, -1, -1});\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                row[id] = i;\n                col[id] = j;\n\n                if (i > 0 && hWall[i - 1][j] == '0') {\n                    int to = (i - 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][0] = to;\n                }\n                if (i + 1 < N && hWall[i][j] == '0') {\n                    int to = (i + 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][1] = to;\n                }\n                if (j > 0 && vWall[i][j - 1] == '0') {\n                    int to = i * N + (j - 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][2] = to;\n                }\n                if (j + 1 < N && vWall[i][j] == '0') {\n                    int to = i * N + (j + 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][3] = to;\n                }\n            }\n        }\n    }\n\n    void precompute_apsp() {\n        const int16_t INF = 30000;\n        distMat.assign(V, vector<int16_t>(V, INF));\n        nextHop.assign(V, vector<int16_t>(V, -1));\n\n        vector<int> q(V);\n\n        for (int s = 0; s < V; s++) {\n            auto &ds = distMat[s];\n            auto &ns = nextHop[s];\n            fill(ds.begin(), ds.end(), INF);\n            fill(ns.begin(), ns.end(), -1);\n\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            ds[s] = 0;\n            ns[s] = s;\n\n            while (head < tail) {\n                int u = q[head++];\n                for (int v : adj[u]) {\n                    if (ds[v] != INF) continue;\n                    ds[v] = ds[u] + 1;\n                    ns[v] = (u == s ? v : ns[u]);\n                    q[tail++] = v;\n                }\n            }\n        }\n    }\n\n    char dir_between(int u, int v) const {\n        if (row[v] == row[u] - 1) return 'U';\n        if (row[v] == row[u] + 1) return 'D';\n        if (col[v] == col[u] - 1) return 'L';\n        return 'R';\n    }\n\n    char opposite(char c) const {\n        if (c == 'U') return 'D';\n        if (c == 'D') return 'U';\n        if (c == 'L') return 'R';\n        return 'L';\n    }\n\n    string path_between(int a, int b) const {\n        if (a == b) return \"\";\n        string p;\n        int u = a;\n        int guard = 0;\n        while (u != b) {\n            int v = (int)nextHop[u][b];\n            if (v < 0 || v == u) return \"\";\n            p.push_back(dir_between(u, v));\n            u = v;\n            if (++guard > 500000) return \"\";\n        }\n        return p;\n    }\n\n    string roundtrip_detour(int a, int target) const {\n        if (a == target) return \"\";\n        string fwd = path_between(a, target);\n        if (fwd.empty()) return \"\";\n        string det = fwd;\n        for (int i = (int)fwd.size() - 1; i >= 0; i--) det.push_back(opposite(fwd[i]));\n        return det;\n    }\n\n    vector<int> decode_positions(const string &route) const {\n        int L = (int)route.size();\n        vector<int> pos(L + 1);\n        int cur = 0;\n        pos[0] = 0;\n        for (int i = 0; i < L; i++) {\n            int d = dirMap[(unsigned char)route[i]];\n            if (d < 0) return {};\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return {};\n            cur = nx;\n            pos[i + 1] = cur;\n        }\n        return pos;\n    }\n\n    vector<int> build_counts(const vector<int> &pos) const {\n        vector<int> cnt(V, 0);\n        for (int i = 1; i < (int)pos.size(); i++) cnt[pos[i]]++;\n        return cnt;\n    }\n\n    Metric evaluate(const string &route) {\n        int L = (int)route.size();\n        if (L <= 0 || L > 100000) return Metric{0, L, false};\n\n        fill(firstVisit.begin(), firstVisit.end(), -1);\n        fill(prevVisit.begin(), prevVisit.end(), -1);\n        fill(tri.begin(), tri.end(), 0LL);\n\n        int cur = 0;\n        for (int t = 1; t <= L; t++) {\n            int d = dirMap[(unsigned char)route[t - 1]];\n            if (d < 0) return Metric{0, L, false};\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return Metric{0, L, false};\n            cur = nx;\n\n            if (prevVisit[cur] != -1) {\n                long long delta = t - prevVisit[cur];\n                tri[cur] += delta * (delta - 1) / 2;\n            } else {\n                firstVisit[cur] = t;\n            }\n            prevVisit[cur] = t;\n        }\n\n        if (cur != 0) return Metric{0, L, false};\n\n        long long total = 0;\n        for (int v = 0; v < V; v++) {\n            if (prevVisit[v] == -1) return Metric{0, L, false};\n            long long delta = (long long)firstVisit[v] + L - prevVisit[v];\n            tri[v] += delta * (delta - 1) / 2;\n            total += tri[v] * (long long)dirt[v];\n        }\n\n        return Metric{total, L, true};\n    }\n\n    bool better(const Metric &a, const Metric &b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        __int128 lhs = (__int128)a.total * b.L;\n        __int128 rhs = (__int128)b.total * a.L;\n        if (lhs != rhs) return lhs < rhs;\n        return a.L < b.L;\n    }\n\n    string build_dfs_route() {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            vector<int> nbs = adj[u];\n            sort(nbs.begin(), nbs.end(), [&](int x, int y) {\n                if (dirt[x] != dirt[y]) return dirt[x] > dirt[y];\n                return x < y;\n            });\n            for (int v : nbs) {\n                if (vis[v]) continue;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_random_route(double alpha, double beta, double gamma) {\n        vector<char> vis(V, 0);\n        vis[0] = 1;\n        int rem = V - 1;\n        int cur = 0;\n\n        string route;\n        route.reserve(V * 3);\n\n        while (rem > 0) {\n            if ((int)route.size() > 90000) return \"\";\n\n            int bestN = -1;\n            double bestS = -1e100;\n\n            for (int nb : adj[cur]) {\n                if (vis[nb]) continue;\n                int onward = 0;\n                for (int nb2 : adj[nb]) if (!vis[nb2]) onward++;\n                double sc = alpha * logd[nb] - beta * onward + rnd01() * 0.02;\n                if (sc > bestS) {\n                    bestS = sc;\n                    bestN = nb;\n                }\n            }\n\n            if (bestN != -1) {\n                route.push_back(dir_between(cur, bestN));\n                cur = bestN;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                continue;\n            }\n\n            int target = -1;\n            double bestVal = 1e100;\n            for (int v = 0; v < V; v++) {\n                if (vis[v]) continue;\n                int dd = (int)distMat[cur][v];\n                double val = (double)dd - gamma * logd[v] + rnd01() * 0.03;\n                if (val < bestVal) {\n                    bestVal = val;\n                    target = v;\n                }\n            }\n            if (target < 0) return \"\";\n\n            while (cur != target) {\n                int nx = (int)nextHop[cur][target];\n                if (nx < 0 || nx == cur) return \"\";\n                route.push_back(dir_between(cur, nx));\n                cur = nx;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                if ((int)route.size() > 90000) return \"\";\n            }\n        }\n\n        while (cur != 0) {\n            int nx = (int)nextHop[cur][0];\n            if (nx < 0 || nx == cur) return \"\";\n            route.push_back(dir_between(cur, nx));\n            cur = nx;\n            if ((int)route.size() > 90000) return \"\";\n        }\n\n        return route;\n    }\n\n    string insert_detour(const string &route, int t, const string &det) const {\n        string out;\n        out.reserve(route.size() + det.size());\n        out.append(route, 0, t);\n        out += det;\n        out.append(route, t, route.size() - t);\n        return out;\n    }\n\n    string remove_segment(const string &route, int l, int len) const {\n        string out;\n        out.reserve(route.size() - len);\n        out.append(route, 0, l);\n        out.append(route, l + len, route.size() - (l + len));\n        return out;\n    }\n\n    string replace_segment(const string &route, int l, int r, const string &rep) const {\n        string out;\n        out.reserve(route.size() - (r - l) + rep.size());\n        out.append(route, 0, l);\n        out += rep;\n        out.append(route, r, route.size() - r);\n        return out;\n    }\n\n    static void add_delta_small(vector<int> &ids, vector<int> &delta, int v, int add) {\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (ids[i] == v) {\n                delta[i] += add;\n                return;\n            }\n        }\n        ids.push_back(v);\n        delta.push_back(add);\n    }\n\n    bool can_remove_closed(const vector<int> &pos, const vector<int> &cnt, int l, int r) const {\n        vector<int> ids, delta;\n        ids.reserve(r - l);\n        delta.reserve(r - l);\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool can_replace_segment(\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        int l, int r,\n        const string &rep\n    ) const {\n        vector<int> ids, delta;\n        ids.reserve((r - l) + (int)rep.size() + 4);\n        delta.reserve((r - l) + (int)rep.size() + 4);\n\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n\n        int cur = pos[l];\n        for (char c : rep) {\n            int d = dirMap[(unsigned char)c];\n            if (d < 0) return false;\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return false;\n            cur = nx;\n            add_delta_small(ids, delta, cur, +1);\n        }\n        if (cur != pos[r]) return false;\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool improve_gap_once(string &route, Metric &curM, double timeLimit, int maxLen) {\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n\n        int L = (int)route.size();\n        vector<int> first(V, -1), last(V, -1), maxGap(V, 0), gapStart(V, 0);\n\n        for (int t = 1; t <= L; t++) {\n            int v = pos[t];\n            if (first[v] == -1) {\n                first[v] = last[v] = t;\n            } else {\n                int g = t - last[v];\n                if (g > maxGap[v]) {\n                    maxGap[v] = g;\n                    gapStart[v] = last[v];\n                }\n                last[v] = t;\n            }\n        }\n        for (int v = 0; v < V; v++) {\n            int g = first[v] + L - last[v];\n            if (g > maxGap[v]) {\n                maxGap[v] = g;\n                gapStart[v] = last[v];\n            }\n        }\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(V);\n        for (int v = 0; v < V; v++) {\n            if (maxGap[v] <= 2) continue;\n            long long g = maxGap[v];\n            long long pot = 1LL * dirt[v] * g * g;\n            ord.push_back({pot, v});\n        }\n        if (ord.empty()) return false;\n\n        sort(ord.begin(), ord.end(), greater<pair<long long, int>>());\n        int M = min((int)ord.size(), 140);\n\n        struct Cand {\n            double est;\n            int v;\n            int t;\n        };\n        vector<Cand> cands;\n        cands.reserve(M * 7);\n\n        static const int nums[7] = {1, 2, 3, 4, 5, 6, 7};\n\n        for (int i = 0; i < M; i++) {\n            int v = ord[i].second;\n            long long pot = ord[i].first;\n            int g = maxGap[v];\n            int s = gapStart[v];\n\n            int dyn = max(8, min(100, g / 2 + 5));\n\n            for (int z = 0; z < 7; z++) {\n                int t = (int)((s + (long long)g * nums[z] / 8) % L);\n                int a = pos[t];\n                int dd = (int)distMat[a][v];\n                if (dd <= 0 || dd > dyn) continue;\n                int add = 2 * dd;\n                if (L + add > maxLen) continue;\n\n                double est = (double)pot / (add + 1.0);\n                cands.push_back({est, v, t});\n            }\n        }\n\n        if (cands.empty()) return false;\n        sort(cands.begin(), cands.end(), [](const Cand &x, const Cand &y) {\n            return x.est > y.est;\n        });\n        if ((int)cands.size() > 70) cands.resize(70);\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (const auto &c : cands) {\n            if (elapsed() >= timeLimit) break;\n            int a = pos[c.t];\n            string det = roundtrip_detour(a, c.v);\n            if (det.empty()) continue;\n            string cand = insert_detour(route, c.t, det);\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\n    }\n\n    int pick_target_near_anchor(int anchor, const vector<int> &highIds, int maxDist) {\n        int H = (int)highIds.size();\n        if (H == 0) return -1;\n\n        int best = -1;\n        double bestScore = -1e100;\n\n        int tries = 26;\n        for (int it = 0; it < tries; it++) {\n            int x;\n            if ((rng() % 100) < 85) {\n                x = highIds[(int)(rng() % H)];\n            } else {\n                x = (int)(rng() % V);\n            }\n            int dd = (int)distMat[anchor][x];\n            if (dd <= 0 || dd > maxDist) continue;\n            double sc = (double)dirt[x] / dd + rnd01() * 0.05;\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = x;\n            }\n        }\n        return best;\n    }\n\n    bool make_random_loop_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L >= maxLen) return false;\n\n        int t = (int)(rng() % (L + 1));\n        int a = pos[t];\n\n        int maxDist = 6 + (int)(rng() % 15); // 6..20\n        int x = pick_target_near_anchor(a, highIds, maxDist);\n        if (x < 0) return false;\n\n        int dd = (int)distMat[a][x];\n        if (dd <= 0) return false;\n        if (L + 2 * dd > maxLen) return false;\n\n        string det = roundtrip_detour(a, x);\n        if (det.empty()) return false;\n\n        cand = insert_detour(route, t, det);\n        return true;\n    }\n\n    bool make_random_edge_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L <= 0 || L >= maxLen) return false;\n\n        int t = (int)(rng() % L);\n        int u = pos[t];\n        int w = pos[t + 1];\n\n        int H = (int)highIds.size();\n        if (H == 0) return false;\n\n        int bestX = -1;\n        double bestVal = -1e100;\n        int bestD1 = 0, bestD2 = 0;\n\n        int maxVia = 10 + (int)(rng() % 18); // 10..27\n        for (int it = 0; it < 30; it++) {\n            int x;\n            if ((rng() % 100) < 90) {\n                x = highIds[(int)(rng() % H)];\n            } else {\n                x = (int)(rng() % V);\n            }\n\n            int d1 = (int)distMat[u][x];\n            int d2 = (int)distMat[x][w];\n            int via = d1 + d2;\n            if (via > maxVia) continue;\n            int add = via - 1;\n            if (add <= 0) continue;\n            if (L + add > maxLen) continue;\n\n            double val = (double)dirt[x] / add + rnd01() * 0.03;\n            if (val > bestVal) {\n                bestVal = val;\n                bestX = x;\n                bestD1 = d1;\n                bestD2 = d2;\n            }\n        }\n\n        if (bestX < 0) return false;\n\n        string p1 = (bestD1 == 0 ? \"\" : path_between(u, bestX));\n        string p2 = (bestD2 == 0 ? \"\" : path_between(bestX, w));\n        if ((bestD1 > 0 && p1.empty()) || (bestD2 > 0 && p2.empty())) return false;\n\n        string rep = p1 + p2;\n        if ((int)rep.size() <= 1) return false; // no real insertion\n\n        cand = replace_segment(route, t, t + 1, rep);\n        return true;\n    }\n\n    bool make_random_loop_remove(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        int maxLen = min(90, L);\n        if (maxLen < 2) return false;\n\n        int len = 2 + (int)(rng() % (maxLen - 1)); // 2..maxLen\n        int l = (int)(rng() % (L - len + 1));\n        int r = l + len;\n\n        if (pos[l] != pos[r]) return false;\n        if (!can_remove_closed(pos, cnt, l, r)) return false;\n\n        cand = remove_segment(route, l, len);\n        return true;\n    }\n\n    bool make_random_shortcut(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        int maxSpan = min(70, L);\n        if (maxSpan < 3) return false;\n\n        int span = 3 + (int)(rng() % (maxSpan - 2)); // 3..maxSpan\n        int l = (int)(rng() % (L - span + 1));\n        int r = l + span;\n\n        int u = pos[l];\n        int v = pos[r];\n        int p = (int)distMat[u][v];\n        if (p <= 0 || p >= span) return false;\n\n        string rep = path_between(u, v);\n        if ((int)rep.size() != p) return false;\n        if ((int)rep.size() >= span) return false;\n\n        if (!can_replace_segment(pos, cnt, l, r, rep)) return false;\n\n        cand = replace_segment(route, l, r, rep);\n        return true;\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}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % (uint64_t)n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct Solver {\n    static constexpr int INF = 1e9;\n\n    int N{}, M{}, V{};\n    int si{}, sj{}, startId{};\n    vector<string> board;\n    vector<string> words;\n\n    array<vector<int>, 26> occ{};\n    int distMat[225][225]{};\n\n    vector<vector<int>> ov; // overlap [0..4]\n\n    vector<int> lastChar;\n    vector<int> nEnd;\n\n    // exact evaluator precompute\n    vector<vector<int>> firstEndCost; // first word from start -> each end-index\n    vector<size_t> transOffset;       // offset for pair (a,b): transOffset[a*M+b]\n    vector<int> transData;            // flattened matrices: [nEnd[a] x nEnd[b]]\n\n    // approximate objective (from exact transition minima)\n    vector<int> startCostApprox;\n    vector<vector<int>> edgeApprox;\n\n    chrono::steady_clock::time_point t0;\n    XorShift64 rng{};\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n        words.resize(M);\n        for (int i = 0; i < M; i++) cin >> words[i];\n        V = N * N;\n        startId = si * N + sj;\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t h = 1469598103934665603ull;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto &r : board) for (char c : r) mix((uint64_t)c);\n        for (auto &w : words) for (char c : w) mix((uint64_t)c);\n        return h;\n    }\n\n    void computeOccAndDist() {\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 a = 0; a < V; a++) {\n            int ra = a / N, ca = a % N;\n            for (int b = 0; b < V; b++) {\n                int rb = b / N, cb = b % N;\n                distMat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n    }\n\n    void computeOverlap() {\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int best = 0;\n                for (int k = 4; k >= 0; k--) {\n                    bool ok = true;\n                    for (int x = 0; x < k; x++) {\n                        if (words[i][5 - k + x] != words[j][x]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (ok) {\n                        best = k;\n                        break;\n                    }\n                }\n                ov[i][j] = best;\n            }\n        }\n    }\n\n    // Type words[w][begin..4] from single startCell.\n    // Output costs for each end cell in occ[lastChar[w]] order.\n    void endCostsSingleStartRaw(int startCell, int w, int begin, int* out) const {\n        int prevId[225], nextId[225];\n        int prevCost[225], nextCost[225];\n\n        int ps = 1;\n        prevId[0] = startCell;\n        prevCost[0] = 0;\n\n        for (int pos = begin; pos < 5; pos++) {\n            const vector<int>& cells = occ[words[w][pos] - 'A'];\n            int ns = (int)cells.size();\n\n            for (int ni = 0; ni < ns; ni++) {\n                int q = cells[ni];\n                int best = INF;\n                for (int pi = 0; pi < ps; pi++) {\n                    int p = prevId[pi];\n                    int cand = prevCost[pi] + distMat[p][q] + 1;\n                    if (cand < best) best = cand;\n                }\n                nextId[ni] = q;\n                nextCost[ni] = best;\n            }\n\n            ps = ns;\n            for (int i = 0; i < ps; i++) {\n                prevId[i] = nextId[i];\n                prevCost[i] = nextCost[i];\n            }\n        }\n\n        for (int i = 0; i < ps; i++) out[i] = prevCost[i];\n    }\n\n    void preprocessTransitionsAndApprox() {\n        lastChar.resize(M);\n        nEnd.resize(M);\n        for (int w = 0; w < M; w++) {\n            lastChar[w] = words[w][4] - 'A';\n            nEnd[w] = (int)occ[lastChar[w]].size();\n        }\n\n        firstEndCost.assign(M, {});\n        startCostApprox.assign(M, INF);\n        edgeApprox.assign(M, vector<int>(M, INF));\n\n        // first-word exact costs from initial finger\n        for (int w = 0; w < M; w++) {\n            firstEndCost[w].resize(nEnd[w]);\n            endCostsSingleStartRaw(startId, w, 0, firstEndCost[w].data());\n            int mn = INF;\n            for (int v : firstEndCost[w]) mn = min(mn, v);\n            startCostApprox[w] = mn;\n        }\n\n        // offsets\n        transOffset.assign((size_t)M * M + 1, 0);\n        size_t total = 0;\n        for (int a = 0; a < M; a++) {\n            for (int b = 0; b < M; b++) {\n                size_t id = (size_t)a * M + b;\n                total += (size_t)nEnd[a] * nEnd[b];\n                transOffset[id + 1] = total;\n            }\n        }\n        transData.assign(total, INF);\n\n        // pair transitions + approximate edge minima\n        int row[225];\n        for (int a = 0; a < M; a++) {\n            const vector<int>& starts = occ[lastChar[a]];\n            int na = nEnd[a];\n\n            for (int b = 0; b < M; b++) {\n                int nb = nEnd[b];\n                size_t id = (size_t)a * M + b;\n                size_t off = transOffset[id];\n                int begin = ov[a][b];\n\n                int mn = INF;\n                for (int si = 0; si < na; si++) {\n                    endCostsSingleStartRaw(starts[si], b, begin, row);\n                    size_t base = off + (size_t)si * nb;\n                    for (int tj = 0; tj < nb; tj++) {\n                        int v = row[tj];\n                        transData[base + tj] = v;\n                        if (v < mn) mn = v;\n                    }\n                }\n                edgeApprox[a][b] = mn;\n            }\n        }\n    }\n\n    void preprocess() {\n        computeOccAndDist();\n        computeOverlap();\n        preprocessTransitionsAndApprox();\n    }\n\n    long long approxCost(const vector<int>& perm) const {\n        long long c = startCostApprox[perm[0]];\n        for (int i = 1; i < M; i++) c += edgeApprox[perm[i - 1]][perm[i]];\n        return c;\n    }\n\n    inline long long edgeContrib(int from, int to) const {\n        if (to < 0) return 0;\n        if (from < 0) return startCostApprox[to];\n        return edgeApprox[from][to];\n    }\n\n    long long deltaSwapApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int cand[4] = {i, i + 1, j, j + 1};\n        int pos[4];\n        int npos = 0;\n        for (int z = 0; z < 4; z++) {\n            int t = cand[z];\n            if (t < 0 || t >= M) continue;\n            bool ex = false;\n            for (int k = 0; k < npos; k++) if (pos[k] == t) { ex = true; break; }\n            if (!ex) pos[npos++] = t;\n        }\n\n        auto getNew = [&](int idx) -> int {\n            if (idx == i) return p[j];\n            if (idx == j) return p[i];\n            return p[idx];\n        };\n\n        long long oldc = 0, newc = 0;\n        for (int k = 0; k < npos; k++) {\n            int t = pos[k];\n\n            int toOld = p[t];\n            int fromOld = (t == 0 ? -1 : p[t - 1]);\n            oldc += edgeContrib(fromOld, toOld);\n\n            int toNew = getNew(t);\n            int fromNew = (t == 0 ? -1 : getNew(t - 1));\n            newc += edgeContrib(fromNew, toNew);\n        }\n        return newc - oldc;\n    }\n\n    long long deltaRelocateApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        int x = p[i];\n\n        if (i < j) {\n            int a = (i > 0 ? p[i - 1] : -1);\n            int b = p[i + 1]; // exists\n            int c = p[j];\n            int d = (j + 1 < M ? p[j + 1] : -1);\n\n            long long oldc = edgeContrib(a, x) + edgeContrib(x, b) + edgeContrib(c, d);\n            long long newc = edgeContrib(a, b) + edgeContrib(c, x) + edgeContrib(x, d);\n            return newc - oldc;\n        } else {\n            int a = p[i - 1];\n            int b = (i + 1 < M ? p[i + 1] : -1);\n            int c = (j > 0 ? p[j - 1] : -1);\n            int d = p[j];\n\n            long long oldc = edgeContrib(c, d) + edgeContrib(a, x) + edgeContrib(x, b);\n            long long newc = edgeContrib(c, x) + edgeContrib(x, d) + edgeContrib(a, b);\n            return newc - oldc;\n        }\n    }\n\n    static void relocateMove(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) p[k] = p[k + 1];\n            p[j] = v;\n        } else {\n            for (int k = i; k > j; k--) p[k] = p[k - 1];\n            p[j] = v;\n        }\n    }\n\n    vector<int> nearestAllStarts() const {\n        vector<int> bestPerm;\n        long long best = (1LL << 60);\n\n        vector<char> used(M);\n        vector<int> perm(M);\n\n        for (int s = 0; s < M; s++) {\n            fill(used.begin(), used.end(), 0);\n            perm[0] = s;\n            used[s] = 1;\n            long long c = startCostApprox[s];\n\n            for (int pos = 1; pos < M; pos++) {\n                int prev = perm[pos - 1];\n                int bestj = -1;\n                int bestv = INF;\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeApprox[prev][j];\n                    if (v < bestv) {\n                        bestv = v;\n                        bestj = j;\n                    }\n                }\n                perm[pos] = bestj;\n                used[bestj] = 1;\n                c += bestv;\n            }\n\n            if (c < best) {\n                best = c;\n                bestPerm = perm;\n            }\n        }\n        return bestPerm;\n    }\n\n    vector<int> cheapestInsertion(int seed) const {\n        vector<int> path;\n        path.reserve(M);\n        vector<char> used(M, 0);\n        path.push_back(seed);\n        used[seed] = 1;\n\n        for (int step = 1; step < M; step++) {\n            long long bestDelta = (1LL << 60);\n            int bestWord = -1;\n            int bestPos = -1;\n            int len = (int)path.size();\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                long long dFront = (long long)startCostApprox[x] + edgeApprox[x][path[0]] - startCostApprox[path[0]];\n                if (dFront < bestDelta) {\n                    bestDelta = dFront;\n                    bestWord = x;\n                    bestPos = 0;\n                }\n\n                for (int pos = 1; pos < len; pos++) {\n                    int u = path[pos - 1];\n                    int v = path[pos];\n                    long long d = (long long)edgeApprox[u][x] + edgeApprox[x][v] - edgeApprox[u][v];\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestWord = x;\n                        bestPos = pos;\n                    }\n                }\n\n                long long dEnd = edgeApprox[path[len - 1]][x];\n                if (dEnd < bestDelta) {\n                    bestDelta = dEnd;\n                    bestWord = x;\n                    bestPos = len;\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestWord);\n            used[bestWord] = 1;\n        }\n\n        return path;\n    }\n\n    void localSearchApprox(vector<int>& perm, long long& curCost, double endTime) {\n        while (elapsed() < endTime) {\n            long long bestD = 0;\n            int bestType = 0, bi = -1, bj = -1;\n\n            for (int i = 0; i < M; i++) {\n                for (int j = i + 1; j < M; j++) {\n                    long long d = deltaSwapApprox(perm, i, j);\n                    if (d < bestD) {\n                        bestD = d;\n                        bestType = 1;\n                        bi = i; bj = j;\n                    }\n                }\n                if ((i & 15) == 0 && elapsed() >= endTime) break;\n            }\n            if (elapsed() >= endTime) break;\n\n            for (int i = 0; i < M; i++) {\n                for (int j = 0; j < M; j++) if (i != j) {\n                    long long d = deltaRelocateApprox(perm, i, j);\n                    if (d < bestD) {\n                        bestD = d;\n                        bestType = 2;\n                        bi = i; bj = j;\n                    }\n                }\n                if ((i & 7) == 0 && elapsed() >= endTime) break;\n            }\n            if (elapsed() >= endTime) break;\n\n            if (bestD >= 0) break;\n\n            if (bestType == 1) swap(perm[bi], perm[bj]);\n            else relocateMove(perm, bi, bj);\n            curCost += bestD;\n        }\n    }\n\n    void SAApprox(vector<int>& perm, long long& curCost, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm;\n        vector<int> bestPerm = perm;\n        long long curC = curCost;\n        long long bestC = curC;\n\n        const double T0 = 20.0, T1 = 0.03;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            int i = rng.nextInt(M);\n            int j = rng.nextInt(M - 1);\n            if (j >= i) j++;\n            bool sw = (rng.nextInt(100) < 55);\n\n            long long d = sw ? deltaSwapApprox(cur, i, j) : deltaRelocateApprox(cur, i, j);\n            if (d == 0) continue;\n\n            bool ok = (d <= 0) || (rng.nextDouble() < exp(-double(d) / temp));\n            if (!ok) continue;\n\n            if (sw) swap(cur[i], cur[j]);\n            else relocateMove(cur, i, j);\n            curC += d;\n\n            if (curC < bestC) {\n                bestC = curC;\n                bestPerm = cur;\n            }\n        }\n\n        perm = bestPerm;\n        curCost = bestC;\n    }\n\n    // exact cost of permutation via word-boundary DP on precomputed pair matrices\n    int exactCost(const vector<int>& perm) const {\n        int dpA[225], dpB[225];\n\n        int w0 = perm[0];\n        int sz = nEnd[w0];\n        for (int i = 0; i < sz; i++) dpA[i] = firstEndCost[w0][i];\n\n        for (int idx = 1; idx < M; idx++) {\n            int a = perm[idx - 1];\n            int b = perm[idx];\n            int na = nEnd[a];\n            int nb = nEnd[b];\n\n            for (int j = 0; j < nb; j++) dpB[j] = INF;\n\n            size_t id = (size_t)a * M + b;\n            const int* mat = transData.data() + transOffset[id];\n\n            for (int i = 0; i < na; i++) {\n                int base = dpA[i];\n                const int* row = mat + (size_t)i * nb;\n                for (int j = 0; j < nb; j++) {\n                    int cand = base + row[j];\n                    if (cand < dpB[j]) dpB[j] = cand;\n                }\n            }\n\n            for (int j = 0; j < nb; j++) dpA[j] = dpB[j];\n            sz = nb;\n        }\n\n        int ans = INF;\n        for (int i = 0; i < sz; i++) ans = min(ans, dpA[i]);\n        return ans;\n    }\n\n    void SAExact(vector<int>& perm, long long& approxCur, int& exactCur, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm;\n        vector<int> best = perm;\n        long long curA = approxCur, bestA = approxCur;\n        int curE = exactCur, bestE = exactCur;\n\n        const double T0 = 14.0, T1 = 0.05;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        int stagn = 0;\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            int i = rng.nextInt(M);\n            int j = rng.nextInt(M - 1);\n            if (j >= i) j++;\n            bool sw = (rng.nextInt(100) < 55);\n\n            long long dA = sw ? deltaSwapApprox(cur, i, j) : deltaRelocateApprox(cur, i, j);\n\n            // cheap prefilter: avoid spending exact eval on obviously bad approximate moves\n            if (dA > 180 && rng.nextInt(100) < 95) continue;\n\n            if (sw) swap(cur[i], cur[j]);\n            else relocateMove(cur, i, j);\n\n            int nc = exactCost(cur);\n            int dE = nc - curE;\n\n            bool ok = (dE <= 0) || (rng.nextDouble() < exp(-double(dE) / temp));\n            if (ok) {\n                curE = nc;\n                curA += dA;\n\n                if (curE < bestE || (curE == bestE && curA < bestA)) {\n                    bestE = curE;\n                    bestA = curA;\n                    best = cur;\n                    stagn = 0;\n                } else {\n                    stagn++;\n                }\n            } else {\n                if (sw) swap(cur[i], cur[j]);\n                else relocateMove(cur, j, i); // inverse\n                stagn++;\n            }\n\n            // light restart/perturbation\n            if (stagn > 8000) {\n                cur = best;\n                curE = bestE;\n                curA = bestA;\n\n                for (int rep = 0; rep < 3; rep++) {\n                    int a = rng.nextInt(M);\n                    int b = rng.nextInt(M - 1);\n                    if (b >= a) b++;\n                    bool sw2 = (rng.nextInt(100) < 50);\n                    long long dA2 = sw2 ? deltaSwapApprox(cur, a, b) : deltaRelocateApprox(cur, a, b);\n                    if (sw2) swap(cur[a], cur[b]);\n                    else relocateMove(cur, a, b);\n                    curA += dA2;\n                }\n                curE = exactCost(cur);\n                stagn = 0;\n            }\n        }\n\n        perm = best;\n        approxCur = bestA;\n        exactCur = bestE;\n    }\n\n    void buildString(const vector<int>& perm, string& out) const {\n        out.clear();\n        out.reserve(5 * M);\n        out += words[perm[0]];\n        for (int i = 1; i < M; i++) {\n            int a = perm[i - 1];\n            int b = perm[i];\n            int k = ov[a][b];\n            for (int p = k; p < 5; p++) out.push_back(words[b][p]);\n        }\n    }\n\n    vector<int> bestPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<short>> parent(L, vector<short>(V, -1));\n\n        vector<int> prev(V, INF), cur(V, INF);\n        vector<int> prevCells = occ[s[0] - 'A'];\n\n        for (int q : prevCells) prev[q] = distMat[startId][q] + 1;\n\n        for (int idx = 1; idx < L; idx++) {\n            const vector<int>& nextCells = occ[s[idx] - 'A'];\n\n            for (int q : nextCells) {\n                int best = INF;\n                short bp = -1;\n                for (int p : prevCells) {\n                    int cand = prev[p] + distMat[p][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bp = (short)p;\n                    }\n                }\n                cur[q] = best;\n                parent[idx][q] = bp;\n            }\n\n            for (int p : prevCells) prev[p] = INF;\n            prevCells = nextCells;\n            for (int q : prevCells) {\n                prev[q] = cur[q];\n                cur[q] = INF;\n            }\n        }\n\n        int endCell = -1, best = INF;\n        for (int p : prevCells) {\n            if (prev[p] < best) {\n                best = prev[p];\n                endCell = p;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = endCell;\n        for (int i = L - 1; i >= 1; i--) {\n            path[i - 1] = parent[i][path[i]];\n        }\n        return path;\n    }\n\n    void solve() {\n        readInput();\n        rng = XorShift64(makeSeed());\n        t0 = chrono::steady_clock::now();\n\n        preprocess();\n\n        vector<vector<int>> candidates;\n        candidates.reserve(20);\n\n        vector<int> nn = nearestAllStarts();\n        candidates.push_back(nn);\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 (startCostApprox[a] != startCostApprox[b]) return startCostApprox[a] < startCostApprox[b];\n            return a < b;\n        });\n\n        vector<char> usedSeed(M, 0);\n        auto addSeed = [&](int s) {\n            if (usedSeed[s]) return;\n            usedSeed[s] = 1;\n            candidates.push_back(cheapestInsertion(s));\n        };\n\n        addSeed(nn[0]);\n        for (int i = 0; i < min(M, 8); i++) addSeed(ord[i]);\n        for (int t = 0; t < 6; t++) addSeed(rng.nextInt(M));\n\n        int bestAIdx = 0, bestEIdx = 0;\n        long long bestA = (1LL << 60);\n        int bestE = INF;\n\n        vector<long long> candA(candidates.size());\n        vector<int> candE(candidates.size());\n\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            candA[i] = approxCost(candidates[i]);\n            if (candA[i] < bestA) {\n                bestA = candA[i];\n                bestAIdx = i;\n            }\n        }\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            candE[i] = exactCost(candidates[i]);\n            if (candE[i] < bestE) {\n                bestE = candE[i];\n                bestEIdx = i;\n            }\n        }\n\n        vector<int> perm = candidates[bestAIdx];\n        long long curA = candA[bestAIdx];\n\n        double T_LIMIT = 1.92;\n        double approxEnd = min(1.00, elapsed() + 0.30);\n        if (elapsed() < approxEnd) {\n            double lsEnd = min(approxEnd, elapsed() + 0.10);\n            localSearchApprox(perm, curA, lsEnd);\n            SAApprox(perm, curA, approxEnd);\n        }\n\n        int curE = exactCost(perm);\n\n        if (bestE < curE) {\n            perm = candidates[bestEIdx];\n            curA = candA[bestEIdx];\n            curE = bestE;\n        }\n\n        double exactEnd = T_LIMIT - 0.03;\n        SAExact(perm, curA, curE, exactEnd);\n\n        string finalS;\n        buildString(perm, finalS);\n\n        vector<int> path = bestPathForString(finalS);\n\n        for (int id : path) {\n            cout << (id / N) << ' ' << (id % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Mask {\n    static constexpr int W = 7; // 7 * 64 = 448 >= 400\n    array<uint64_t, W> w;\n    Mask() { w.fill(0ULL); }\n    inline void set(int idx) { w[idx >> 6] |= (1ULL << (idx & 63)); }\n    inline bool test(int idx) const { return (w[idx >> 6] >> (idx & 63)) & 1ULL; }\n    inline void or_with(const Mask& other) {\n        for (int i = 0; i < W; i++) w[i] |= other.w[i];\n    }\n};\n\nstruct Placement {\n    vector<int> cells;        // covered global cell indices\n    Mask mask;                // bit representation\n    vector<uint8_t> qcov;     // coverage bits for drilled-query list\n};\n\nclass OilSolver {\npublic:\n    int N = 0, M = 0, n2 = 0;\n    double eps = 0.0;\n\n    vector<vector<pair<int,int>>> shapes;\n    vector<vector<Placement>> fieldPls; // [field][placement]\n\n    vector<int> drilledVal;   // -1 unknown, else exact v(i,j)\n    vector<int> qidOfCell;    // cell -> drilled-query index\n    vector<int> queryVals;    // observed exact values\n    vector<int> queryCells;   // queried cell index list\n\n    vector<int> priorOrder;\n    int priorPtr = 0;\n\n    mt19937 rng;\n    int ops = 0;\n    int wrongGuesses = 0;\n    int guessCooldown = 0;\n    vector<int> lastWrongGuess;\n    bool hasLastWrongGuess = false;\n\n    chrono::steady_clock::time_point globalStart;\n\n    static constexpr int MAX_WRONG_GUESSES = 8;\n\n    OilSolver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        n2 = N * N;\n        shapes.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            shapes[k].resize(d);\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                shapes[k][t] = {i, j};\n            }\n        }\n        drilledVal.assign(n2, -1);\n        qidOfCell.assign(n2, -1);\n    }\n\n    void build_placements() {\n        fieldPls.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int maxr = 0, maxc = 0;\n            for (auto [r, c] : shapes[k]) {\n                maxr = max(maxr, r);\n                maxc = max(maxc, c);\n            }\n            for (int di = 0; di + maxr < N; di++) {\n                for (int dj = 0; dj + maxc < N; dj++) {\n                    Placement pl;\n                    pl.cells.reserve(shapes[k].size());\n                    pl.qcov.reserve(n2);\n                    for (auto [r, c] : shapes[k]) {\n                        int ni = di + r;\n                        int nj = dj + c;\n                        int idx = ni * N + nj;\n                        pl.cells.push_back(idx);\n                        pl.mask.set(idx);\n                    }\n                    fieldPls[k].push_back(move(pl));\n                }\n            }\n        }\n    }\n\n    void build_prior_order() {\n        vector<vector<int>> coverCnt(M, vector<int>(n2, 0));\n        for (int k = 0; k < M; k++) {\n            for (const auto& pl : fieldPls[k]) {\n                for (int idx : pl.cells) coverCnt[k][idx]++;\n            }\n        }\n\n        vector<double> score(n2, 0.0);\n        for (int idx = 0; idx < n2; idx++) {\n            double p0 = 1.0;\n            for (int k = 0; k < M; k++) {\n                double pk = (double)coverCnt[k][idx] / (double)fieldPls[k].size();\n                p0 *= (1.0 - pk);\n            }\n            double p = 1.0 - p0;\n            score[idx] = p * (1.0 - p); // entropy proxy\n        }\n\n        priorOrder.resize(n2);\n        iota(priorOrder.begin(), priorOrder.end(), 0);\n        sort(priorOrder.begin(), priorOrder.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return a < b;\n        });\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << \" \" << (idx % N) << endl;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    int ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int idx : cells) {\n            cout << \" \" << (idx / N) << \" \" << (idx % N);\n        }\n        cout << endl;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    void add_drill(int idx, int val) {\n        if (drilledVal[idx] != -1) return;\n        drilledVal[idx] = val;\n        int qid = (int)queryVals.size();\n        qidOfCell[idx] = qid;\n        queryVals.push_back(val);\n        queryCells.push_back(idx);\n\n        for (int k = 0; k < M; k++) {\n            for (auto& pl : fieldPls[k]) {\n                pl.qcov.push_back(pl.mask.test(idx) ? 1 : 0);\n            }\n        }\n    }\n\n    int pick_prior_cell() {\n        while (priorPtr < (int)priorOrder.size() && drilledVal[priorOrder[priorPtr]] != -1) priorPtr++;\n        if (priorPtr < (int)priorOrder.size()) return priorOrder[priorPtr++];\n        return -1;\n    }\n\n    int first_unknown_cell() const {\n        for (int idx = 0; idx < n2; idx++) if (drilledVal[idx] == -1) return idx;\n        return -1;\n    }\n\n    bool propagate_domains(vector<vector<int>>& domains) {\n        int q = (int)queryVals.size();\n        domains.assign(M, {});\n\n        vector<vector<char>> active(M);\n        for (int k = 0; k < M; k++) active[k].assign(fieldPls[k].size(), 1);\n\n        int iter = 0;\n        while (true) {\n            iter++;\n\n            vector<int> domSize(M, 0);\n            vector<vector<int>> cnt1(M, vector<int>(q, 0));\n\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    domSize[k]++;\n                    const auto& qc = pls[p].qcov;\n                    for (int r = 0; r < q; r++) cnt1[k][r] += qc[r];\n                }\n            }\n            for (int k = 0; k < M; k++) if (domSize[k] == 0) return false;\n\n            vector<vector<int8_t>> minv(M, vector<int8_t>(q, 0));\n            vector<vector<int8_t>> maxv(M, vector<int8_t>(q, 0));\n            vector<int> totalMin(q, 0), totalMax(q, 0);\n\n            for (int r = 0; r < q; r++) {\n                int tmin = 0, tmax = 0;\n                for (int k = 0; k < M; k++) {\n                    bool has1 = cnt1[k][r] > 0;\n                    bool has0 = (domSize[k] - cnt1[k][r]) > 0;\n                    int mn = has0 ? 0 : 1;\n                    int mx = has1 ? 1 : 0;\n                    minv[k][r] = (int8_t)mn;\n                    maxv[k][r] = (int8_t)mx;\n                    tmin += mn;\n                    tmax += mx;\n                }\n                totalMin[r] = tmin;\n                totalMax[r] = tmax;\n                int y = queryVals[r];\n                if (y < tmin || y > tmax) return false;\n            }\n\n            bool changed = false;\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    const auto& qc = pls[p].qcov;\n                    bool ok = true;\n                    for (int r = 0; r < q; r++) {\n                        int x = qc[r];\n                        int need = queryVals[r] - x;\n                        int lo = totalMin[r] - minv[k][r];\n                        int hi = totalMax[r] - maxv[k][r];\n                        if (need < lo || need > hi) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) {\n                        active[k][p] = 0;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed || iter >= 40) {\n                for (int k = 0; k < M; k++) {\n                    for (int p = 0; p < (int)fieldPls[k].size(); p++) {\n                        if (active[k][p]) domains[k].push_back(p);\n                    }\n                    if (domains[k].empty()) return false;\n                }\n                return true;\n            }\n        }\n    }\n\n    vector<vector<int>> sample_solutions(int maxSol, long long nodeLimit, int timeMs) {\n        vector<vector<int>> domains;\n        if (!propagate_domains(domains)) return {};\n\n        int q = (int)queryVals.size();\n        vector<vector<int>> sols;\n        if (maxSol <= 0) return sols;\n\n        if (q == 0) {\n            for (int s = 0; s < maxSol; s++) {\n                vector<int> asg(M, -1);\n                for (int k = 0; k < M; k++) {\n                    auto& d = domains[k];\n                    uniform_int_distribution<int> dist(0, (int)d.size() - 1);\n                    asg[k] = d[dist(rng)];\n                }\n                sols.push_back(move(asg));\n            }\n            return sols;\n        }\n\n        vector<vector<int8_t>> varMin(M, vector<int8_t>(q, 0));\n        vector<vector<int8_t>> varMax(M, vector<int8_t>(q, 0));\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            vector<int> c1(q, 0);\n            for (int p : domains[k]) {\n                const auto& qc = fieldPls[k][p].qcov;\n                for (int r = 0; r < q; r++) c1[r] += qc[r];\n            }\n            for (int r = 0; r < q; r++) {\n                bool has1 = c1[r] > 0;\n                bool has0 = (ds - c1[r]) > 0;\n                varMin[k][r] = has0 ? 0 : 1;\n                varMax[k][r] = has1 ? 1 : 0;\n            }\n        }\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (domains[a].size() != domains[b].size()) return domains[a].size() < domains[b].size();\n            return a < b;\n        });\n\n        vector<vector<int>> sufMin(M + 1, vector<int>(q, 0));\n        vector<vector<int>> sufMax(M + 1, vector<int>(q, 0));\n        for (int d = M - 1; d >= 0; d--) {\n            int k = order[d];\n            for (int r = 0; r < q; r++) {\n                sufMin[d][r] = sufMin[d + 1][r] + varMin[k][r];\n                sufMax[d][r] = sufMax[d + 1][r] + varMax[k][r];\n            }\n        }\n        for (int r = 0; r < q; r++) {\n            if (queryVals[r] < sufMin[0][r] || queryVals[r] > sufMax[0][r]) return {};\n        }\n\n        vector<vector<int>> domOrd(M);\n        for (int k = 0; k < M; k++) {\n            domOrd[k] = domains[k];\n            shuffle(domOrd[k].begin(), domOrd[k].end(), rng);\n        }\n\n        vector<int> target = queryVals;\n        vector<int> assign(M, -1);\n\n        auto deadline = chrono::steady_clock::now() + chrono::milliseconds(timeMs);\n        bool timeout = false;\n        long long nodes = 0;\n\n        auto dfs = [&](auto&& self, int depth) -> void {\n            if (timeout || (int)sols.size() >= maxSol) return;\n            if (depth == M) {\n                for (int r = 0; r < q; r++) if (target[r] != 0) return;\n                sols.push_back(assign);\n                return;\n            }\n            int k = order[depth];\n            for (int p : domOrd[k]) {\n                nodes++;\n                if ((nodes & 2047LL) == 0) {\n                    if (nodes > nodeLimit || chrono::steady_clock::now() >= deadline) {\n                        timeout = true;\n                        return;\n                    }\n                }\n\n                const auto& qc = fieldPls[k][p].qcov;\n                bool ok = true;\n                for (int r = 0; r < q; r++) {\n                    int t = target[r] - qc[r];\n                    if (t < sufMin[depth + 1][r] || t > sufMax[depth + 1][r]) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (!ok) continue;\n\n                assign[k] = p;\n                for (int cell : fieldPls[k][p].cells) {\n                    int id = qidOfCell[cell];\n                    if (id != -1) target[id]--;\n                }\n\n                self(self, depth + 1);\n\n                for (int cell : fieldPls[k][p].cells) {\n                    int id = qidOfCell[cell];\n                    if (id != -1) target[id]++;\n                }\n\n                if (timeout || (int)sols.size() >= maxSol) return;\n            }\n            assign[k] = -1;\n        };\n\n        dfs(dfs, 0);\n\n        // fallback: randomized constructive attempts\n        if (sols.empty()) {\n            for (int attempt = 0; attempt < 120 && sols.empty(); attempt++) {\n                vector<int> t = queryVals;\n                vector<int> asg(M, -1);\n                bool okAll = true;\n\n                for (int depth = 0; depth < M; depth++) {\n                    int k = order[depth];\n                    vector<int> cand = domains[k];\n                    shuffle(cand.begin(), cand.end(), rng);\n\n                    int chosen = -1;\n                    for (int p : cand) {\n                        const auto& qc = fieldPls[k][p].qcov;\n                        bool feasible = true;\n                        for (int r = 0; r < q; r++) {\n                            int nt = t[r] - qc[r];\n                            if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                                feasible = false;\n                                break;\n                            }\n                        }\n                        if (feasible) {\n                            chosen = p;\n                            break;\n                        }\n                    }\n\n                    if (chosen == -1) {\n                        okAll = false;\n                        break;\n                    }\n\n                    asg[k] = chosen;\n                    for (int cell : fieldPls[k][chosen].cells) {\n                        int id = qidOfCell[cell];\n                        if (id != -1) t[id]--;\n                    }\n                }\n\n                if (okAll) {\n                    bool exact = true;\n                    for (int v : t) if (v != 0) { exact = false; break; }\n                    if (exact) sols.push_back(move(asg));\n                }\n            }\n        }\n\n        return sols;\n    }\n\n    vector<int> calc_freq(const vector<vector<int>>& sols) {\n        vector<int> freq(n2, 0);\n        for (const auto& asg : sols) {\n            Mask uni;\n            for (int k = 0; k < M; k++) {\n                uni.or_with(fieldPls[k][asg[k]].mask);\n            }\n            for (int wi = 0; wi < Mask::W; wi++) {\n                uint64_t bits = uni.w[wi];\n                while (bits) {\n                    int b = __builtin_ctzll(bits);\n                    int idx = wi * 64 + b;\n                    if (idx < n2) freq[idx]++;\n                    bits &= bits - 1;\n                }\n            }\n        }\n        return freq;\n    }\n\n    int choose_uncertain_cell(const vector<int>& freq, int S) {\n        if (S <= 0) return -1;\n        int best = -1;\n        double bestScore = -1.0;\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            int f = freq[idx];\n            if (f == 0 || f == S) continue;\n            double p = (double)f / (double)S;\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    vector<int> build_consensus_guess(const vector<int>& freq, int S) {\n        vector<char> used(n2, 0);\n        if (S > 0) {\n            for (int idx = 0; idx < n2; idx++) {\n                if (freq[idx] == S) used[idx] = 1;\n            }\n        }\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] > 0) used[idx] = 1;\n        }\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int idx = 0; idx < n2; idx++) if (used[idx]) ans.push_back(idx);\n        return ans;\n    }\n\n    vector<int> exact_from_drilled() const {\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] > 0) ans.push_back(idx);\n        }\n        return ans;\n    }\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - globalStart).count();\n    }\n\n    void solve() {\n        globalStart = chrono::steady_clock::now();\n        int initQueries = min(8, N);\n        int maxOps = 2 * n2;\n        int solveLimit = min(n2, 140);\n\n        while (true) {\n            int drilledCnt = (int)queryVals.size();\n\n            if (drilledCnt == n2) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    (void)res;\n                }\n                return;\n            }\n\n            bool simpleMode = (elapsed_ms() > 2500.0);\n\n            int next = -1;\n            vector<vector<int>> sols;\n            vector<int> freq;\n            bool consensus = false;\n            int S = 0;\n\n            if (!simpleMode && drilledCnt >= 3 && drilledCnt <= solveLimit) {\n                int maxSol = (drilledCnt < 12 ? 16 : 24);\n                long long nodeLim = (drilledCnt < 12 ? 40000 : 120000);\n                int timeMs = (drilledCnt < 12 ? 15 : 30);\n                sols = sample_solutions(maxSol, nodeLim, timeMs);\n                S = (int)sols.size();\n                if (S > 0) {\n                    freq = calc_freq(sols);\n                    next = choose_uncertain_cell(freq, S);\n                    consensus = (next == -1);\n                }\n            }\n\n            if (drilledCnt < initQueries && next == -1) {\n                next = pick_prior_cell();\n            }\n\n            if (next == -1) {\n                if (!simpleMode && consensus && S > 0 && guessCooldown == 0 &&\n                    wrongGuesses < MAX_WRONG_GUESSES && drilledCnt >= max(6, M / 2)) {\n                    if (S >= 4 || drilledCnt >= 20) {\n                        vector<int> guess = build_consensus_guess(freq, S);\n                        bool sameAsLastWrong = (hasLastWrongGuess && guess == lastWrongGuess);\n                        if (!sameAsLastWrong && ops < maxOps) {\n                            int res = ask_answer(guess);\n                            ops++;\n                            if (res == 1) return;\n                            wrongGuesses++;\n                            guessCooldown = 3;\n                            lastWrongGuess = move(guess);\n                            hasLastWrongGuess = true;\n                            continue;\n                        }\n                    }\n                }\n                next = pick_prior_cell();\n            }\n\n            if (next == -1) next = first_unknown_cell();\n            if (next == -1) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    if (res == 1) return;\n                }\n                return;\n            }\n\n            if (ops >= maxOps) return;\n\n            int v = ask_drill(next);\n            ops++;\n            add_drill(next, v);\n            if (guessCooldown > 0) guessCooldown--;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    OilSolver solver;\n    solver.read_input();\n    solver.build_placements();\n    solver.build_prior_order();\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Iseg {\n    int c, l, r; // coordinate, [l, r)\n    bool operator==(const Iseg&) const = default;\n};\n\nstruct Candidate {\n    vector<array<int, 4>> rects; // by request index k\n    vector<Iseg> hsegs;          // horizontal: y=c, x in [l,r)\n    vector<Iseg> vsegs;          // vertical:   x=c, y in [l,r)\n    long long shortage = 0;\n    int boundaryLen = 0;\n};\n\nstatic inline long long rect_area(const array<int, 4>& rc) {\n    return 1LL * (rc[2] - rc[0]) * (rc[3] - rc[1]);\n}\n\nstatic vector<Iseg> merge_segments(vector<Iseg> segs) {\n    sort(segs.begin(), segs.end(), [](const Iseg& a, const Iseg& b) {\n        if (a.c != b.c) return a.c < b.c;\n        if (a.l != b.l) return a.l < b.l;\n        return a.r < b.r;\n    });\n    vector<Iseg> out;\n    out.reserve(segs.size());\n    for (auto& s : segs) {\n        if (s.l >= s.r) continue;\n        if (out.empty() || out.back().c != s.c || s.l > out.back().r) {\n            out.push_back(s);\n        } else {\n            out.back().r = max(out.back().r, s.r);\n        }\n    }\n    return out;\n}\n\n// Build candidate from a set of geometric cells (unordered).\n// Then optimally assign cells to requests by area sorting (ascending).\nstatic Candidate build_candidate_from_cells(\n    int W,\n    const vector<int>& dayA, // sorted nondecreasing by problem statement\n    const vector<array<int, 4>>& cells\n) {\n    int N = (int)dayA.size();\n    Candidate cand;\n    cand.rects.resize(N);\n\n    vector<pair<long long, int>> ord;\n    ord.reserve(N);\n    for (int i = 0; i < N; i++) ord.push_back({rect_area(cells[i]), i});\n    sort(ord.begin(), ord.end(), [](auto& p, auto& q) {\n        if (p.first != q.first) return p.first < q.first;\n        return p.second < q.second;\n    });\n\n    for (int k = 0; k < N; k++) {\n        cand.rects[k] = cells[ord[k].second];\n    }\n\n    long long sh = 0;\n    for (int k = 0; k < N; k++) {\n        long long b = rect_area(cand.rects[k]);\n        if (b < dayA[k]) sh += 100LL * (dayA[k] - b);\n    }\n    cand.shortage = sh;\n\n    vector<Iseg> rawH, rawV;\n    rawH.reserve(2 * N);\n    rawV.reserve(2 * N);\n\n    // Perimeter union of all rectangles, excluding outer boundary of hall.\n    for (const auto& rc : cells) {\n        int y0 = rc[0], x0 = rc[1], y1 = rc[2], x1 = rc[3];\n        if (y0 > 0) rawH.push_back({y0, x0, x1});\n        if (y1 < W) rawH.push_back({y1, x0, x1});\n        if (x0 > 0) rawV.push_back({x0, y0, y1});\n        if (x1 < W) rawV.push_back({x1, y0, y1});\n    }\n\n    cand.hsegs = merge_segments(move(rawH));\n    cand.vsegs = merge_segments(move(rawV));\n\n    long long bl = 0;\n    for (auto& s : cand.hsegs) bl += (s.r - s.l);\n    for (auto& s : cand.vsegs) bl += (s.r - s.l);\n    cand.boundaryLen = (int)bl;\n\n    return cand;\n}\n\nstatic bool same_shape(const Candidate& a, const Candidate& b) {\n    return a.hsegs == b.hsegs && a.vsegs == b.vsegs;\n}\n\nstatic long long symdiff_len(const vector<Iseg>& A, const vector<Iseg>& B) {\n    long long cost = 0;\n    int i = 0, j = 0;\n\n    while (i < (int)A.size() || j < (int)B.size()) {\n        int c;\n        if (j == (int)B.size() || (i < (int)A.size() && A[i].c < B[j].c)) c = A[i].c;\n        else c = B[j].c;\n\n        int i0 = i;\n        while (i < (int)A.size() && A[i].c == c) i++;\n        int j0 = j;\n        while (j < (int)B.size() && B[j].c == c) j++;\n\n        long long lenA = 0, lenB = 0;\n        for (int p = i0; p < i; p++) lenA += (A[p].r - A[p].l);\n        for (int q = j0; q < j; q++) lenB += (B[q].r - B[q].l);\n\n        long long inter = 0;\n        int p = i0, q = j0;\n        while (p < i && q < j) {\n            int L = max(A[p].l, B[q].l);\n            int R = min(A[p].r, B[q].r);\n            if (R > L) inter += (R - L);\n            if (A[p].r < B[q].r) p++;\n            else q++;\n        }\n\n        cost += lenA + lenB - 2LL * inter;\n    }\n\n    return cost;\n}\n\nstatic inline long long transition_cost(const Candidate& A, const Candidate& B) {\n    return symdiff_len(A.hsegs, B.hsegs) + symdiff_len(A.vsegs, B.vsegs);\n}\n\nstatic int min_height_segment(const vector<int>& arr, int l, int r, int W) {\n    auto ok = [&](int h) -> bool {\n        long long sumw = 0;\n        for (int i = l; i < r; i++) {\n            sumw += (arr[i] + h - 1) / h;\n            if (sumw > W) return false;\n        }\n        return true;\n    };\n\n    if (!ok(W)) return W + 1;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (ok(mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nstatic vector<int> sample_rows(const vector<int>& feasible, int cap) {\n    if (feasible.empty()) return {};\n    if ((int)feasible.size() <= cap) return feasible;\n    if (cap <= 1) return {feasible.front()};\n\n    vector<int> ret;\n    ret.reserve(cap);\n    int m = (int)feasible.size();\n    int last = -1;\n    for (int t = 0; t < cap; t++) {\n        int idx = (long long)t * (m - 1) / (cap - 1);\n        int v = feasible[idx];\n        if (v != last) {\n            ret.push_back(v);\n            last = v;\n        }\n    }\n    for (int v : feasible) {\n        if ((int)ret.size() >= cap) break;\n        bool found = false;\n        for (int x : ret) if (x == v) { found = true; break; }\n        if (!found) ret.push_back(v);\n    }\n    sort(ret.begin(), ret.end());\n    return ret;\n}\n\nstatic vector<Candidate> generate_shelf_one_order(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    int capRows\n) {\n    int N = (int)dayA.size();\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    vector<vector<int>> htab(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            htab[l][r] = min_height_segment(arr, l, r, W);\n        }\n    }\n\n    const int INF = 1e9;\n    vector<vector<int>> dp(N + 1, vector<int>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int rr = 1; rr <= N; rr++) {\n        for (int i = 1; i <= N; i++) {\n            int best = INF, bestj = -1;\n            for (int j = 0; j < i; j++) {\n                if (dp[rr - 1][j] == INF) continue;\n                int h = htab[j][i];\n                if (h > W) continue;\n                int val = dp[rr - 1][j] + h;\n                if (val < best || (val == best && j > bestj)) {\n                    best = val;\n                    bestj = j;\n                }\n            }\n            dp[rr][i] = best;\n            par[rr][i] = bestj;\n        }\n    }\n\n    vector<int> feasibleRows;\n    for (int rr = 1; rr <= N; rr++) {\n        if (dp[rr][N] <= W) feasibleRows.push_back(rr);\n    }\n\n    vector<int> selected = sample_rows(feasibleRows, capRows);\n    vector<Candidate> out;\n    out.reserve(selected.size());\n\n    for (int rr : selected) {\n        vector<int> split(rr + 1);\n        split[rr] = N;\n        int cur = N;\n        bool ok = true;\n        for (int r = rr; r >= 1; r--) {\n            int j = par[r][cur];\n            if (j < 0) {\n                ok = false;\n                break;\n            }\n            split[r - 1] = j;\n            cur = j;\n        }\n        if (!ok || split[0] != 0) continue;\n\n        vector<int> hs(rr);\n        long long totalh = 0;\n        for (int g = 0; g < rr; g++) {\n            int l = split[g], r = split[g + 1];\n            hs[g] = htab[l][r];\n            totalh += hs[g];\n        }\n        if (totalh > W) continue;\n        hs.back() += (int)(W - totalh);\n\n        vector<array<int, 4>> cells;\n        cells.reserve(N);\n\n        int y = 0;\n        for (int g = 0; g < rr; g++) {\n            int l = split[g], r = split[g + 1];\n            int h = hs[g];\n            int x = 0;\n            for (int t = l; t < r; t++) {\n                int req = dayA[ord[t]];\n                int w = (t < r - 1) ? (req + h - 1) / h : (W - x);\n                cells.push_back({y, x, y + h, x + w});\n                x += w;\n            }\n            y += h;\n        }\n\n        if ((int)cells.size() == N) {\n            out.push_back(build_candidate_from_cells(W, dayA, cells));\n        }\n    }\n\n    return out;\n}\n\nstatic Candidate fallback_horizontal(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int y0 = (long long)W * k / N;\n        int y1 = (long long)W * (k + 1) / N;\n        cells.push_back({y0, 0, y1, W});\n    }\n    return build_candidate_from_cells(W, dayA, cells);\n}\n\nstatic Candidate fallback_vertical(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int x0 = (long long)W * k / N;\n        int x1 = (long long)W * (k + 1) / N;\n        cells.push_back({0, x0, W, x1});\n    }\n    return build_candidate_from_cells(W, dayA, cells);\n}\n\n// Recursive guillotine candidate; returns false if construction failed.\nstatic bool generate_guillotine_candidate(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    Candidate& outCand\n) {\n    int N = (int)dayA.size();\n    vector<int> vals(N);\n    for (int i = 0; i < N; i++) vals[i] = dayA[ord[i]];\n\n    vector<long long> ps(N + 1, 0);\n    for (int i = 0; i < N; i++) ps[i + 1] = ps[i] + vals[i];\n\n    struct Opt {\n        int orient; // 0: vertical cut, 1: horizontal cut\n        int m;\n        int cut;\n        long long score;\n    };\n\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n\n    function<bool(int, int, int, int, int, int)> dfs =\n        [&](int l, int r, int y0, int y1, int x0, int x1) -> bool {\n            if (r - l == 1) {\n                if (!(y0 < y1 && x0 < x1)) return false;\n                cells.push_back({y0, x0, y1, x1});\n                return true;\n            }\n\n            int h = y1 - y0;\n            int w = x1 - x0;\n            if (h <= 0 || w <= 0) return false;\n\n            long long S = ps[r] - ps[l];\n            if (S <= 0) return false;\n\n            auto collect = [&](int orient) {\n                vector<Opt> opts;\n                opts.reserve((r - l > 1) ? (r - l - 1) : 0);\n\n                for (int m = l + 1; m < r; m++) {\n                    long long s1 = ps[m] - ps[l];\n                    long long s2 = S - s1;\n\n                    if (orient == 0) { // vertical\n                        long long min1 = max(1LL, (s1 + h - 1) / h);\n                        long long min2 = max(1LL, (s2 + h - 1) / h);\n                        if (min1 + min2 > w) continue;\n\n                        int cut = (int)llround((double)w * (double)s1 / (double)S);\n                        cut = max(cut, (int)min1);\n                        cut = min(cut, w - (int)min2);\n                        if (cut <= 0 || cut >= w) continue;\n\n                        long long cap1 = 1LL * cut * h;\n                        long long cap2 = 1LL * (w - cut) * h;\n                        long long sl1 = cap1 - s1, sl2 = cap2 - s2;\n                        long long score = sl1 * sl1 + sl2 * sl2\n                                        + llabs((long long)(2 * (m - l) - (r - l)));\n                        opts.push_back({0, m, cut, score});\n                    } else { // horizontal\n                        long long min1 = max(1LL, (s1 + w - 1) / w);\n                        long long min2 = max(1LL, (s2 + w - 1) / w);\n                        if (min1 + min2 > h) continue;\n\n                        int cut = (int)llround((double)h * (double)s1 / (double)S);\n                        cut = max(cut, (int)min1);\n                        cut = min(cut, h - (int)min2);\n                        if (cut <= 0 || cut >= h) continue;\n\n                        long long cap1 = 1LL * cut * w;\n                        long long cap2 = 1LL * (h - cut) * w;\n                        long long sl1 = cap1 - s1, sl2 = cap2 - s2;\n                        long long score = sl1 * sl1 + sl2 * sl2\n                                        + llabs((long long)(2 * (m - l) - (r - l)));\n                        opts.push_back({1, m, cut, score});\n                    }\n                }\n\n                sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n                    return a.score < b.score;\n                });\n                return opts;\n            };\n\n            int pref = (w >= h ? 0 : 1);\n            for (int pass = 0; pass < 2; pass++) {\n                int orient = (pass == 0 ? pref : 1 - pref);\n                auto opts = collect(orient);\n                int lim = min<int>((pass == 0 ? 3 : 1), opts.size());\n                for (int t = 0; t < lim; t++) {\n                    const auto& op = opts[t];\n                    size_t old = cells.size();\n\n                    bool ok = false;\n                    if (op.orient == 0) {\n                        int xm = x0 + op.cut;\n                        ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                             dfs(op.m, r, y0, y1, xm, x1);\n                    } else {\n                        int ym = y0 + op.cut;\n                        ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                             dfs(op.m, r, ym, y1, x0, x1);\n                    }\n                    if (ok) return true;\n                    cells.resize(old);\n                }\n            }\n            return false;\n        };\n\n    bool ok = dfs(0, N, 0, W, 0, W);\n    if (!ok || (int)cells.size() != N) return false;\n\n    outCand = build_candidate_from_cells(W, dayA, cells);\n    return true;\n}\n\nstatic void dedup_and_trim(vector<Candidate>& pool, int maxCand) {\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n\n    for (auto& c : pool) {\n        bool merged = false;\n        for (auto& u : uniq) {\n            if (same_shape(c, u)) {\n                if (c.shortage < u.shortage ||\n                    (c.shortage == u.shortage && c.boundaryLen < u.boundaryLen)) {\n                    u = c;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) uniq.push_back(move(c));\n    }\n\n    sort(uniq.begin(), uniq.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.shortage != b.shortage) return a.shortage < b.shortage;\n        return a.boundaryLen < b.boundaryLen;\n    });\n\n    if ((int)uniq.size() > maxCand) uniq.resize(maxCand);\n    pool.swap(uniq);\n}\n\nstatic pair<long long, vector<int>> solve_dp(const vector<vector<Candidate>>& cands) {\n    int D = (int)cands.size();\n    const long long INF = (1LL << 62);\n\n    vector<vector<int>> parent(D);\n    vector<long long> dpPrev(cands[0].size(), INF), dpCur;\n\n    for (int i = 0; i < (int)cands[0].size(); i++) {\n        dpPrev[i] = cands[0][i].shortage; // L0 = 0\n    }\n\n    for (int d = 1; d < D; d++) {\n        int P = (int)cands[d - 1].size();\n        int C = (int)cands[d].size();\n\n        dpCur.assign(C, INF);\n        parent[d].assign(C, -1);\n\n        for (int i = 0; i < C; i++) {\n            long long add = cands[d][i].shortage;\n            long long best = INF;\n            int bestj = 0;\n            for (int j = 0; j < P; j++) {\n                long long tr = transition_cost(cands[d - 1][j], cands[d][i]);\n                long long val = dpPrev[j] + tr + add;\n                if (val < best) {\n                    best = val;\n                    bestj = j;\n                }\n            }\n            dpCur[i] = best;\n            parent[d][i] = bestj;\n        }\n\n        dpPrev.swap(dpCur);\n    }\n\n    int last = 0;\n    for (int i = 1; i < (int)dpPrev.size(); i++) {\n        if (dpPrev[i] < dpPrev[last]) last = i;\n    }\n\n    vector<int> choice(D, 0);\n    choice[D - 1] = last;\n    for (int d = D - 1; d >= 1; d--) {\n        choice[d - 1] = parent[d][choice[d]];\n    }\n\n    return {dpPrev[last], choice};\n}\n\nstatic void add_order_unique(vector<vector<int>>& orders, const vector<int>& ord) {\n    for (auto& v : orders) {\n        if (v == ord) return;\n    }\n    orders.push_back(ord);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) cin >> a[d][k];\n    }\n\n    const int CAP_ROWS = min(12, N);\n    const int MAX_CAND = 50;\n\n    vector<vector<Candidate>> cands(D);\n\n    for (int d = 0; d < D; d++) {\n        vector<int> asc(N), desc(N), zig1, zig2;\n        iota(asc.begin(), asc.end(), 0);\n        for (int i = 0; i < N; i++) desc[i] = N - 1 - i;\n\n        {\n            int l = 0, r = N - 1;\n            while (l <= r) {\n                if (l == r) {\n                    zig1.push_back(l);\n                    break;\n                }\n                zig1.push_back(l++);\n                zig1.push_back(r--);\n            }\n        }\n        {\n            int l = 0, r = N - 1;\n            while (l <= r) {\n                if (l == r) {\n                    zig2.push_back(r);\n                    break;\n                }\n                zig2.push_back(r--);\n                zig2.push_back(l++);\n            }\n        }\n\n        mt19937 rng(123456789u + 10007u * d + 911u * N);\n        vector<int> rnd1 = asc, rnd2 = asc;\n        shuffle(rnd1.begin(), rnd1.end(), rng);\n        shuffle(rnd2.begin(), rnd2.end(), rng);\n\n        vector<vector<int>> shelfOrders;\n        add_order_unique(shelfOrders, asc);\n        add_order_unique(shelfOrders, desc);\n        add_order_unique(shelfOrders, zig1);\n        add_order_unique(shelfOrders, zig2);\n        add_order_unique(shelfOrders, rnd1);\n        add_order_unique(shelfOrders, rnd2);\n\n        vector<vector<int>> guillOrders;\n        add_order_unique(guillOrders, asc);\n        add_order_unique(guillOrders, desc);\n        add_order_unique(guillOrders, rnd1);\n        add_order_unique(guillOrders, rnd2);\n\n        vector<Candidate> pool;\n        pool.reserve(80);\n\n        for (auto& ord : shelfOrders) {\n            auto v = generate_shelf_one_order(W, a[d], ord, CAP_ROWS);\n            for (auto& c : v) pool.push_back(move(c));\n        }\n\n        for (auto& ord : guillOrders) {\n            Candidate g;\n            if (generate_guillotine_candidate(W, a[d], ord, g)) {\n                pool.push_back(move(g));\n            }\n        }\n\n        pool.push_back(fallback_horizontal(W, a[d]));\n        pool.push_back(fallback_vertical(W, a[d]));\n\n        dedup_and_trim(pool, MAX_CAND);\n        if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n\n        cands[d] = move(pool);\n    }\n\n    // First DP\n    auto [cost1, choice1] = solve_dp(cands);\n\n    // One enrichment pass: add neighbor-day chosen shapes remapped to current day.\n    vector<vector<array<int, 4>>> pathCells(D);\n    for (int d = 0; d < D; d++) {\n        pathCells[d] = cands[d][choice1[d]].rects;\n    }\n\n    for (int d = 0; d < D; d++) {\n        if (d > 0) {\n            cands[d].push_back(build_candidate_from_cells(W, a[d], pathCells[d - 1]));\n        }\n        if (d + 1 < D) {\n            cands[d].push_back(build_candidate_from_cells(W, a[d], pathCells[d + 1]));\n        }\n        dedup_and_trim(cands[d], MAX_CAND);\n        if (cands[d].empty()) cands[d].push_back(fallback_horizontal(W, a[d]));\n    }\n\n    // Final DP\n    auto [cost2, choice] = solve_dp(cands);\n\n    for (int d = 0; d < D; d++) {\n        const auto& rects = cands[d][choice[d]].rects;\n        for (int k = 0; k < N; k++) {\n            const auto& r = rects[k];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\nstatic constexpr int N = 9;\nstatic constexpr int K = 81;\nstatic constexpr int CELLS = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return static_cast<int>(next_u64() % static_cast<uint64_t>(n));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / (1ULL << 53));\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Action {\n    uint8_t cell[9];\n    uint32_t val[9];\n    uint32_t thr[9];  // MOD - val\n    long long raw = 0; // sum of val[0..8]\n    int m = 0, p = 0, q = 0;\n};\n\nstruct State {\n    array<uint32_t, CELLS> board{};\n    array<int, K> ops{};\n    long long score = 0; // sum(board)\n};\n\ninline long long gain_add(const uint32_t* b, const Action& a) {\n    int wraps = 0;\n    for (int k = 0; k < 9; k++) wraps += (b[a.cell[k]] >= a.thr[k]);\n    return a.raw - 1LL * MOD * wraps;\n}\n\ninline void apply_add(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        const int idx = a.cell[k];\n        const uint32_t oldv = b[idx];\n        uint32_t nv = oldv + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)oldv;\n    }\n}\n\ninline void apply_remove(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        const int idx = a.cell[k];\n        const uint32_t oldv = b[idx];\n        const uint32_t v = a.val[k];\n        uint32_t nv = (oldv >= v) ? (oldv - v) : (oldv + MOD - v);\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)oldv;\n    }\n}\n\nState make_empty_state(const array<uint32_t, CELLS>& base, int dummy_id) {\n    State st;\n    st.board = base;\n    st.ops.fill(dummy_id);\n    long long s = 0;\n    for (uint32_t v : base) s += v;\n    st.score = s;\n    return st;\n}\n\ninline void shuffle_order(array<int, K>& ord, XorShift64& rng) {\n    for (int i = K - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nbool one_sweep(State& st, const vector<Action>& actions, int dummy_id,\n               array<int, K>& order, XorShift64& rng) {\n    shuffle_order(order, rng);\n    bool changed = false;\n    const int A = dummy_id;\n\n    for (int t = 0; t < K; t++) {\n        const int pos = order[t];\n        const int old = st.ops[pos];\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int best = dummy_id;\n        long long best_gain = 0; // dummy\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            const long long g = gain_add(b, actions[id]);\n            if (g > best_gain || (g == best_gain && id == old)) {\n                best_gain = g;\n                best = id;\n            }\n        }\n\n        if (best != dummy_id) apply_add(st, actions[best]);\n        st.ops[pos] = best;\n        if (best != old) changed = true;\n    }\n    return changed;\n}\n\nvoid local_opt(State& st, const vector<Action>& actions, int dummy_id,\n               Timer& timer, double tl, XorShift64& rng, int max_sweeps) {\n    array<int, K> order;\n    iota(order.begin(), order.end(), 0);\n    for (int sw = 0; sw < max_sweeps; sw++) {\n        if (timer.elapsed() >= tl) break;\n        bool ch = one_sweep(st, actions, dummy_id, order, rng);\n        if (!ch) break;\n    }\n}\n\nState construct_best_greedy(const array<uint32_t, CELLS>& base,\n                            const vector<Action>& actions, int dummy_id) {\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        int best = dummy_id;\n        long long best_gain = 0;\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain) {\n                best_gain = g;\n                best = id;\n            }\n        }\n        if (best == dummy_id) break;\n        st.ops[pos] = best;\n        apply_add(st, actions[best]);\n    }\n    return st;\n}\n\nState construct_random_greedy(const array<uint32_t, CELLS>& base,\n                              const vector<Action>& actions, int dummy_id,\n                              XorShift64& rng, int topR) {\n    constexpr int MAX_TOP = 8;\n    topR = max(1, min(topR, MAX_TOP));\n\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        array<long long, MAX_TOP> topG;\n        array<int, MAX_TOP> topId;\n        topG.fill(LLONG_MIN);\n        topId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g <= 0) continue;\n            if (g <= topG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > topG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                topG[t] = topG[t - 1];\n                topId[t] = topId[t - 1];\n            }\n            topG[at] = g;\n            topId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && topId[cnt] != -1) cnt++;\n        if (cnt == 0) break;\n\n        int pick;\n        int r = rng.next_int(100);\n        if (r < 55) pick = topId[0];\n        else if (r < 80) pick = topId[rng.next_int(min(cnt, 2))];\n        else pick = topId[rng.next_int(cnt)];\n\n        st.ops[pos] = pick;\n        apply_add(st, actions[pick]);\n    }\n    return st;\n}\n\nvoid random_perturb(State& st, const vector<Action>& actions, int dummy_id,\n                    XorShift64& rng, int cnt) {\n    const int A = dummy_id;\n    for (int t = 0; t < cnt; t++) {\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n\n        int nid;\n        int r = rng.next_int(100);\n        if (r < 12) nid = dummy_id;\n        else nid = rng.next_int(A);\n\n        if (nid == old) continue;\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n    }\n}\n\nvoid destroy_repair(State& st, const vector<Action>& actions, int dummy_id,\n                    XorShift64& rng, int remove_cnt, int topR) {\n    constexpr int MAX_TOP = 8;\n    remove_cnt = max(0, min(remove_cnt, K));\n    if (remove_cnt == 0) return;\n    topR = max(1, min(topR, MAX_TOP));\n\n    array<int, K> ord;\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int i = 0; i < remove_cnt; i++) {\n        int j = i + rng.next_int(K - i);\n        swap(ord[i], ord[j]);\n    }\n\n    array<int, K> removed_pos{};\n    for (int i = 0; i < remove_cnt; i++) {\n        int pos = ord[i];\n        removed_pos[i] = pos;\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n        st.ops[pos] = dummy_id;\n    }\n\n    for (int i = remove_cnt - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(removed_pos[i], removed_pos[j]);\n    }\n\n    const int A = dummy_id;\n    for (int i = 0; i < remove_cnt; i++) {\n        int pos = removed_pos[i];\n\n        array<long long, MAX_TOP> topG;\n        array<int, MAX_TOP> topId;\n        topG.fill(LLONG_MIN);\n        topId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g <= 0) continue;\n            if (g <= topG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > topG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                topG[t] = topG[t - 1];\n                topId[t] = topId[t - 1];\n            }\n            topG[at] = g;\n            topId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && topId[cnt] != -1) cnt++;\n\n        int pick = dummy_id;\n        if (cnt > 0) {\n            int r = rng.next_int(100);\n            if (r < 8) pick = dummy_id;\n            else if (r < 63) pick = topId[0];\n            else if (r < 85) pick = topId[rng.next_int(min(cnt, 2))];\n            else pick = topId[rng.next_int(cnt)];\n        }\n\n        st.ops[pos] = pick;\n        if (pick != dummy_id) apply_add(st, actions[pick]);\n    }\n}\n\nbool pair_improve_once(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, int top_first) {\n    constexpr int MAX_TOP = 8;\n    top_first = max(1, min(top_first, MAX_TOP));\n\n    int p1 = rng.next_int(K);\n    int p2 = rng.next_int(K - 1);\n    if (p2 >= p1) p2++;\n\n    long long before = st.score;\n\n    int old1 = st.ops[p1];\n    int old2 = st.ops[p2];\n\n    if (old1 != dummy_id) apply_remove(st, actions[old1]);\n    if (old2 != dummy_id) apply_remove(st, actions[old2]);\n    st.ops[p1] = dummy_id;\n    st.ops[p2] = dummy_id;\n\n    array<long long, MAX_TOP> firstG;\n    array<int, MAX_TOP> firstId;\n    firstG.fill(LLONG_MIN);\n    firstId.fill(-1);\n\n    const int A = dummy_id;\n    {\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]); // allow negative here\n            if (g <= firstG[top_first - 1]) continue;\n\n            int at = top_first - 1;\n            while (at > 0 && g > firstG[at - 1]) --at;\n            for (int t = top_first - 1; t > at; --t) {\n                firstG[t] = firstG[t - 1];\n                firstId[t] = firstId[t - 1];\n            }\n            firstG[at] = g;\n            firstId[at] = id;\n        }\n    }\n\n    array<long long, MAX_TOP + 1> candG{};\n    array<int, MAX_TOP + 1> candId{};\n    int candCnt = 1;\n    candG[0] = 0;\n    candId[0] = dummy_id;\n    for (int i = 0; i < top_first; i++) {\n        if (firstId[i] == -1) break;\n        candG[candCnt] = firstG[i];\n        candId[candCnt] = firstId[i];\n        candCnt++;\n    }\n\n    long long bestTot = LLONG_MIN;\n    int best1 = dummy_id, best2 = dummy_id;\n\n    for (int c = 0; c < candCnt; c++) {\n        int id1 = candId[c];\n        long long g1 = candG[c];\n\n        if (id1 != dummy_id) apply_add(st, actions[id1]);\n\n        long long bestg2 = 0;\n        int bestid2 = dummy_id;\n        const uint32_t* b2 = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g2 = gain_add(b2, actions[id]);\n            if (g2 > bestg2) {\n                bestg2 = g2;\n                bestid2 = id;\n            }\n        }\n\n        long long tot = g1 + bestg2;\n        if (tot > bestTot) {\n            bestTot = tot;\n            best1 = id1;\n            best2 = bestid2;\n        }\n\n        if (id1 != dummy_id) apply_remove(st, actions[id1]);\n    }\n\n    if (best1 != dummy_id) apply_add(st, actions[best1]);\n    if (best2 != dummy_id) apply_add(st, actions[best2]);\n    st.ops[p1] = best1;\n    st.ops[p2] = best2;\n\n    if (st.score > before) return true;\n\n    // revert\n    if (best1 != dummy_id) apply_remove(st, actions[best1]);\n    if (best2 != dummy_id) apply_remove(st, actions[best2]);\n\n    if (old1 != dummy_id) apply_add(st, actions[old1]);\n    if (old2 != dummy_id) apply_add(st, actions[old2]);\n    st.ops[p1] = old1;\n    st.ops[p2] = old2;\n    return false;\n}\n\nbool pair_local_search(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, int trials, int top_first,\n                       Timer& timer, double tl) {\n    bool improved = false;\n    for (int t = 0; t < trials; t++) {\n        if ((t & 3) == 0 && timer.elapsed() >= tl) break;\n        if (pair_improve_once(st, actions, dummy_id, rng, top_first)) improved = true;\n    }\n    return improved;\n}\n\nvoid insert_elite(vector<State>& elite, const State& cand, int cap) {\n    elite.push_back(cand);\n    sort(elite.begin(), elite.end(), [](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n\n    vector<State> nxt;\n    nxt.reserve(cap);\n    for (const auto& s : elite) {\n        bool dup = false;\n        for (const auto& t : nxt) {\n            if (s.score == t.score && s.ops == t.ops) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) nxt.push_back(s);\n        if ((int)nxt.size() >= cap) break;\n    }\n    elite.swap(nxt);\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    array<uint32_t, CELLS> base{};\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(n); mix(m); mix(k);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            uint32_t v;\n            cin >> v;\n            base[i * N + j] = v;\n            mix(v);\n        }\n    }\n\n    vector<array<array<uint32_t, 3>, 3>> stamp(m);\n    for (int mm = 0; mm < m; mm++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                uint32_t v;\n                cin >> v;\n                stamp[mm][i][j] = v;\n                mix(v);\n            }\n        }\n    }\n\n    vector<Action> actions;\n    actions.reserve(m * (N - 2) * (N - 2));\n\n    for (int mm = 0; mm < m; mm++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action ac;\n                ac.m = mm;\n                ac.p = p;\n                ac.q = q;\n                ac.raw = 0;\n\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        uint32_t v = stamp[mm][i][j];\n                        ac.val[t] = v;\n                        ac.thr[t] = MOD - v;\n                        ac.cell[t] = static_cast<uint8_t>((p + i) * N + (q + j));\n                        ac.raw += v;\n                        t++;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n\n    const int dummy_id = (int)actions.size(); // 980\n    XorShift64 rng(seed);\n    Timer timer;\n    const double TL = 1.92;\n\n    // Initial solution: deterministic greedy + local optimization\n    State best = construct_best_greedy(base, actions, dummy_id);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 50);\n    pair_local_search(best, actions, dummy_id, rng, 14, 6, timer, TL);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 20);\n\n    const int ELITE_CAP = 7;\n    vector<State> elite;\n    elite.reserve(ELITE_CAP + 2);\n    elite.push_back(best);\n\n    // Randomized multi-start initialization\n    for (int t = 0; t < 12; t++) {\n        if (timer.elapsed() >= TL * 0.25) break;\n        int topR = 3 + rng.next_int(5); // 3..7\n        State cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 26);\n        if (rng.next_int(100) < 60) {\n            pair_local_search(cand, actions, dummy_id, rng, 8, 6, timer, TL);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 10);\n        }\n        if (cand.score > best.score) best = cand;\n        insert_elite(elite, cand, ELITE_CAP);\n    }\n\n    // Main diversified search\n    while (timer.elapsed() < TL * 0.90) {\n        int eidx = (rng.next_int(100) < 60) ? 0 : rng.next_int((int)elite.size());\n        State cand = elite[eidx];\n\n        double phase = timer.elapsed() / TL;\n        int r = rng.next_int(100);\n\n        if (r < 55) {\n            int rem = (phase < 0.45) ? (4 + rng.next_int(10)) : (3 + rng.next_int(7));\n            int topR = 3 + rng.next_int(3); // 3..5\n            destroy_repair(cand, actions, dummy_id, rng, rem, topR);\n        } else if (r < 78) {\n            int cnt = (phase < 0.45) ? (2 + rng.next_int(18)) : (1 + rng.next_int(10));\n            random_perturb(cand, actions, dummy_id, rng, cnt);\n        } else if (r < 92) {\n            int rem = 12 + rng.next_int(20); // larger shake\n            destroy_repair(cand, actions, dummy_id, rng, rem, 4);\n        } else {\n            int topR = 3 + rng.next_int(5);\n            cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 10);\n\n        if (rng.next_int(100) < 35) {\n            pair_local_search(cand, actions, dummy_id, rng, 6, 6, timer, TL);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 6);\n        }\n\n        if (cand.score > best.score) best = cand;\n        insert_elite(elite, cand, ELITE_CAP);\n    }\n\n    // Final intensification around best\n    State cur = best;\n    while (timer.elapsed() < TL) {\n        bool improved = pair_local_search(cur, actions, dummy_id, rng, 24, 6, timer, TL);\n        long long pre = cur.score;\n        local_opt(cur, actions, dummy_id, timer, TL, rng, 20);\n\n        if (cur.score > best.score) {\n            best = cur;\n            improved = true;\n        }\n\n        if (!improved && cur.score <= pre) {\n            cur = best;\n            int rem = 3 + rng.next_int(7);\n            destroy_repair(cur, actions, dummy_id, rng, rem, 3);\n            local_opt(cur, actions, dummy_id, timer, TL, rng, 8);\n            if (cur.score > best.score) best = cur;\n            cur = best;\n        } else {\n            cur = best;\n        }\n    }\n\n    vector<tuple<int, int, int>> ans;\n    ans.reserve(K);\n    for (int pos = 0; pos < K; pos++) {\n        int id = best.ops[pos];\n        if (id == dummy_id) continue;\n        const auto& ac = actions[id];\n        ans.emplace_back(ac.m, ac.p, ac.q);\n    }\n\n    cout << ans.size() << '\\n';\n    for (auto [mm, p, q] : ans) {\n        cout << mm << ' ' << p << ' ' << q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct GreedySolver {\n    int N;\n    vector<vector<int>> A;\n\n    vector<int> nextIn;\n    vector<vector<int>> grid; // -1 or container id\n    int pr = 0, pc = 0;\n    int hold = -1;\n\n    vector<int> srcRow, srcIdx;\n    vector<char> dispatched;\n    vector<int> need;\n    int dispatchedCnt = 0;\n\n    int turn = 0;\n    int revealRow = -1;\n\n    vector<string> out;\n\n    GreedySolver(int n, const vector<vector<int>>& a) : N(n), A(a) {\n        nextIn.assign(N, 0);\n        grid.assign(N, vector<int>(N, -1));\n        srcRow.assign(N * N, -1);\n        srcIdx.assign(N * N, -1);\n        dispatched.assign(N * N, 0);\n        need.resize(N);\n        out.assign(N, \"\");\n\n        for (int r = 0; r < N; r++) need[r] = r * N;\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n    }\n\n    inline int md(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    void spawn_step() {\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] >= N) continue;\n            if (grid[r][0] != -1) continue;\n            if (pr == r && pc == 0 && hold != -1) continue; // holding crane blocks spawn\n            grid[r][0] = A[r][nextIn[r]];\n            nextIn[r]++;\n        }\n    }\n\n    void dispatch_step() {\n        int dc = N - 1;\n        for (int r = 0; r < N; r++) {\n            if (grid[r][dc] == -1) continue;\n            int v = grid[r][dc];\n            grid[r][dc] = -1;\n\n            if (!dispatched[v]) {\n                dispatched[v] = 1;\n                dispatchedCnt++;\n            }\n\n            int dr = v / N;\n            int hi = dr * N + (N - 1);\n            while (need[dr] <= hi && dispatched[need[dr]]) need[dr]++;\n        }\n    }\n\n    // One turn: spawn -> action -> dispatch\n    void apply(char act) {\n        if (turn >= 10000) return;\n\n        spawn_step();\n\n        char real = act;\n        if (act == 'P') {\n            if (!(hold == -1 && grid[pr][pc] != -1)) real = '.';\n        } else if (act == 'Q') {\n            if (!(hold != -1 && grid[pr][pc] == -1)) real = '.';\n        } else if (act == 'U') {\n            if (pr == 0) real = '.';\n        } else if (act == 'D') {\n            if (pr == N - 1) real = '.';\n        } else if (act == 'L') {\n            if (pc == 0) real = '.';\n        } else if (act == 'R') {\n            if (pc == N - 1) real = '.';\n        } else if (act != '.') {\n            real = '.';\n        }\n\n        switch (real) {\n            case 'P':\n                hold = grid[pr][pc];\n                grid[pr][pc] = -1;\n                break;\n            case 'Q':\n                grid[pr][pc] = hold;\n                hold = -1;\n                break;\n            case 'U': pr--; break;\n            case 'D': pr++; break;\n            case 'L': pc--; break;\n            case 'R': pc++; break;\n            case '.': break;\n        }\n\n        dispatch_step();\n\n        out[0].push_back(real);\n        if (turn == 0) {\n            for (int i = 1; i < N; i++) out[i].push_back('B');\n        } else {\n            for (int i = 1; i < N; i++) out[i].push_back('.');\n        }\n        turn++;\n    }\n\n    bool find_container(int v, int &rr, int &cc) const {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == v) {\n                    rr = r; cc = c;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool has_ready_container(int &bestV, int &bestR, int &bestC) const {\n        int bestScore = INT_MAX;\n        bestV = -1; bestR = -1; bestC = -1;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (!find_container(x, r, c)) continue;\n\n            int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestV = x; bestR = r; bestC = c;\n            }\n        }\n        return bestV != -1;\n    }\n\n    int choose_reveal_row() const {\n        int bestRow = -1;\n        int bestScore = INT_MAX;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (find_container(x, r, c)) continue;\n\n            int s = srcRow[x];\n            int frontIdx = (grid[s][0] != -1 ? nextIn[s] - 1 : nextIn[s]);\n            int depth = srcIdx[x] - frontIdx;\n            if (depth < 0) depth = 0;\n\n            int sc = depth * 90 + md(pr, pc, s, 0);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestRow = dr;\n            }\n        }\n        return bestRow;\n    }\n\n    pair<int,int> choose_storage_cell() const {\n        int bestR = -1, bestC = -1;\n        int bestScore = INT_MAX;\n        int dr = (hold == -1 ? 0 : hold / N);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c <= N - 2; c++) {\n                if (grid[r][c] != -1) continue;\n                int penalty = (c == 0 && nextIn[r] < N) ? 40 : 0;\n                int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1) + penalty;\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestR = r;\n                    bestC = c;\n                }\n            }\n        }\n        return {bestR, bestC};\n    }\n\n    void move_to(int tr, int tc) {\n        while (turn < 10000 && (pr != tr || pc != tc)) {\n            char d;\n            if (pc < tc) d = 'R';\n            else if (pc > tc) d = 'L';\n            else if (pr < tr) d = 'D';\n            else d = 'U';\n            apply(d);\n        }\n    }\n\n    void dispatch_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        int dr = hold / N;\n        move_to(dr, N - 1);\n        if (turn < 10000) apply('Q');\n    }\n\n    void store_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        auto [sr, sc] = choose_storage_cell();\n        if (sr == -1) return;\n        move_to(sr, sc);\n        if (turn < 10000) apply('Q');\n    }\n\n    void solve() {\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                int dr = hold / N;\n                int hi = dr * N + (N - 1);\n                if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                else store_holding();\n                revealRow = -1;\n                continue;\n            }\n\n            int v, r, c;\n            if (has_ready_container(v, r, c)) {\n                revealRow = -1;\n                move_to(r, c);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) {\n                    int dr = hold / N;\n                    int hi = dr * N + (N - 1);\n                    if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                    else store_holding();\n                }\n                continue;\n            }\n\n            if (revealRow != -1) {\n                int hi = revealRow * N + (N - 1);\n                if (need[revealRow] > hi) revealRow = -1;\n                else {\n                    int rr, cc;\n                    if (find_container(need[revealRow], rr, cc)) revealRow = -1;\n                }\n            }\n            if (revealRow == -1) revealRow = choose_reveal_row();\n\n            if (revealRow == -1) {\n                // fallback: pick nearest container\n                int bestR = -1, bestC = -1, bestScore = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    for (int j = 0; j < N; j++) {\n                        int val = grid[i][j];\n                        if (val == -1) continue;\n                        int dr = val / N;\n                        int sc = md(pr, pc, i, j) + md(i, j, dr, N - 1);\n                        if (sc < bestScore) {\n                            bestScore = sc;\n                            bestR = i; bestC = j;\n                        }\n                    }\n                }\n\n                if (bestR == -1) {\n                    apply('.');\n                    continue;\n                }\n\n                move_to(bestR, bestC);\n                if (turn >= 10000) break;\n                apply('P');\n\n                if (hold != -1) {\n                    int dr = hold / N;\n                    int hi = dr * N + (N - 1);\n                    if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                    else store_holding();\n                }\n                revealRow = -1;\n                continue;\n            }\n\n            int x = need[revealRow];\n            int s = srcRow[x];\n\n            move_to(s, 0);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold == -1) {\n                revealRow = -1;\n                continue;\n            }\n\n            int y = hold;\n            int dr = y / N;\n            int hi = dr * N + (N - 1);\n\n            if (need[dr] <= hi && y == need[dr]) {\n                revealRow = -1;\n                dispatch_holding();\n            } else {\n                store_holding();\n            }\n        }\n\n        if (turn < 10000 && hold != -1) {\n            int dr = hold / N;\n            int hi = dr * N + (N - 1);\n            if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n            else store_holding();\n        }\n\n        // Safety cleanup\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                int dr = hold / N;\n                int hi = dr * N + (N - 1);\n                if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                else store_holding();\n                continue;\n            }\n\n            int bestR = -1, bestC = -1, bestScore = INT_MAX;\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    int val = grid[i][j];\n                    if (val == -1) continue;\n                    int dr = val / N;\n                    int sc = md(pr, pc, i, j) + md(i, j, dr, N - 1);\n                    if (sc < bestScore) {\n                        bestScore = sc;\n                        bestR = i; bestC = j;\n                    }\n                }\n            }\n\n            if (bestR == -1) {\n                bool anyQueue = false;\n                for (int r = 0; r < N; r++) if (nextIn[r] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(bestR, bestC);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) {\n                int dr = hold / N;\n                int hi = dr * N + (N - 1);\n                if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                else store_holding();\n            }\n        }\n\n        if (out[0].empty()) apply('.');\n    }\n};\n\nstruct BeamSolver {\n    static constexpr int N = 5;\n    vector<vector<int>> A;\n    array<int, 25> srcRow{}, srcIdx{};\n    int dist[25][25]{};\n\n    struct State {\n        array<int8_t, 25> cell;   // -1 empty, 0..24 container\n        array<int8_t, 25> loc;    // -3 dispatched, -2 hold, -1 not yet on grid, 0..24 on grid\n        array<uint8_t, 5> nextIn; // 0..5\n        array<uint8_t, 5> need;   // row-wise required container\n        int8_t hold;              // -1 or 0..24\n        uint8_t pos;              // 0..24\n    };\n\n    struct Trace {\n        int parent;\n        char act;\n    };\n\n    struct BeamItem {\n        State st;\n        int trace;\n        int eval;\n    };\n\n    struct Cand {\n        State st;\n        int parentTrace;\n        char act;\n        int eval;\n        uint64_t h;\n    };\n\n    BeamSolver(const vector<vector<int>>& a) : A(a) {\n        srcRow.fill(-1);\n        srcIdx.fill(-1);\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n        for (int i = 0; i < 25; i++) {\n            for (int j = 0; j < 25; j++) {\n                dist[i][j] = abs(i / N - j / N) + abs(i % N - j % N);\n            }\n        }\n    }\n\n    State initial_state() const {\n        State s;\n        s.cell.fill(-1);\n        s.loc.fill(-1);\n        s.nextIn.fill(0);\n        for (int r = 0; r < N; r++) s.need[r] = (uint8_t)(r * N);\n        s.hold = -1;\n        s.pos = 0;\n        return s;\n    }\n\n    inline int dispatched_count(const State& s) const {\n        int d = 0;\n        for (int r = 0; r < N; r++) d += (int)s.need[r] - r * N;\n        return d;\n    }\n\n    inline bool is_goal(const State& s) const {\n        return dispatched_count(s) == 25 && s.hold == -1;\n    }\n\n    void spawn(State& s) const {\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] != -1) continue;\n            if (s.pos == g && s.hold != -1) continue;\n            int v = A[r][s.nextIn[r]];\n            s.nextIn[r]++;\n            s.cell[g] = (int8_t)v;\n            s.loc[v] = (int8_t)g;\n        }\n    }\n\n    bool apply_action_dispatch(const State& sp, char act, State& ns) const {\n        ns = sp;\n        int p = ns.pos;\n        int r = p / N, c = p % N;\n\n        switch (act) {\n            case '.':\n                break;\n            case 'P': {\n                if (ns.hold != -1) return false;\n                int v = ns.cell[p];\n                if (v < 0) return false;\n                ns.hold = (int8_t)v;\n                ns.cell[p] = -1;\n                ns.loc[v] = -2;\n                break;\n            }\n            case 'Q': {\n                if (ns.hold == -1) return false;\n                if (ns.cell[p] != -1) return false;\n                if (c == N - 1) {\n                    if (ns.hold != (int8_t)ns.need[r]) return false;\n                }\n                int v = ns.hold;\n                ns.hold = -1;\n                ns.cell[p] = (int8_t)v;\n                ns.loc[v] = (int8_t)p;\n                break;\n            }\n            case 'U':\n                if (r == 0) return false;\n                ns.pos = (uint8_t)(p - N);\n                break;\n            case 'D':\n                if (r == N - 1) return false;\n                ns.pos = (uint8_t)(p + N);\n                break;\n            case 'L':\n                if (c == 0) return false;\n                ns.pos = (uint8_t)(p - 1);\n                break;\n            case 'R':\n                if (c == N - 1) return false;\n                ns.pos = (uint8_t)(p + 1);\n                break;\n            default:\n                return false;\n        }\n\n        // Enforce perfect gate correctness & order\n        for (int rr = 0; rr < N; rr++) {\n            int idx = rr * N + (N - 1);\n            int v = ns.cell[idx];\n            if (v == -1) continue;\n            if (v != ns.need[rr]) return false;\n            ns.need[rr]++;\n            ns.cell[idx] = -1;\n            ns.loc[v] = -3;\n        }\n\n        return true;\n    }\n\n    int lower_bound(const State& s) const {\n        int lb = 0;\n        int pos = s.pos;\n\n        for (int v = 0; v < 25; v++) {\n            int dr = v / N;\n            if (v < (int)s.need[dr]) continue;\n\n            int gate = dr * N + (N - 1);\n            if (s.hold == v) {\n                lb += dist[pos][gate] + 1; // only drop needed\n                continue;\n            }\n\n            int lp = s.loc[v];\n            if (lp >= 0) {\n                lb += dist[lp][gate] + 2; // pick + carry + drop\n            } else if (lp == -1) {\n                int sr = srcRow[v];\n                lb += (abs(sr - dr) + (N - 1)) + 2;\n            } else if (lp == -2) {\n                lb += dist[pos][gate] + 1;\n            }\n        }\n        return lb;\n    }\n\n    int eval_state(const State& s, int lb) const {\n        int disp = dispatched_count(s);\n        int ready = 0;\n        for (int r = 0; r < N; r++) {\n            int x = s.need[r];\n            if (x >= r * N + N) continue;\n            if (s.hold == x || s.loc[x] >= 0) ready++;\n        }\n\n        int e = disp * 100000 - lb * 450 + ready * 2500;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            if (v == s.need[dr]) {\n                e += 6000 - dist[s.pos][dr * N + (N - 1)] * 180;\n            } else {\n                e -= 1200;\n            }\n        }\n\n        // Penalize putting unrelated container on active receiving gate\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] == -1) continue;\n            if (s.nextIn[r] == 0) continue;\n            int expected = A[r][s.nextIn[r] - 1];\n            if ((int)s.cell[g] != expected) e -= 5000;\n        }\n\n        return e;\n    }\n\n    uint64_t hash_state(const State& s) const {\n        uint64_t h = 1469598103934665603ULL;\n        auto add = [&](uint8_t x) {\n            h ^= x;\n            h *= 1099511628211ULL;\n        };\n\n        add((uint8_t)s.pos);\n        add((uint8_t)(s.hold + 1));\n        for (int r = 0; r < N; r++) {\n            add(s.nextIn[r]);\n            add((uint8_t)((int)s.need[r] - r * N));\n        }\n        for (int i = 0; i < 25; i++) {\n            add((uint8_t)(s.cell[i] + 1));\n        }\n        return h;\n    }\n\n    void gen_actions(const State& s, array<char, 8>& acts, int& acnt) const {\n        acnt = 0;\n        bool used[256] = {};\n        auto add = [&](char ch) {\n            unsigned u = (unsigned char)ch;\n            if (!used[u]) {\n                used[u] = true;\n                acts[acnt++] = ch;\n            }\n        };\n        auto add_toward = [&](int target) {\n            int p = s.pos;\n            int r = p / N, c = p % N;\n            int tr = target / N, tc = target % N;\n            if (r < tr) add('D');\n            if (r > tr) add('U');\n            if (c < tc) add('R');\n            if (c > tc) add('L');\n        };\n\n        int pos = s.pos;\n        int r = pos / N, c = pos % N;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            int gate = dr * N + (N - 1);\n\n            if (v == s.need[dr]) {\n                if (pos == gate && s.cell[pos] == -1) add('Q');\n                add_toward(gate);\n            } else {\n                if (s.cell[pos] == -1 && c != N - 1) add('Q');\n\n                pair<int,int> cand[25];\n                int m = 0;\n                for (int idx = 0; idx < 25; idx++) {\n                    int rr = idx / N, cc = idx % N;\n                    if (cc == N - 1) continue;\n                    if (s.cell[idx] != -1) continue;\n                    int pen = (cc == 0 && s.nextIn[rr] < N) ? 30 : 0;\n                    int sc = dist[pos][idx] + dist[idx][gate] + pen;\n                    cand[m++] = {sc, idx};\n                }\n                sort(cand, cand + m);\n                for (int i = 0; i < min(2, m); i++) add_toward(cand[i].second);\n            }\n        } else {\n            if (s.cell[pos] != -1) add('P');\n\n            pair<int,int> ready[5];\n            int rcnt = 0;\n            for (int rr = 0; rr < N; rr++) {\n                int x = s.need[rr];\n                if (x >= rr * N + N) continue;\n                int lp = s.loc[x];\n                if (lp >= 0) {\n                    int sc = dist[pos][lp] + dist[lp][rr * N + (N - 1)];\n                    ready[rcnt++] = {sc, lp};\n                }\n            }\n\n            if (rcnt > 0) {\n                sort(ready, ready + rcnt);\n                for (int i = 0; i < min(3, rcnt); i++) {\n                    add_toward(ready[i].second);\n                }\n            } else {\n                pair<int,int> rev[5];\n                int vcnt = 0;\n                for (int rr = 0; rr < N; rr++) {\n                    int x = s.need[rr];\n                    if (x >= rr * N + N) continue;\n                    int src = srcRow[x];\n                    int front = (int)s.nextIn[src] - (s.cell[src * N] == -1 ? 0 : 1);\n                    int depth = srcIdx[x] - front;\n                    if (depth < 0) depth = 0;\n                    int gp = src * N;\n                    int sc = depth * 10 + dist[pos][gp];\n                    rev[vcnt++] = {sc, gp};\n                }\n                sort(rev, rev + vcnt);\n                for (int i = 0; i < min(2, vcnt); i++) {\n                    add_toward(rev[i].second);\n                }\n            }\n        }\n\n        if (acnt < 2) {\n            if (r > 0) add('U');\n            if (r < N - 1) add('D');\n            if (c > 0) add('L');\n            if (c < N - 1) add('R');\n        }\n\n        if (acnt == 0) add('.');\n    }\n\n    vector<char> reconstruct(int traceId, const vector<Trace>& traces) const {\n        vector<char> rev;\n        while (traceId > 0) {\n            rev.push_back(traces[traceId].act);\n            traceId = traces[traceId].parent;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    bool validate(const vector<char>& actions) const {\n        State s = initial_state();\n        for (char a : actions) {\n            State sp = s, ns;\n            spawn(sp);\n            if (!apply_action_dispatch(sp, a, ns)) return false;\n            s = ns;\n        }\n        return is_goal(s);\n    }\n\n    bool search(int boundLen, int width, double timeLimitSec,\n                const chrono::steady_clock::time_point& start,\n                vector<char>& outActions) const {\n        if (boundLen <= 1) return false;\n        int maxDepth = min(boundLen - 1, 10000);\n\n        vector<Trace> traces;\n        traces.reserve((size_t)width * 400 + 16);\n        traces.push_back({-1, '?'});\n\n        vector<BeamItem> cur, nxt;\n        cur.reserve(width + 16);\n        nxt.reserve(width + 16);\n\n        State init = initial_state();\n        int lb0 = lower_bound(init);\n        if (lb0 >= boundLen) return false;\n        cur.push_back({init, 0, eval_state(init, lb0)});\n\n        vector<Cand> cands;\n        cands.reserve((size_t)width * 6 + 100);\n\n        auto time_over = [&]() -> bool {\n            double e = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            return e > timeLimitSec;\n        };\n\n        for (int depth = 0; depth < maxDepth; depth++) {\n            if (time_over()) return false;\n\n            cands.clear();\n\n            int it = 0;\n            for (const auto& bi : cur) {\n                if ((it++ & 127) == 0 && time_over()) return false;\n\n                State sp = bi.st;\n                spawn(sp);\n\n                array<char, 8> acts{};\n                int acnt = 0;\n                gen_actions(sp, acts, acnt);\n\n                for (int i = 0; i < acnt; i++) {\n                    State ns;\n                    char act = acts[i];\n                    if (!apply_action_dispatch(sp, act, ns)) continue;\n\n                    int nd = depth + 1;\n                    if (is_goal(ns)) {\n                        int tr = (int)traces.size();\n                        traces.push_back({bi.trace, act});\n                        outActions = reconstruct(tr, traces);\n                        return true;\n                    }\n\n                    int lb = lower_bound(ns);\n                    if (nd + lb >= boundLen) continue;\n\n                    int ev = eval_state(ns, lb);\n                    uint64_t h = hash_state(ns);\n\n                    cands.push_back({ns, bi.trace, act, ev, h});\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                if (a.h != b.h) return a.h < b.h;\n                return a.eval > b.eval;\n            });\n\n            vector<Cand> uniq;\n            uniq.reserve(cands.size());\n            for (size_t i = 0; i < cands.size();) {\n                size_t j = i + 1;\n                Cand best = cands[i];\n                while (j < cands.size() && cands[j].h == cands[i].h) {\n                    if (cands[j].eval > best.eval) best = cands[j];\n                    j++;\n                }\n                uniq.push_back(std::move(best));\n                i = j;\n            }\n\n            if ((int)uniq.size() > width) {\n                nth_element(uniq.begin(), uniq.begin() + width, uniq.end(),\n                            [](const Cand& a, const Cand& b) {\n                                return a.eval > b.eval;\n                            });\n                uniq.resize(width);\n            }\n\n            nxt.clear();\n            nxt.reserve(uniq.size());\n            for (const auto& cd : uniq) {\n                int tr = (int)traces.size();\n                traces.push_back({cd.parentTrace, cd.act});\n                nxt.push_back({cd.st, tr, cd.eval});\n            }\n\n            cur.swap(nxt);\n            if (cur.empty()) break;\n        }\n\n        return false;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> A(N, vector<int>(N));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> A[i][j];\n    }\n\n    auto start = chrono::steady_clock::now();\n\n    // Robust baseline\n    GreedySolver greedy(N, A);\n    greedy.solve();\n    int greedyLen = (int)greedy.out[0].size();\n\n    // Improvement phase: beam search under strict M1/M2=0 constraints\n    vector<char> beamActs;\n    bool useBeam = false;\n\n    if (greedyLen > 1) {\n        BeamSolver beam(A);\n        int width = 2200;\n        double timeLimitSec = 2.70; // leave margin for system-test slowdown\n        bool ok = beam.search(greedyLen, width, timeLimitSec, start, beamActs);\n        if (ok && !beamActs.empty() && (int)beamActs.size() < greedyLen && beam.validate(beamActs)) {\n            useBeam = true;\n        }\n    }\n\n    if (useBeam) {\n        int T = (int)beamActs.size();\n        string s0;\n        s0.reserve(T);\n        for (char c : beamActs) s0.push_back(c);\n        cout << s0 << '\\n';\n        for (int i = 1; i < N; i++) {\n            string si(T, '.');\n            if (T > 0) si[0] = 'B';\n            else si = \".\";\n            cout << si << '\\n';\n        }\n    } else {\n        for (int i = 0; i < N; i++) {\n            if (greedy.out[i].empty()) {\n                if (i == 0) cout << \".\\n\";\n                else cout << \"B\\n\";\n            } else {\n                cout << greedy.out[i] << '\\n';\n            }\n        }\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SimResult {\n    long long cost = (1LL << 62);\n    int turns = 0;\n    bool valid = false;\n    vector<string> ops;\n};\n\nclass Solver {\n    static constexpr int MAX_TURNS = 100000;\n    static constexpr long long INF = (1LL << 62);\n\n    int N = 0;\n    int M = 0;\n    vector<int> init_h;\n    vector<int> rr, cc;\n    uint64_t input_hash = 0;\n\n    int modM(int x) const {\n        x %= M;\n        if (x < 0) x += M;\n        return x;\n    }\n\n    static uint64_t xorshift64(uint64_t &x) {\n        if (x == 0) x = 88172645463325252ULL;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n\n    vector<int> buildBaseCycle() const {\n        // Hamiltonian cycle for even N\n        vector<int> cyc;\n        cyc.reserve(M);\n\n        // top row\n        for (int c = 0; c < N; c++) cyc.push_back(c);\n\n        // rows 1..N-1 excluding col 0 (serpentine)\n        for (int r = 1; r < N; r++) {\n            if (r & 1) {\n                for (int c = N - 1; c >= 1; c--) cyc.push_back(r * N + c);\n            } else {\n                for (int c = 1; c < N; c++) cyc.push_back(r * N + c);\n            }\n        }\n\n        // col 0 from bottom to row 1\n        for (int r = N - 1; r >= 1; r--) cyc.push_back(r * N);\n\n        return cyc;\n    }\n\n    pair<int, int> transformPoint(int r, int c, int t) const {\n        switch (t) {\n            case 0: return {r, c};                         // identity\n            case 1: return {r, N - 1 - c};                 // mirror vertical\n            case 2: return {N - 1 - r, c};                 // mirror horizontal\n            case 3: return {N - 1 - r, N - 1 - c};         // rotate 180\n            case 4: return {c, r};                         // transpose\n            case 5: return {c, N - 1 - r};                 // rotate 90\n            case 6: return {N - 1 - c, r};                 // rotate 270\n            case 7: return {N - 1 - c, N - 1 - r};         // anti-diagonal mirror\n        }\n        return {r, c};\n    }\n\n    vector<int> transformCycle(const vector<int> &base, int t) const {\n        vector<int> v;\n        v.reserve(M);\n        for (int id : base) {\n            int r = id / N, c = id % N;\n            auto [nr, nc] = transformPoint(r, c, t);\n            v.push_back(nr * N + nc);\n        }\n        auto it = find(v.begin(), v.end(), 0);\n        if (it != v.end()) rotate(v.begin(), it, v.end());\n        return v;\n    }\n\n    template <bool RECORD>\n    SimResult simulateCycle(const vector<int> &cyc, int dir, int shift, long long cutoff = INF) const {\n        vector<int> h = init_h;\n        long long posRemain = 0, negRemain = 0;\n        for (int x : h) {\n            if (x > 0) posRemain += x;\n            else negRemain += -x;\n        }\n\n        long long cost = 0;\n        long long load = 0;\n        int turns = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(20000);\n\n        int pos = 0;\n        int idx = 0;\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        auto unloadHere = [&]() {\n            if (load <= 0) return;\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n        };\n\n        // initial shift\n        for (int t = 0; t < shift; t++) {\n            idx = modM(idx + dir);\n            if (!doMove(cyc[idx])) return fail();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n        }\n\n        // one pass\n        for (int t = 0; t < M; t++) {\n            int cell = cyc[idx];\n            int v = h[cell];\n            if (v > 0) {\n                doLoad(v);\n                h[cell] = 0;\n            } else if (v < 0) {\n                int d = (int)min<long long>(load, -1LL * v);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                idx = modM(idx + dir);\n                if (!doMove(cyc[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // cleanup deficits\n        while (load > 0) {\n            unloadHere();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            if (load == 0) break;\n\n            int best = -1;\n            int bestDist = INT_MAX;\n            int bestDef = -1;\n            int pr = rr[pos], pc = cc[pos];\n\n            for (int id = 0; id < M; id++) {\n                if (h[id] < 0) {\n                    int dist = abs(pr - rr[id]) + abs(pc - cc[id]);\n                    int def = -h[id];\n                    if (dist < bestDist || (dist == bestDist && def > bestDef)) {\n                        bestDist = dist;\n                        bestDef = def;\n                        best = id;\n                    }\n                }\n            }\n            if (best == -1) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (nxt == -1) return fail();\n                if (!doMove(nxt)) return fail();\n                unloadHere();\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (posRemain == 0 && negRemain == 0 && load == 0 && turns <= MAX_TURNS);\n\n        SimResult res;\n        res.cost = valid ? cost : INF;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) {\n            if (valid) res.ops = move(ops);\n        }\n        return res;\n    }\n\n    struct GreedyParam {\n        int cap = 1000000000;\n        int src_bias = 0;\n        int dst_bias = 0;\n        bool collect_when_loaded = false;\n        int axis_pref = 2; // 0: vertical, 1: horizontal, 2: adaptive\n        int dist_scale = 256;\n        int path_unload_bonus = 120;\n        int path_load_bonus = 60;\n    };\n\n    template <bool RECORD>\n    SimResult simulateGreedy(const GreedyParam &p, uint64_t seed, long long cutoff = INF) const {\n        vector<int> h = init_h;\n        long long posRemain = 0, negRemain = 0;\n        for (int x : h) {\n            if (x > 0) posRemain += x;\n            else negRemain += -x;\n        }\n\n        long long cost = 0;\n        long long load = 0;\n        int turns = 0;\n        int pos = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(100000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        auto processHere = [&]() {\n            if (h[pos] < 0 && load > 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            bool canLoad = (load == 0 || p.collect_when_loaded);\n            if (canLoad && h[pos] > 0 && load < p.cap) {\n                int d = (int)min<long long>((long long)p.cap - load, (long long)h[pos]);\n                if (d > 0) {\n                    doLoad(d);\n                    h[pos] -= d;\n                }\n            }\n        };\n\n        auto chooseTarget = [&](bool seekSource) -> int {\n            long long bestVal = INF;\n            int best = -1;\n            int bestGain = -1;\n            int pr = rr[pos], pc = cc[pos];\n\n            for (int id = 0; id < M; id++) {\n                int amt = seekSource ? h[id] : -h[id];\n                if (amt <= 0) continue;\n\n                int gain = amt;\n                if (seekSource) {\n                    long long room = (long long)p.cap - load;\n                    if (room <= 0) continue;\n                    gain = (int)min<long long>(gain, room);\n                } else {\n                    if (load <= 0) continue;\n                    gain = (int)min<long long>(gain, load);\n                }\n\n                int dist = abs(pr - rr[id]) + abs(pc - cc[id]);\n                long long val = 1LL * p.dist_scale * dist - 1LL * (seekSource ? p.src_bias : p.dst_bias) * gain;\n\n                if (val < bestVal) {\n                    bestVal = val;\n                    best = id;\n                    bestGain = gain;\n                } else if (val == bestVal) {\n                    if (gain > bestGain) {\n                        best = id;\n                        bestGain = gain;\n                    } else if (gain == bestGain) {\n                        if (xorshift64(seed) & 1ULL) best = id;\n                    }\n                }\n            }\n            return best;\n        };\n\n        auto chooseNext = [&](int target) -> int {\n            int r = rr[pos], c = cc[pos];\n            int tr = rr[target], tc = cc[target];\n\n            int cand[2];\n            int sz = 0;\n            if (r < tr) cand[sz++] = pos + N;\n            else if (r > tr) cand[sz++] = pos - N;\n\n            if (c < tc) cand[sz++] = pos + 1;\n            else if (c > tc) cand[sz++] = pos - 1;\n\n            if (sz == 1) return cand[0];\n\n            auto scoreCell = [&](int id) -> long long {\n                long long sc = 0;\n                int v = h[id];\n                if (load > 0 && v < 0) {\n                    sc += 1LL * p.path_unload_bonus * min<long long>(load, -1LL * v);\n                }\n                bool canLoad = (load == 0 || p.collect_when_loaded) && (load < p.cap);\n                if (canLoad && v > 0) {\n                    sc += 1LL * p.path_load_bonus * min<long long>((long long)p.cap - load, (long long)v);\n                }\n                return sc;\n            };\n\n            int a = cand[0], b = cand[1];\n            long long sa = scoreCell(a), sb = scoreCell(b);\n            if (sa != sb) return (sa > sb ? a : b);\n\n            bool aV = (rr[a] != r);\n            bool bV = (rr[b] != r);\n\n            if (p.axis_pref == 0) {\n                if (aV != bV) return (aV ? a : b);\n            } else if (p.axis_pref == 1) {\n                if (aV != bV) return (aV ? b : a);\n            } else {\n                int dr = abs(tr - r), dc = abs(tc - c);\n                if (dr != dc) {\n                    if (dr > dc) {\n                        if (aV != bV) return (aV ? a : b);\n                    } else {\n                        if (aV != bV) return (aV ? b : a);\n                    }\n                }\n            }\n\n            return (xorshift64(seed) & 1ULL) ? a : b;\n        };\n\n        int stagnation = 0;\n        for (int outer = 0; outer < 200000; outer++) {\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n            long long prevPos = posRemain, prevNeg = negRemain, prevLoad = load;\n            int prevCell = pos;\n\n            processHere();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n            bool seekSource = (load == 0);\n            int target = chooseTarget(seekSource);\n            if (target < 0) return fail();\n\n            int inner = 0;\n            while (pos != target) {\n                int nxt = chooseNext(target);\n                if (!doMove(nxt)) return fail();\n                processHere();\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n                if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n                if (seekSource) {\n                    if (load > 0) break;\n                } else {\n                    if (load == 0) break;\n                }\n\n                if (++inner > 2500) break;\n            }\n\n            if (prevPos == posRemain && prevNeg == negRemain && prevLoad == load && prevCell == pos) {\n                stagnation++;\n            } else {\n                stagnation = 0;\n            }\n            if (stagnation > 2000) return fail();\n        }\n\n        bool valid = (posRemain == 0 && negRemain == 0 && load == 0 && turns <= MAX_TURNS);\n\n        SimResult res;\n        res.cost = valid ? cost : INF;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) {\n            if (valid) res.ops = move(ops);\n        }\n        return res;\n    }\n\n    SimResult searchBestCycle() const {\n        vector<int> base = buildBaseCycle();\n\n        vector<vector<int>> cycles;\n        for (int t = 0; t < 8; t++) {\n            auto cyc = transformCycle(base, t);\n            if ((int)cyc.size() != M) continue;\n            if (cyc[0] != 0) continue;\n\n            bool dup = false;\n            for (auto &v : cycles) {\n                if (v == cyc) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) cycles.push_back(move(cyc));\n        }\n        if (cycles.empty()) cycles.push_back(base);\n\n        long long bestCost = INF;\n        int bestCi = 0, bestDir = 1, bestShift = 0;\n\n        for (int ci = 0; ci < (int)cycles.size(); ci++) {\n            for (int dir : {1, -1}) {\n                for (int shift = 0; shift < M; shift++) {\n                    auto cur = simulateCycle<false>(cycles[ci], dir, shift, bestCost);\n                    if (cur.valid && cur.cost < bestCost) {\n                        bestCost = cur.cost;\n                        bestCi = ci;\n                        bestDir = dir;\n                        bestShift = shift;\n                    }\n                }\n            }\n        }\n\n        if (bestCost >= INF / 2) {\n            return simulateCycle<true>(cycles[0], 1, 0, INF);\n        }\n        return simulateCycle<true>(cycles[bestCi], bestDir, bestShift, INF);\n    }\n\n    SimResult searchBestGreedy(long long cutoff) const {\n        vector<GreedyParam> params;\n        auto addParam = [&](int cap, int bias, bool collect, int axis, int ub, int lb) {\n            GreedyParam p;\n            p.cap = cap;\n            p.src_bias = bias;\n            p.dst_bias = bias;\n            p.collect_when_loaded = collect;\n            p.axis_pref = axis;\n            p.dist_scale = 256;\n            p.path_unload_bonus = ub;\n            p.path_load_bonus = lb;\n            params.push_back(p);\n        };\n\n        const int INF_CAP = 1000000000;\n\n        addParam(200, 0, false, 2, 140, 70);\n        addParam(200, 2, false, 2, 140, 70);\n\n        addParam(400, 0, false, 2, 140, 70);\n        addParam(400, 2, false, 2, 140, 70);\n        addParam(400, 4, false, 2, 140, 70);\n\n        addParam(800, 0, false, 2, 130, 65);\n        addParam(800, 2, false, 2, 130, 65);\n        addParam(800, 2, true,  2, 120, 80);\n        addParam(800, 2, false, 0, 130, 65);\n        addParam(800, 2, false, 1, 130, 65);\n\n        addParam(1600, 0, false, 2, 120, 60);\n        addParam(1600, 2, false, 2, 120, 60);\n        addParam(1600, 1, true,  2, 110, 75);\n\n        addParam(INF_CAP, 0, false, 2, 110, 55);\n        addParam(INF_CAP, 2, false, 2, 110, 55);\n        addParam(INF_CAP, 1, true,  2, 100, 70);\n        addParam(INF_CAP, 2, false, 0, 110, 55);\n        addParam(INF_CAP, 2, false, 1, 110, 55);\n\n        long long bestCost = cutoff;\n        int bestIdx = -1;\n        uint64_t bestSeed = 0;\n\n        const uint64_t MUL = 0x9e3779b97f4a7c15ULL;\n\n        for (int i = 0; i < (int)params.size(); i++) {\n            for (int rep = 0; rep < 2; rep++) {\n                uint64_t seed = input_hash ^ (MUL * (uint64_t)(i * 3 + rep + 1));\n                if (seed == 0) seed = 88172645463325252ULL;\n\n                auto cur = simulateGreedy<false>(params[i], seed, bestCost);\n                if (cur.valid && cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestIdx = i;\n                    bestSeed = seed;\n                }\n            }\n        }\n\n        if (bestIdx == -1) {\n            SimResult none;\n            none.valid = false;\n            none.cost = INF;\n            return none;\n        }\n\n        return simulateGreedy<true>(params[bestIdx], bestSeed, INF);\n    }\n\npublic:\n    void solve() {\n        cin >> N;\n        M = N * N;\n\n        init_h.assign(M, 0);\n        rr.assign(M, 0);\n        cc.assign(M, 0);\n\n        input_hash = 1469598103934665603ULL;\n\n        bool allZero = true;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int x;\n                cin >> x;\n                int id = r * N + c;\n                init_h[id] = x;\n                rr[id] = r;\n                cc[id] = c;\n                if (x != 0) allZero = false;\n\n                input_hash ^= (uint64_t)(x + 1000);\n                input_hash *= 1099511628211ULL;\n            }\n        }\n\n        if (allZero) return;\n\n        SimResult best;\n        best.cost = INF;\n        best.valid = false;\n\n        auto cyc = searchBestCycle();\n        if (cyc.valid && cyc.cost < best.cost) best = move(cyc);\n\n        auto gre = searchBestGreedy(best.valid ? best.cost : INF);\n        if (gre.valid && gre.cost < best.cost) best = move(gre);\n\n        if (!best.valid) {\n            vector<int> base = buildBaseCycle();\n            best = simulateCycle<true>(base, 1, 0, INF);\n        }\n\n        for (const auto &s : best.ops) {\n            cout << s << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // 2^53\n    }\n};\n\nclass Solver {\n    static constexpr int MAXS = 60;\n    static constexpr int MAXM = 15;\n\n    int N{}, M{}, T{};\n    int S{}, P{}; // S=seed count, P=cell count\n    int X[MAXS][MAXM]{}; // seed vectors\n    int V[MAXS]{};       // seed value sums\n    double PS[MAXS][MAXS]{}; // pair scores\n\n    vector<pair<int, int>> edges;   // grid edges (size S)\n    vector<vector<int>> nbr;        // neighbors per position\n    XorShift64 rng;\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    bool read_state() {\n        for (int i = 0; i < S; ++i) {\n            for (int l = 0; l < M; ++l) {\n                if (!(cin >> X[i][l])) return false;\n                if (X[i][l] < 0) exit(0); // interactive error signal safeguard\n            }\n            for (int l = M; l < MAXM; ++l) X[i][l] = 0;\n        }\n        return true;\n    }\n\n    void build_graph() {\n        edges.clear();\n        nbr.assign(P, {});\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p = i * N + j;\n                if (j + 1 < N) {\n                    int q = p + 1;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n                if (i + 1 < N) {\n                    int q = p + N;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n            }\n        }\n    }\n\n    void compute_values() {\n        for (int i = 0; i < S; ++i) {\n            int s = 0;\n            for (int l = 0; l < M; ++l) s += X[i][l];\n            V[i] = s;\n        }\n    }\n\n    void build_pair_scores(double cSigma) {\n        for (int i = 0; i < S; ++i) {\n            PS[i][i] = (double)V[i];\n            for (int j = i + 1; j < S; ++j) {\n                long long d2 = 0;\n                for (int l = 0; l < M; ++l) {\n                    int d = X[i][l] - X[j][l];\n                    d2 += 1LL * d * d;\n                }\n                double mu = 0.5 * (V[i] + V[j]);\n                double sigma = 0.5 * sqrt((double)d2);\n                double sc = mu + cSigma * sigma;\n                PS[i][j] = PS[j][i] = sc;\n            }\n        }\n    }\n\n    double evaluate(const vector<int>& a,\n                    double wSum, double wMax,\n                    double beta1, double beta2) const {\n        double edgeSum = 0.0;\n        double edgeBest = -1e100;\n        for (const auto& e : edges) {\n            double s = PS[a[e.first]][a[e.second]];\n            edgeSum += s;\n            if (s > edgeBest) edgeBest = s;\n        }\n\n        double cov1 = 0.0, cov2 = 0.0;\n        if (beta1 > 0.0 || beta2 > 0.0) {\n            for (int l = 0; l < M; ++l) {\n                int m1 = -1, m2 = -1;\n                for (int p = 0; p < P; ++p) {\n                    int val = X[a[p]][l];\n                    if (val > m1) {\n                        m2 = m1;\n                        m1 = val;\n                    } else if (val > m2) {\n                        m2 = val;\n                    }\n                }\n                if (m2 < 0) m2 = 0;\n                cov1 += m1;\n                cov2 += m2;\n            }\n        }\n\n        return wSum * edgeSum + wMax * edgeBest + beta1 * cov1 + beta2 * cov2;\n    }\n\n    vector<int> initial_assignment() {\n        vector<int> coordMax(M, 0);\n        for (int l = 0; l < M; ++l) {\n            int mx = 0;\n            for (int i = 0; i < S; ++i) mx = max(mx, X[i][l]);\n            coordMax[l] = mx;\n        }\n\n        vector<double> base(S, 0.0);\n        for (int i = 0; i < S; ++i) {\n            int rare = 0, near = 0;\n            for (int l = 0; l < M; ++l) {\n                if (X[i][l] == coordMax[l]) rare++;\n                if (X[i][l] >= coordMax[l] - 2) near++;\n            }\n            base[i] = V[i] + 15.0 * rare + 2.5 * near;\n        }\n\n        vector<int> ordV(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<int> cand;\n        cand.reserve(S);\n        vector<char> used(S, 0);\n        auto add = [&](int id) {\n            if (!used[id]) {\n                used[id] = 1;\n                cand.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < min(S, 24); ++i) add(ordV[i]);\n\n        for (int l = 0; l < M; ++l) {\n            vector<int> ord(S);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                return V[a] > V[b];\n            });\n            for (int k = 0; k < min(S, 3); ++k) add(ord[k]);\n        }\n\n        auto cmp_base = [&](int a, int b) {\n            if (base[a] != base[b]) return base[a] > base[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        };\n\n        if ((int)cand.size() > P) {\n            sort(cand.begin(), cand.end(), cmp_base);\n            cand.resize(P);\n        }\n\n        used.assign(S, 0);\n        for (int id : cand) used[id] = 1;\n\n        vector<int> ordB(S);\n        iota(ordB.begin(), ordB.end(), 0);\n        sort(ordB.begin(), ordB.end(), cmp_base);\n        for (int id : ordB) {\n            if ((int)cand.size() >= P) break;\n            if (!used[id]) {\n                used[id] = 1;\n                cand.push_back(id);\n            }\n        }\n\n        vector<int> posOrd(P);\n        iota(posOrd.begin(), posOrd.end(), 0);\n        sort(posOrd.begin(), posOrd.end(), [&](int a, int b) {\n            int da = (int)nbr[a].size();\n            int db = (int)nbr[b].size();\n            if (da != db) return da > db;\n            return a < b;\n        });\n\n        sort(cand.begin(), cand.end(), cmp_base);\n\n        vector<int> assign(P, -1);\n        for (int k = 0; k < P; ++k) assign[posOrd[k]] = cand[k];\n        return assign;\n    }\n\n    vector<int> decide_layout(int turn) {\n        compute_values();\n\n        double progress = (T <= 1 ? 1.0 : (double)turn / (double)(T - 1));\n\n        // Tunable schedule (early: diversity, late: peak-hunting)\n        double cSigma = 0.9;\n        double wSum  = 1.0 - 0.7 * progress;\n        double wMax  = 18.0 * progress;\n        double beta1 = 10.0 * (1.0 - progress);\n        double beta2 = 4.0 * (1.0 - progress);\n\n        build_pair_scores(cSigma);\n\n        vector<int> assign = initial_assignment();\n        vector<int> seedPos(S, -1);\n        for (int p = 0; p < P; ++p) seedPos[assign[p]] = p;\n\n        auto eval_now = [&](const vector<int>& a) {\n            return evaluate(a, wSum, wMax, beta1, beta2);\n        };\n\n        double cur = eval_now(assign);\n        double best = cur;\n        vector<int> bestAssign = assign;\n\n        int ITER = 15000 + 1000 * turn;\n        double temp0 = 120.0, temp1 = 0.5;\n\n        for (int it = 0; it < ITER; ++it) {\n            int p = rng.next_int(P);\n            int s = rng.next_int(S);\n            int q = seedPos[s];\n            if (q == p) continue;\n\n            int oldP = assign[p];\n            double nxt;\n\n            if (q == -1) {\n                // replacement\n                assign[p] = s;\n                seedPos[s] = p;\n                seedPos[oldP] = -1;\n\n                nxt = eval_now(assign);\n                double delta = nxt - cur;\n                double temp = temp0 + (temp1 - temp0) * (double)it / (double)ITER;\n                bool ok = (delta >= 0.0) || (exp(delta / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestAssign = assign;\n                    }\n                } else {\n                    assign[p] = oldP;\n                    seedPos[oldP] = p;\n                    seedPos[s] = -1;\n                }\n            } else {\n                // swap\n                swap(assign[p], assign[q]); // s comes to p\n                seedPos[s] = p;\n                seedPos[oldP] = q;\n\n                nxt = eval_now(assign);\n                double delta = nxt - cur;\n                double temp = temp0 + (temp1 - temp0) * (double)it / (double)ITER;\n                bool ok = (delta >= 0.0) || (exp(delta / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestAssign = assign;\n                    }\n                } else {\n                    swap(assign[p], assign[q]);\n                    seedPos[s] = q;\n                    seedPos[oldP] = p;\n                }\n            }\n        }\n\n        assign = bestAssign;\n        fill(seedPos.begin(), seedPos.end(), -1);\n        for (int p = 0; p < P; ++p) seedPos[assign[p]] = p;\n        cur = eval_now(assign);\n\n        // One greedy polishing pass\n        vector<int> plist(P);\n        iota(plist.begin(), plist.end(), 0);\n        for (int i = P - 1; i > 0; --i) {\n            int j = rng.next_int(i + 1);\n            swap(plist[i], plist[j]);\n        }\n\n        for (int p : plist) {\n            int oldP = assign[p];\n            double localBest = cur;\n            int bestS = -1;\n            int bestQ = -2; // -1 means replacement\n\n            for (int s = 0; s < S; ++s) {\n                int q = seedPos[s];\n                if (q == p) continue;\n\n                double candScore;\n\n                if (q == -1) {\n                    assign[p] = s;\n                    seedPos[s] = p;\n                    seedPos[oldP] = -1;\n\n                    candScore = eval_now(assign);\n\n                    assign[p] = oldP;\n                    seedPos[oldP] = p;\n                    seedPos[s] = -1;\n                } else {\n                    swap(assign[p], assign[q]);\n                    seedPos[s] = p;\n                    seedPos[oldP] = q;\n\n                    candScore = eval_now(assign);\n\n                    swap(assign[p], assign[q]);\n                    seedPos[s] = q;\n                    seedPos[oldP] = p;\n                }\n\n                if (candScore > localBest + 1e-9) {\n                    localBest = candScore;\n                    bestS = s;\n                    bestQ = q;\n                }\n            }\n\n            if (bestS != -1) {\n                if (bestQ == -1) {\n                    int out = assign[p];\n                    assign[p] = bestS;\n                    seedPos[bestS] = p;\n                    seedPos[out] = -1;\n                } else {\n                    int out = assign[p];\n                    int q = bestQ;\n                    swap(assign[p], assign[q]); // bestS -> p\n                    seedPos[bestS] = p;\n                    seedPos[out] = q;\n                }\n                cur = localBest;\n            }\n        }\n\n        return assign;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> T)) return;\n        S = 2 * N * (N - 1);\n        P = N * N;\n\n        build_graph();\n        if (!read_state()) return;\n\n        for (int turn = 0; turn < T; ++turn) {\n            vector<int> assign = decide_layout(turn);\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 (!read_state()) return;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MAXC = 900;  // 30*30\n    static constexpr int MAXK = 14;   // V-1, V<=15\n\n    const int DX[4] = {0, 1, 0, -1}; // R, D, L, U in x(row),y(col)\n    const int DY[4] = {1, 0, -1, 0};\n\n    int N, M, V;\n    vector<string> S, T;\n\n    int C;      // N*N\n    int K;      // #fingertips\n    int Vp;     // #vertices = K+1\n\n    vector<int> len;      // length of each leaf edge (leaf id 0..K-1 = vertex id 1..K)\n    vector<int> curDir;   // current direction per leaf (0:R,1:D,2:L,3:U)\n    vector<char> hold;    // 0/1\n\n    vector<uint8_t> src;  // current cells with takoyaki that should be removed (s=1,t=0)\n    vector<uint8_t> dst;  // current empty target cells to fill (s=0,t=1)\n    int remSrc = 0, remDst = 0;\n\n    int curX = 0, curY = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n\n    int rotD[4][4];\n\n    vector<int> rx, ry; // rid -> x,y\n    vector<int> reach;  // ((rid*K + leaf)<<2) + dir -> cell id or -1\n\n    // stamp-based matching buffers\n    int owner[MAXC], ownerDir[MAXC], ownerStamp[MAXC];\n    int vis[MAXC];\n    int cellMark[MAXC];\n    int stampOwner = 1, stampVis = 1, stampCell = 1;\n\n    Solver() {\n        memset(ownerStamp, 0, sizeof(ownerStamp));\n        memset(vis, 0, sizeof(vis));\n        memset(cellMark, 0, sizeof(cellMark));\n    }\n\n    int heldCount() const {\n        int h = 0;\n        for (char b : hold) h += (int)b;\n        return h;\n    }\n\n    void input() {\n        cin >> N >> M >> V;\n        S.resize(N);\n        T.resize(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        C = N * N;\n        K = V - 1;\n        Vp = K + 1;\n\n        src.assign(C, 0);\n        dst.assign(C, 0);\n        remSrc = remDst = 0;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                int c = x * N + y;\n                int sv = (S[x][y] == '1');\n                int tv = (T[x][y] == '1');\n                if (sv && !tv) {\n                    src[c] = 1;\n                    remSrc++;\n                } else if (!sv && tv) {\n                    dst[c] = 1;\n                    remDst++;\n                }\n            }\n        }\n    }\n\n    void buildRot() {\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                int d = (b - a + 4) % 4;\n                rotD[a][b] = min(d, 4 - d);\n            }\n        }\n    }\n\n    void buildArm() {\n        // Keep lengths <= floor((N-1)/2) so every leaf can reach every cell\n        int maxLen = max(1, (N - 1) / 2);\n\n        len.assign(K, 1);\n        if (K <= maxLen) {\n            if (K == 1) len[0] = 1;\n            else {\n                for (int i = 0; i < K; i++) {\n                    len[i] = 1 + (long long)i * (maxLen - 1) / (K - 1);\n                }\n            }\n        } else {\n            for (int i = 0; i < maxLen; i++) len[i] = i + 1;\n            for (int i = maxLen; i < K; i++) len[i] = 1 + (i - maxLen) % maxLen;\n        }\n\n        curDir.assign(K, 0); // initially all edges point right\n        hold.assign(K, 0);\n    }\n\n    void precomputeReach() {\n        rx.resize(C);\n        ry.resize(C);\n        for (int r = 0; r < C; r++) {\n            rx[r] = r / N;\n            ry[r] = r % N;\n        }\n\n        reach.assign(C * K * 4, -1);\n        for (int rid = 0; rid < C; rid++) {\n            int x = rx[rid], y = ry[rid];\n            for (int leaf = 0; leaf < K; leaf++) {\n                int L = len[leaf];\n                int base = ((rid * K + leaf) << 2);\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + DX[d] * L;\n                    int ny = y + DY[d] * L;\n                    if (0 <= nx && nx < N && 0 <= ny && ny < N) {\n                        reach[base + d] = nx * N + ny;\n                    } else {\n                        reach[base + d] = -1;\n                    }\n                }\n            }\n        }\n    }\n\n    struct MatchRes {\n        int cnt = 0;\n        int rmax = 0;\n    };\n\n    MatchRes matchAt(\n        int rid,\n        const vector<int>& activeLeaves,\n        const vector<uint8_t>& target,\n        vector<int>* outDir = nullptr,\n        vector<int>* outCell = nullptr\n    ) {\n        MatchRes res;\n        int n = (int)activeLeaves.size();\n        if (n == 0) return res;\n\n        int deg[MAXK];\n        int eCell[MAXK][4];\n        int eDir[MAXK][4];\n        int eRot[MAXK][4];\n\n        vector<int> candCells;\n        candCells.reserve(4 * n);\n        int cstamp = ++stampCell;\n\n        for (int u = 0; u < n; u++) {\n            int leaf = activeLeaves[u];\n            deg[u] = 0;\n            int base = ((rid * K + leaf) << 2);\n\n            for (int d = 0; d < 4; d++) {\n                int c = reach[base + d];\n                if (c >= 0 && target[c]) {\n                    int k = deg[u]++;\n                    eCell[u][k] = c;\n                    eDir[u][k] = d;\n                    eRot[u][k] = rotD[curDir[leaf]][d];\n\n                    if (cellMark[c] != cstamp) {\n                        cellMark[c] = cstamp;\n                        candCells.push_back(c);\n                    }\n                }\n            }\n\n            // sort by smaller rotation need\n            for (int a = 0; a < deg[u]; a++) {\n                for (int b = a + 1; b < deg[u]; b++) {\n                    if (eRot[u][a] > eRot[u][b]) {\n                        swap(eRot[u][a], eRot[u][b]);\n                        swap(eCell[u][a], eCell[u][b]);\n                        swap(eDir[u][a], eDir[u][b]);\n                    }\n                }\n            }\n        }\n\n        int ord[MAXK];\n        for (int i = 0; i < n; i++) ord[i] = i;\n        sort(ord, ord + n, [&](int a, int b) {\n            if (deg[a] != deg[b]) return deg[a] < deg[b];\n            return activeLeaves[a] < activeLeaves[b];\n        });\n\n        int mid = ++stampOwner;\n\n        auto dfs = [&](auto&& self, int u, int tag) -> bool {\n            for (int ei = 0; ei < deg[u]; ei++) {\n                int c = eCell[u][ei];\n                if (vis[c] == tag) continue;\n                vis[c] = tag;\n\n                int ow = (ownerStamp[c] == mid ? owner[c] : -1);\n                if (ow == -1 || self(self, ow, tag)) {\n                    ownerStamp[c] = mid;\n                    owner[c] = u;\n                    ownerDir[c] = eDir[u][ei];\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        int cnt = 0;\n        for (int i = 0; i < n; i++) {\n            int tag = ++stampVis;\n            if (dfs(dfs, ord[i], tag)) cnt++;\n        }\n        res.cnt = cnt;\n        if (cnt == 0) return res;\n\n        int rmax = 0;\n        for (int c : candCells) {\n            if (ownerStamp[c] != mid) continue;\n            int u = owner[c];\n            int leaf = activeLeaves[u];\n            int d = ownerDir[c];\n            rmax = max(rmax, rotD[curDir[leaf]][d]);\n            if (outDir) {\n                (*outDir)[leaf] = d;\n                (*outCell)[leaf] = c;\n            }\n        }\n        res.rmax = rmax;\n        return res;\n    }\n\n    bool betterByRatio(int cnt, int turns, int dist, int bestCnt, int bestTurns, int bestDist) {\n        if (bestCnt < 0) return true;\n        long long lhs = 1LL * cnt * bestTurns;\n        long long rhs = 1LL * bestCnt * turns;\n        if (lhs != rhs) return lhs > rhs;\n        if (cnt != bestCnt) return cnt > bestCnt;\n        if (turns != bestTurns) return turns < bestTurns;\n        return dist < bestDist;\n    }\n\n    bool findBestRoot(\n        const vector<int>& activeLeaves,\n        const vector<uint8_t>& target,\n        int& bestRid, int& bestCnt, int& bestTurns, int& bestDist\n    ) {\n        bestRid = -1;\n        bestCnt = -1;\n        bestTurns = (int)1e9;\n        bestDist = (int)1e9;\n\n        for (int rid = 0; rid < C; rid++) {\n            MatchRes mr = matchAt(rid, activeLeaves, target);\n            if (mr.cnt == 0) continue;\n\n            int d = abs(rx[rid] - curX) + abs(ry[rid] - curY);\n            int turns = max(d, mr.rmax);\n            if (turns == 0) turns = 1;\n\n            if (betterByRatio(mr.cnt, turns, d, bestCnt, bestTurns, bestDist)) {\n                bestRid = rid;\n                bestCnt = mr.cnt;\n                bestTurns = turns;\n                bestDist = d;\n            }\n        }\n        return bestRid != -1;\n    }\n\n    void chooseInitialRoot() {\n        if (remSrc == 0) {\n            initX = N / 2;\n            initY = N / 2;\n            curX = initX;\n            curY = initY;\n            return;\n        }\n\n        vector<int> allLeaves(K);\n        iota(allLeaves.begin(), allLeaves.end(), 0);\n\n        int bestRid = -1, bestCnt = -1, bestTurns = (int)1e9, bestCenter = (int)1e9;\n        int cx = N / 2, cy = N / 2;\n\n        for (int rid = 0; rid < C; rid++) {\n            MatchRes mr = matchAt(rid, allLeaves, src);\n            if (mr.cnt == 0) continue;\n\n            int turns = max(1, mr.rmax);\n            int centerDist = abs(rx[rid] - cx) + abs(ry[rid] - cy);\n\n            bool better = false;\n            if (bestRid == -1) better = true;\n            else {\n                long long lhs = 1LL * mr.cnt * bestTurns;\n                long long rhs = 1LL * bestCnt * turns;\n                if (lhs != rhs) better = lhs > rhs;\n                else if (mr.cnt != bestCnt) better = mr.cnt > bestCnt;\n                else if (turns != bestTurns) better = turns < bestTurns;\n                else if (centerDist < bestCenter) better = true;\n            }\n\n            if (better) {\n                bestRid = rid;\n                bestCnt = mr.cnt;\n                bestTurns = turns;\n                bestCenter = centerDist;\n            }\n        }\n\n        if (bestRid == -1) bestRid = (N / 2) * N + (N / 2);\n        initX = rx[bestRid];\n        initY = ry[bestRid];\n        curX = initX;\n        curY = initY;\n    }\n\n    void executeMove(int rid, const vector<int>& assignDir, const vector<int>& assignCell) {\n        int bx = rx[rid], by = ry[rid];\n\n        int acted = 0;\n        for (int i = 0; i < K; i++) if (assignDir[i] >= 0) acted++;\n        if (acted == 0) return;\n\n        int rotRem[MAXK] = {};\n        int rotSign[MAXK] = {}; // +1 => R, -1 => L\n        int R = 0;\n\n        for (int i = 0; i < K; i++) {\n            if (assignDir[i] < 0) continue;\n            int diff = (assignDir[i] - curDir[i] + 4) % 4;\n            if (diff == 0) {\n                rotRem[i] = 0;\n            } else if (diff == 1) {\n                rotRem[i] = 1;\n                rotSign[i] = +1;\n            } else if (diff == 3) {\n                rotRem[i] = 1;\n                rotSign[i] = -1;\n            } else { // diff==2\n                rotRem[i] = 2;\n                rotSign[i] = +1;\n            }\n            R = max(R, rotRem[i]);\n        }\n\n        int D = abs(bx - curX) + abs(by - curY);\n        int turns = max(D, R);\n        if (turns == 0) turns = 1;\n\n        int vx = bx - curX;\n        int vy = by - curY;\n\n        for (int t = 0; t < turns; t++) {\n            string line(2 * Vp, '.');\n\n            // move root\n            char mv = '.';\n            if (vx < 0) {\n                mv = 'U';\n                vx++;\n                curX--;\n            } else if (vx > 0) {\n                mv = 'D';\n                vx--;\n                curX++;\n            } else if (vy < 0) {\n                mv = 'L';\n                vy++;\n                curY--;\n            } else if (vy > 0) {\n                mv = 'R';\n                vy--;\n                curY++;\n            }\n            line[0] = mv;\n\n            // rotate leaves\n            for (int i = 0; i < K; i++) {\n                if (rotRem[i] > 0) {\n                    if (rotSign[i] == +1) {\n                        line[1 + i] = 'R';\n                        curDir[i] = (curDir[i] + 1) & 3;\n                    } else {\n                        line[1 + i] = 'L';\n                        curDir[i] = (curDir[i] + 3) & 3;\n                    }\n                    rotRem[i]--;\n                }\n            }\n\n            // actions\n            if (t == turns - 1) {\n                for (int i = 0; i < K; i++) {\n                    if (assignDir[i] >= 0) line[Vp + (i + 1)] = 'P';\n                }\n            }\n\n            ops.push_back(line);\n        }\n\n        // apply pickups / drops\n        for (int i = 0; i < K; i++) {\n            if (assignDir[i] < 0) continue;\n            int c = assignCell[i];\n            if (hold[i]) {\n                // drop\n                if (dst[c]) {\n                    dst[c] = 0;\n                    remDst--;\n                    hold[i] = 0;\n                }\n            } else {\n                // pick\n                if (src[c]) {\n                    src[c] = 0;\n                    remSrc--;\n                    hold[i] = 1;\n                }\n            }\n        }\n    }\n\n    bool emergencySingleAction() {\n        int held = heldCount();\n\n        // Try one drop first\n        if (held > 0 && remDst > 0) {\n            int bestTurns = (int)1e9, bestDist = (int)1e9;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf = 0; leaf < K; leaf++) if (hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (dst[c]) {\n                    int tx = rx[c], ty = ry[c];\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int D = abs(rr - curX) + abs(cc - curY);\n                        int R = rotD[curDir[leaf]][d];\n                        int turns = max(D, R);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && D < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = D;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf != -1) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        // Try one pick\n        if (remSrc > 0) {\n            int bestTurns = (int)1e9, bestDist = (int)1e9;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf = 0; leaf < K; leaf++) if (!hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (src[c]) {\n                    int tx = rx[c], ty = ry[c];\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int D = abs(rr - curX) + abs(cc - curY);\n                        int R = rotD[curDir[leaf]][d];\n                        int turns = max(D, R);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && D < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = D;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf != -1) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void plan() {\n        chooseInitialRoot();\n\n        int mode = 0; // 0=LOAD, 1=UNLOAD\n        int safety = 0;\n\n        while ((remDst > 0 || heldCount() > 0) && (int)ops.size() < 100000 && safety < 200000) {\n            safety++;\n            int held = heldCount();\n\n            // hysteresis\n            if (remSrc == 0) mode = 1;\n            else if (held == 0) mode = 0;\n            else if (held == K) mode = 1;\n            else {\n                if (mode == 0 && held * 3 >= 2 * K) mode = 1;\n                else if (mode == 1 && held * 3 <= K) mode = 0;\n            }\n\n            bool progressed = false;\n\n            for (int trial = 0; trial < 2 && !progressed; trial++) {\n                int useMode = (trial == 0 ? mode : 1 - mode);\n\n                vector<int> active;\n                const vector<uint8_t>* target = nullptr;\n\n                if (useMode == 0) {\n                    if (remSrc == 0) continue;\n                    for (int i = 0; i < K; i++) if (!hold[i]) active.push_back(i);\n                    if (active.empty()) continue;\n                    target = &src;\n                } else {\n                    if (heldCount() == 0) continue;\n                    for (int i = 0; i < K; i++) if (hold[i]) active.push_back(i);\n                    if (active.empty()) continue;\n                    target = &dst;\n                }\n\n                int bestRid, bestCnt, bestTurns, bestDist;\n                if (!findBestRoot(active, *target, bestRid, bestCnt, bestTurns, bestDist)) continue;\n\n                vector<int> ad(K, -1), ac(K, -1);\n                MatchRes mr = matchAt(bestRid, active, *target, &ad, &ac);\n                if (mr.cnt == 0) continue;\n\n                executeMove(bestRid, ad, ac);\n                mode = useMode;\n                progressed = true;\n            }\n\n            if (!progressed) {\n                if (!emergencySingleAction()) break;\n            }\n        }\n\n        // finishing guard\n        while ((remDst > 0 || heldCount() > 0) && (int)ops.size() < 100000) {\n            if (!emergencySingleAction()) break;\n        }\n    }\n\n    void output() {\n        cout << Vp << '\\n';\n        for (int i = 0; i < K; i++) {\n            cout << 0 << ' ' << len[i] << '\\n';\n        }\n        cout << initX << ' ' << initY << '\\n';\n        for (const auto& s : ops) cout << s << '\\n';\n    }\n\n    void run() {\n        input();\n        buildRot();\n        buildArm();\n        precomputeReach();\n        plan();\n        output();\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}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstruct Point {\n    int x, y;\n};\n\nstruct RectCand {\n    int val;\n    int x1, x2, y1, y2;\n};\n\nstruct Component {\n    vector<int> cells;\n    int score = 0;\n    int perim = 0;\n    int minx = INT_MAX, maxx = -1;\n    int miny = INT_MAX, maxy = -1;\n};\n\nstruct Solver {\n    static constexpr int COORD_MAX = 100000;\n    static constexpr int PERIM_LIMIT = 400000;\n    static constexpr double SOFT_LIMIT = 1.90;\n\n    int N;\n    vector<Point> pts;\n    vector<int> wt; // +1 mackerel, -1 sardine\n\n    // Grid\n    int STEP = 500;\n    int W, H, C, PmaxUnits;\n    vector<int> raw; // cell score\n    vector<int> outsideSides;\n    vector<pair<int, int>> adjPairs;\n    vector<int> prefix; // 2D prefix of raw\n    vector<vector<int>> pointCandCells; // for exact inclusion on cell-union boundary\n\n    // Best answer\n    int bestDiff = -1e9;\n    vector<Point> bestPoly;\n\n    chrono::steady_clock::time_point st;\n\n    inline int id(int x, int y) const { return y * W + x; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void read_input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        pts.resize(2 * N);\n        wt.resize(2 * N);\n        for (int i = 0; i < 2 * N; i++) {\n            cin >> pts[i].x >> pts[i].y;\n            wt[i] = (i < N ? +1 : -1);\n        }\n    }\n\n    void build_grid() {\n        W = COORD_MAX / STEP;\n        H = COORD_MAX / STEP;\n        C = W * H;\n        PmaxUnits = PERIM_LIMIT / STEP;\n\n        raw.assign(C, 0);\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x / STEP;\n            int y = pts[i].y / STEP;\n            if (x >= W) x = W - 1; // handle x=100000\n            if (y >= H) y = H - 1; // handle y=100000\n            raw[id(x, y)] += wt[i];\n        }\n\n        outsideSides.assign(C, 0);\n        adjPairs.clear();\n        adjPairs.reserve(C * 2);\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 out = 0;\n                if (x == 0) out++;\n                if (x == W - 1) out++;\n                if (y == 0) out++;\n                if (y == H - 1) out++;\n                outsideSides[v] = out;\n\n                if (x + 1 < W) adjPairs.push_back({v, id(x + 1, y)});\n                if (y + 1 < H) adjPairs.push_back({v, id(x, y + 1)});\n            }\n        }\n\n        // Prefix sum\n        prefix.assign((W + 1) * (H + 1), 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int cur = raw[id(x, y)];\n                int A = prefix[y * (W + 1) + (x + 1)];\n                int B = prefix[(y + 1) * (W + 1) + x];\n                int D = prefix[y * (W + 1) + x];\n                prefix[(y + 1) * (W + 1) + (x + 1)] = cur + A + B - D;\n            }\n        }\n\n        // Exact inclusion candidates for each point (boundary-inclusive)\n        pointCandCells.assign(2 * N, {});\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x;\n            int y = pts[i].y;\n\n            int qx = x / STEP;\n            int qy = y / STEP;\n\n            vector<int> xs, ys;\n            if (qx == W) xs = {W - 1};\n            else if (x % STEP == 0 && qx > 0) xs = {qx - 1, qx};\n            else xs = {qx};\n\n            if (qy == H) ys = {H - 1};\n            else if (y % STEP == 0 && qy > 0) ys = {qy - 1, qy};\n            else ys = {qy};\n\n            vector<int> cand;\n            cand.reserve(4);\n            for (int xx : xs) for (int yy : ys) {\n                int v = id(xx, yy);\n                bool dup = false;\n                for (int z : cand) if (z == v) { dup = true; break; }\n                if (!dup) cand.push_back(v);\n            }\n            pointCandCells[i] = move(cand);\n        }\n    }\n\n    int rect_sum(int x1, int y1, int x2, int y2) const {\n        if (x1 > x2 || y1 > y2) return 0;\n        x1 = max(x1, 0);\n        y1 = max(y1, 0);\n        x2 = min(x2, W - 1);\n        y2 = min(y2, H - 1);\n        if (x1 > x2 || y1 > y2) return 0;\n\n        int A = prefix[(y2 + 1) * (W + 1) + (x2 + 1)];\n        int B = prefix[y1 * (W + 1) + (x2 + 1)];\n        int Cc = prefix[(y2 + 1) * (W + 1) + x1];\n        int D = prefix[y1 * (W + 1) + x1];\n        return A - B - Cc + D;\n    }\n\n    vector<int> build_profit(int r) const {\n        vector<int> p(C, 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int v = id(x, y);\n                int s = rect_sum(x - r, y - r, x + r, y + r);\n                if (r == 0) p[v] = raw[v] * 20;\n                else p[v] = s * 8 + raw[v] * 4;\n            }\n        }\n        return p;\n    }\n\n    vector<char> segment_cut(const vector<int>& profit, int lambda) const {\n        vector<char> sel(C, 0);\n\n        if (lambda == 0) {\n            for (int i = 0; i < C; i++) sel[i] = (profit[i] > 0);\n            return sel;\n        }\n\n        int S = C, T = C + 1;\n        mf_graph<ll> g(C + 2);\n\n        for (int v = 0; v < C; v++) {\n            ll c1 = -(ll)profit[v] + (ll)lambda * outsideSides[v];\n            if (c1 >= 0) g.add_edge(v, T, c1);\n            else g.add_edge(S, v, -c1);\n        }\n\n        for (auto [u, v] : adjPairs) {\n            g.add_edge(u, v, lambda);\n            g.add_edge(v, u, lambda);\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n        for (int i = 0; i < C; i++) sel[i] = cut[i] ? 1 : 0;\n        return sel;\n    }\n\n    vector<Component> top_components(const vector<char>& sel, int K) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n        vector<Component> comps;\n        comps.reserve(64);\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n\n            Component cp;\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cp.cells.push_back(v);\n                cp.score += raw[v];\n\n                int x = v % W, y = v / W;\n                cp.minx = min(cp.minx, x);\n                cp.maxx = max(cp.maxx, x);\n                cp.miny = min(cp.miny, y);\n                cp.maxy = max(cp.maxy, y);\n\n                if (x == 0 || !sel[v - 1]) cp.perim++;\n                else if (!vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n\n                if (x == W - 1 || !sel[v + 1]) cp.perim++;\n                else if (!vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n\n                if (y == 0 || !sel[v - W]) cp.perim++;\n                else if (!vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n\n                if (y == H - 1 || !sel[v + W]) cp.perim++;\n                else if (!vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (cp.score > 0) comps.push_back(move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [&](const Component& a, const Component& b) {\n            if (a.score != b.score) return a.score > b.score;\n            if (a.perim != b.perim) return a.perim < b.perim;\n            return a.cells.size() > b.cells.size();\n        });\n\n        if ((int)comps.size() > K) comps.resize(K);\n        return comps;\n    }\n\n    int bbox_dist(const Component& a, const Component& b) const {\n        int dx = 0, dy = 0;\n        if (a.maxx < b.minx) dx = b.minx - a.maxx - 1;\n        else if (b.maxx < a.minx) dx = a.minx - b.maxx - 1;\n\n        if (a.maxy < b.miny) dy = b.miny - a.maxy - 1;\n        else if (b.maxy < a.miny) dy = a.miny - b.maxy - 1;\n\n        return dx + dy;\n    }\n\n    bool connect_components(const Component& A, const Component& B, vector<char>& outSel, int& pathLen) const {\n        outSel.assign(C, 0);\n        vector<char> inB(C, 0);\n        vector<int> parent(C, -1);\n        queue<int> q;\n\n        for (int v : A.cells) {\n            outSel[v] = 1;\n            parent[v] = -2;\n            q.push(v);\n        }\n        for (int v : B.cells) {\n            outSel[v] = 1;\n            inB[v] = 1;\n        }\n\n        int target = -1;\n\n        while (!q.empty() && target == -1) {\n            int v = q.front(); q.pop();\n            if (inB[v]) {\n                target = v;\n                break;\n            }\n\n            int x = v % W, y = v / W;\n            auto relax = [&](int to) {\n                if (parent[to] == -1) {\n                    parent[to] = v;\n                    q.push(to);\n                    if (inB[to]) target = to;\n                }\n            };\n\n            if (x > 0 && target == -1) relax(v - 1);\n            if (x + 1 < W && target == -1) relax(v + 1);\n            if (y > 0 && target == -1) relax(v - W);\n            if (y + 1 < H && target == -1) relax(v + W);\n        }\n\n        if (target == -1) return false;\n\n        pathLen = 0;\n        int cur = target;\n        while (parent[cur] != -2) {\n            outSel[cur] = 1;\n            cur = parent[cur];\n            if (cur < 0) return false;\n            pathLen++;\n        }\n        outSel[cur] = 1;\n        return true;\n    }\n\n    vector<RectCand> best_rectangles(int K) const {\n        struct CmpMin {\n            bool operator()(const RectCand& a, const RectCand& b) const { return a.val > b.val; }\n        };\n        priority_queue<RectCand, vector<RectCand>, CmpMin> pq;\n\n        vector<int> acc(H, 0), ps(H + 1, 0);\n\n        for (int x1 = 0; x1 < W; x1++) {\n            fill(acc.begin(), acc.end(), 0);\n\n            for (int x2 = x1; x2 < W; x2++) {\n                for (int y = 0; y < H; y++) acc[y] += raw[id(x2, y)];\n\n                int wcell = x2 - x1 + 1;\n                int L = PmaxUnits / 2 - wcell;\n                if (L < 1) break;\n\n                ps[0] = 0;\n                for (int y = 0; y < H; y++) ps[y + 1] = ps[y] + acc[y];\n\n                deque<int> dq;\n                int best = INT_MIN;\n                int bl = 0, br = 0; // [bl, br)\n\n                for (int j = 1; j <= H; j++) {\n                    int add = j - 1;\n                    while (!dq.empty() && ps[dq.back()] >= ps[add]) dq.pop_back();\n                    dq.push_back(add);\n\n                    int lim = j - L;\n                    while (!dq.empty() && dq.front() < lim) dq.pop_front();\n\n                    if (!dq.empty()) {\n                        int val = ps[j] - ps[dq.front()];\n                        if (val > best) {\n                            best = val;\n                            bl = dq.front();\n                            br = j;\n                        }\n                    }\n                }\n\n                if (best <= 0 || br <= bl) continue;\n                RectCand rc{best, x1, x2, bl, br - 1};\n\n                if ((int)pq.size() < K) pq.push(rc);\n                else if (rc.val > pq.top().val) {\n                    pq.pop();\n                    pq.push(rc);\n                }\n            }\n        }\n\n        vector<RectCand> out;\n        while (!pq.empty()) {\n            out.push_back(pq.top());\n            pq.pop();\n        }\n        sort(out.begin(), out.end(), [](const RectCand& a, const RectCand& b) {\n            return a.val > b.val;\n        });\n        return out;\n    }\n\n    int count_nb(const vector<char>& sel, int v) const {\n        int x = v % W, y = v / W;\n        int c = 0;\n        if (x > 0 && sel[v - 1]) c++;\n        if (x + 1 < W && sel[v + 1]) c++;\n        if (y > 0 && sel[v - W]) c++;\n        if (y + 1 < H && sel[v + W]) c++;\n        return c;\n    }\n\n    pair<int, int> score_perim(const vector<char>& sel) const {\n        int sc = 0, per = 0;\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            sc += raw[v];\n            int x = v % W, y = v / W;\n            if (x == 0 || !sel[v - 1]) per++;\n            if (x == W - 1 || !sel[v + 1]) per++;\n            if (y == 0 || !sel[v - W]) per++;\n            if (y == H - 1 || !sel[v + W]) per++;\n        }\n        return {sc, per};\n    }\n\n    void enforce_single_component(vector<char>& sel) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n\n        int compCnt = 0;\n        int bestSc = INT_MIN;\n        vector<int> bestCells;\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n            compCnt++;\n\n            vector<int> cells;\n            int sc = 0;\n\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cells.push_back(v);\n                sc += raw[v];\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && !vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n                if (x + 1 < W && sel[v + 1] && !vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n                if (y > 0 && sel[v - W] && !vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n                if (y + 1 < H && sel[v + W] && !vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (sc > bestSc) {\n                bestSc = sc;\n                bestCells = move(cells);\n            }\n        }\n\n        if (compCnt <= 1) return;\n        fill(sel.begin(), sel.end(), 0);\n        for (int v : bestCells) sel[v] = 1;\n    }\n\n    void fill_holes(vector<char>& sel) const {\n        int minx = W, miny = H, maxx = -1, maxy = -1;\n        for (int v = 0; v < C; v++) if (sel[v]) {\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        if (maxx < minx) return;\n\n        int bw = maxx - minx + 1;\n        int bh = maxy - miny + 1;\n        int LW = bw + 2;\n        int LH = bh + 2;\n\n        vector<char> blocked(LW * LH, 0), vis(LW * LH, 0);\n\n        for (int y = miny; y <= maxy; y++) {\n            for (int x = minx; x <= maxx; x++) {\n                int gv = id(x, y);\n                if (sel[gv]) {\n                    int lx = (x - minx) + 1;\n                    int ly = (y - miny) + 1;\n                    blocked[ly * LW + lx] = 1;\n                }\n            }\n        }\n\n        queue<int> q;\n        auto push_if = [&](int lx, int ly) {\n            int t = ly * LW + lx;\n            if (!blocked[t] && !vis[t]) {\n                vis[t] = 1;\n                q.push(t);\n            }\n        };\n\n        for (int x = 0; x < LW; x++) {\n            push_if(x, 0);\n            push_if(x, LH - 1);\n        }\n        for (int y = 0; y < LH; y++) {\n            push_if(0, y);\n            push_if(LW - 1, y);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int x = v % LW, y = v / LW;\n            if (x > 0) push_if(x - 1, y);\n            if (x + 1 < LW) push_if(x + 1, y);\n            if (y > 0) push_if(x, y - 1);\n            if (y + 1 < LH) push_if(x, y + 1);\n        }\n\n        for (int ly = 1; ly <= bh; ly++) {\n            for (int lx = 1; lx <= bw; lx++) {\n                int t = ly * LW + lx;\n                if (!blocked[t] && !vis[t]) {\n                    int gx = minx + (lx - 1);\n                    int gy = miny + (ly - 1);\n                    sel[id(gx, gy)] = 1;\n                }\n            }\n        }\n    }\n\n    void refine(vector<char>& sel) const {\n        auto sp = score_perim(sel);\n        int perim = sp.second;\n\n        // 1) remove non-positive leaves\n        queue<int> q;\n        for (int v = 0; v < C; v++) {\n            if (sel[v] && raw[v] <= 0 && count_nb(sel, v) <= 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (!sel[v]) continue;\n            int nb = count_nb(sel, v);\n            if (raw[v] <= 0 && nb <= 1) {\n                sel[v] = 0;\n                perim += (-4 + 2 * nb);\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && raw[v - 1] <= 0 && count_nb(sel, v - 1) <= 1) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1] && raw[v + 1] <= 0 && count_nb(sel, v + 1) <= 1) q.push(v + 1);\n                if (y > 0 && sel[v - W] && raw[v - W] <= 0 && count_nb(sel, v - W) <= 1) q.push(v - W);\n                if (y + 1 < H && sel[v + W] && raw[v + W] <= 0 && count_nb(sel, v + W) <= 1) q.push(v + W);\n            }\n        }\n\n        // 2) if perimeter too large, remove leaves with smallest raw loss\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> leafPQ;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) leafPQ.push({raw[v], v});\n\n        while (perim > PmaxUnits && !leafPQ.empty()) {\n            auto [rw, v] = leafPQ.top(); leafPQ.pop();\n            (void)rw;\n            if (!sel[v]) continue;\n            int nb = count_nb(sel, v);\n            if (nb > 1) continue;\n\n            sel[v] = 0;\n            perim += (-4 + 2 * nb);\n\n            int x = v % W, y = v / W;\n            if (x > 0 && sel[v - 1] && count_nb(sel, v - 1) <= 1) leafPQ.push({raw[v - 1], v - 1});\n            if (x + 1 < W && sel[v + 1] && count_nb(sel, v + 1) <= 1) leafPQ.push({raw[v + 1], v + 1});\n            if (y > 0 && sel[v - W] && count_nb(sel, v - W) <= 1) leafPQ.push({raw[v - W], v - W});\n            if (y + 1 < H && sel[v + W] && count_nb(sel, v + W) <= 1) leafPQ.push({raw[v + W], v + W});\n        }\n\n        // 3) greedily grow frontier positives\n        priority_queue<pair<int, int>> pq; // (raw, idx)\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty()) {\n            auto [rw, v] = pq.top(); pq.pop();\n            (void)rw;\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            bool take = false;\n            if (raw[v] > 0) take = true;\n            else if (raw[v] == 0 && dP < 0) take = true;\n\n            if (take) {\n                sel[v] = 1;\n                perim += dP;\n\n                int x = v % W, y = v / W;\n                if (x > 0) push_frontier(v - 1);\n                if (x + 1 < W) push_frontier(v + 1);\n                if (y > 0) push_frontier(v - W);\n                if (y + 1 < H) push_frontier(v + W);\n            }\n        }\n    }\n\n    void resolve_diagonal_crosses(vector<char>& sel) const {\n        for (int it = 0; it < 2; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < H; y++) {\n                for (int x = 0; x + 1 < W; x++) {\n                    int a = id(x, y);\n                    int b = id(x + 1, y);\n                    int c = id(x, y + 1);\n                    int d = id(x + 1, y + 1);\n\n                    if (sel[a] && sel[d] && !sel[b] && !sel[c]) {\n                        sel[(raw[b] >= raw[c]) ? b : c] = 1;\n                        changed = true;\n                    } else if (!sel[a] && !sel[d] && sel[b] && sel[c]) {\n                        sel[(raw[a] >= raw[d]) ? a : d] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    int exact_diff(const vector<char>& sel) const {\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            bool inside = false;\n            for (int c : pointCandCells[i]) {\n                if (sel[c]) { inside = true; break; }\n            }\n            if (inside) diff += wt[i];\n        }\n        return diff;\n    }\n\n    static ll area2(const vector<Point>& poly) {\n        ll s = 0;\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            s += 1LL * poly[i].x * poly[j].y - 1LL * poly[i].y * poly[j].x;\n        }\n        return s;\n    }\n\n    vector<Point> cells_to_polygon(const vector<char>& sel) const {\n        const int SHIFT = 20;\n        auto key = [&](int x, int y) -> ll { return (ll(x) << SHIFT) | ll(y); };\n        auto decode = [&](ll k) -> Point { return Point{int(k >> SHIFT), int(k & ((1LL << SHIFT) - 1))}; };\n\n        unordered_map<ll, ll> nxt;\n        nxt.reserve(8192);\n\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            int cx = v % W, cy = v / W;\n            int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n            int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n\n            // CCW around cell\n            if (cy == 0 || !sel[v - W]) nxt[key(x0, y0)] = key(x1, y0);\n            if (cx == W - 1 || !sel[v + 1]) nxt[key(x1, y0)] = key(x1, y1);\n            if (cy == H - 1 || !sel[v + W]) nxt[key(x1, y1)] = key(x0, y1);\n            if (cx == 0 || !sel[v - 1]) nxt[key(x0, y1)] = key(x0, y0);\n        }\n\n        if (nxt.empty()) return {};\n\n        unordered_set<ll> used;\n        used.reserve(nxt.size() * 2 + 1);\n\n        vector<Point> best;\n        ll bestA = -1;\n\n        for (auto &kv : nxt) {\n            ll start = kv.first;\n            if (used.count(start)) continue;\n\n            unordered_set<ll> local;\n            local.reserve(nxt.size() * 2 + 1);\n\n            vector<Point> cyc;\n            ll cur = start;\n            bool ok = true;\n\n            while (true) {\n                if (local.count(cur)) {\n                    if (cur == start) break;\n                    ok = false;\n                    break;\n                }\n                local.insert(cur);\n                used.insert(cur);\n\n                auto it = nxt.find(cur);\n                if (it == nxt.end()) { ok = false; break; }\n\n                cyc.push_back(decode(cur));\n                cur = it->second;\n\n                if ((int)cyc.size() > (int)nxt.size() + 5) {\n                    ok = false;\n                    break;\n                }\n            }\n\n            if (!ok || (int)cyc.size() < 4) continue;\n            ll a = llabs(area2(cyc));\n            if (a > bestA) {\n                bestA = a;\n                best = move(cyc);\n            }\n        }\n\n        if (best.empty()) return {};\n\n        // Remove collinear points\n        bool changed = true;\n        while (changed && best.size() > 4) {\n            changed = false;\n            int m = (int)best.size();\n            vector<Point> np;\n            np.reserve(m);\n\n            for (int i = 0; i < m; i++) {\n                Point a = best[(i - 1 + m) % m];\n                Point b = best[i];\n                Point c = best[(i + 1) % m];\n\n                if ((a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y)) {\n                    changed = true;\n                    continue;\n                }\n                np.push_back(b);\n            }\n            if (np.size() < 4) break;\n            best.swap(np);\n        }\n\n        return best;\n    }\n\n    bool basic_valid(const vector<Point>& poly) const {\n        int m = (int)poly.size();\n        if (m < 4 || m > 1000) return false;\n\n        const int SHIFT = 20;\n        unordered_set<ll> s;\n        s.reserve(m * 2);\n\n        ll per = 0;\n        for (int i = 0; i < m; i++) {\n            int x = poly[i].x, y = poly[i].y;\n            if (x < 0 || x > COORD_MAX || y < 0 || y > COORD_MAX) return false;\n\n            ll k = (ll(x) << SHIFT) | ll(y);\n            if (s.count(k)) return false;\n            s.insert(k);\n\n            int j = (i + 1) % m;\n            int x2 = poly[j].x, y2 = poly[j].y;\n            if (x != x2 && y != y2) return false;\n            ll len = llabs((ll)x - x2) + llabs((ll)y - y2);\n            if (len <= 0) return false;\n            per += len;\n        }\n\n        if (per > PERIM_LIMIT) return false;\n        if (area2(poly) == 0) return false;\n        return true;\n    }\n\n    struct Seg {\n        int x1, y1, x2, y2;\n        bool vert;\n    };\n\n    static bool overlap1d(int a, int b, int c, int d) {\n        if (a > b) swap(a, b);\n        if (c > d) swap(c, d);\n        return max(a, c) <= min(b, d);\n    }\n\n    static bool seg_intersect(const Seg& A, const Seg& B) {\n        if (A.vert && B.vert) {\n            if (A.x1 != B.x1) return false;\n            return overlap1d(A.y1, A.y2, B.y1, B.y2);\n        }\n        if (!A.vert && !B.vert) {\n            if (A.y1 != B.y1) return false;\n            return overlap1d(A.x1, A.x2, B.x1, B.x2);\n        }\n\n        const Seg& V = A.vert ? A : B;\n        const Seg& Hs = A.vert ? B : A;\n\n        int vx = V.x1;\n        int hy = Hs.y1;\n        int hxL = min(Hs.x1, Hs.x2), hxR = max(Hs.x1, Hs.x2);\n        int vyL = min(V.y1, V.y2), vyR = max(V.y1, V.y2);\n\n        return (hxL <= vx && vx <= hxR && vyL <= hy && hy <= vyR);\n    }\n\n    bool final_valid(const vector<Point>& poly) const {\n        if (!basic_valid(poly)) return false;\n        int m = (int)poly.size();\n\n        vector<Seg> edges(m);\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            edges[i] = Seg{poly[i].x, poly[i].y, poly[j].x, poly[j].y, (poly[i].x == poly[j].x)};\n        }\n\n        for (int i = 0; i < m; i++) {\n            for (int j = i + 1; j < m; j++) {\n                if ((i + 1) % m == j) continue;      // adjacent\n                if ((j + 1) % m == i) continue;      // adjacent\n                if (seg_intersect(edges[i], edges[j])) return false;\n            }\n        }\n        return true;\n    }\n\n    void consider_candidate(vector<char> sel) {\n        if (elapsed() > SOFT_LIMIT) return;\n\n        bool any = false;\n        for (char b : sel) if (b) { any = true; break; }\n        if (!any) return;\n\n        enforce_single_component(sel);\n        fill_holes(sel);\n        refine(sel);\n        resolve_diagonal_crosses(sel);\n        fill_holes(sel);\n        enforce_single_component(sel);\n\n        auto [sc, per] = score_perim(sel);\n        (void)sc;\n        if (per <= 0 || per > PmaxUnits) return;\n\n        int diff = exact_diff(sel);\n        if (diff <= bestDiff) return;\n\n        auto poly = cells_to_polygon(sel);\n        if (!final_valid(poly)) return;\n\n        bestDiff = diff;\n        bestPoly = move(poly);\n    }\n\n    int rect_diff(int x0, int x1, int y0, int y1) const {\n        int d = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x0 <= x && x <= x1 && y0 <= y && y <= y1) d += wt[i];\n        }\n        return d;\n    }\n\n    vector<Point> tiny_square_around_first_mackerel() const {\n        int x = pts[0].x, y = pts[0].y;\n        int x0, x1, y0, y1;\n        if (x < COORD_MAX) { x0 = x; x1 = x + 1; }\n        else { x0 = x - 1; x1 = x; }\n\n        if (y < COORD_MAX) { y0 = y; y1 = y + 1; }\n        else { y0 = y - 1; y1 = y; }\n\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    vector<Point> cell_rect_poly(int v) const {\n        int cx = v % W, cy = v / W;\n        int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n        int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n        build_grid();\n\n        // Candidate 0: best single positive cell\n        int bestCell = 0;\n        for (int i = 1; i < C; i++) if (raw[i] > raw[bestCell]) bestCell = i;\n        if (raw[bestCell] > 0) {\n            vector<char> sel(C, 0);\n            sel[bestCell] = 1;\n            consider_candidate(move(sel));\n        }\n\n        // Candidate family: best rectangles under perimeter limit\n        auto rects = best_rectangles(10);\n        for (auto &rc : rects) {\n            if (elapsed() > SOFT_LIMIT * 0.55) break;\n            vector<char> sel(C, 0);\n            for (int y = rc.y1; y <= rc.y2; y++) {\n                for (int x = rc.x1; x <= rc.x2; x++) {\n                    sel[id(x, y)] = 1;\n                }\n            }\n            consider_candidate(move(sel));\n        }\n\n        // Profit maps\n        vector<vector<int>> profits(4);\n        for (int r = 0; r <= 3; r++) profits[r] = build_profit(r);\n\n        // (radius, lambda)\n        vector<pair<int, int>> params = {\n            {2, 0}, {3, 0}, {1, 0},\n            {0, 4}, {1, 8}, {2, 12},\n            {0, 7}, {1, 12}, {2, 16},\n            {0, 10}, {3, 18}\n        };\n\n        for (auto [r, lam] : params) {\n            if (lam > 0 && elapsed() > 1.78) break;\n            if (lam == 0 && elapsed() > 1.86) break;\n\n            auto sel = segment_cut(profits[r], lam);\n            auto comps = top_components(sel, 5);\n\n            int singleTake = min(4, (int)comps.size());\n            for (int i = 0; i < singleTake; i++) {\n                if (elapsed() > SOFT_LIMIT) break;\n                vector<char> compSel(C, 0);\n                for (int v : comps[i].cells) compSel[v] = 1;\n                consider_candidate(move(compSel));\n            }\n\n            int pairTake = min(3, (int)comps.size());\n            for (int i = 0; i < pairTake; i++) {\n                for (int j = i + 1; j < pairTake; j++) {\n                    if (elapsed() > SOFT_LIMIT) break;\n\n                    int d = bbox_dist(comps[i], comps[j]);\n                    if (d > PmaxUnits / 2) continue;\n\n                    int estPer = comps[i].perim + comps[j].perim + 2 * d + 8;\n                    if (estPer > PmaxUnits + 180) continue;\n\n                    vector<char> merged;\n                    int pathLen = 0;\n                    if (!connect_components(comps[i], comps[j], merged, pathLen)) continue;\n                    if (pathLen > PmaxUnits / 2 + 30) continue;\n\n                    consider_candidate(move(merged));\n                }\n            }\n        }\n\n        // Fallback candidates\n        vector<Point> fbTiny = tiny_square_around_first_mackerel();\n        int tinyDiff = rect_diff(fbTiny[0].x, fbTiny[1].x, fbTiny[0].y, fbTiny[2].y);\n\n        int cellBest = 0;\n        for (int i = 1; i < C; i++) if (raw[i] > raw[cellBest]) cellBest = i;\n        vector<Point> fbCell = cell_rect_poly(cellBest);\n        int cellDiff = rect_diff(fbCell[0].x, fbCell[1].x, fbCell[0].y, fbCell[2].y);\n\n        vector<Point> fb = (cellDiff >= tinyDiff ? fbCell : fbTiny);\n        int fbDiff = max(cellDiff, tinyDiff);\n\n        vector<Point> ans = bestPoly;\n        int ansDiff = bestDiff;\n\n        if (ans.empty() || ansDiff < fbDiff || !final_valid(ans)) ans = fb;\n        if (!final_valid(ans)) ans = fbTiny;\n\n        cout << ans.size() << '\\n';\n        for (auto &p : ans) {\n            cout << p.x << ' ' << p.y << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nconstexpr int MAXN = 105;\nconstexpr ll DIM_MAX = 1000000000LL;\n\nstatic inline uint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstruct FastRNG {\n    uint64_t x;\n    bool has_spare = false;\n    double spare = 0.0;\n\n    explicit FastRNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next_u64() {\n        return splitmix64(x += 0x9e3779b97f4a7c15ULL);\n    }\n    double uniform01() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n    int randint(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double normal01() {\n        if (has_spare) {\n            has_spare = false;\n            return spare;\n        }\n        double u, v, s;\n        do {\n            u = uniform01() * 2.0 - 1.0;\n            v = uniform01() * 2.0 - 1.0;\n            s = u * u + v * v;\n        } while (s >= 1.0 || s == 0.0);\n        double m = sqrt(-2.0 * log(s) / s);\n        spare = v * m;\n        has_spare = true;\n        return u * m;\n    }\n};\n\nstruct Operation {\n    uint8_t r; // 0/1\n    uint8_t d; // 0:U, 1:L\n    int b;     // -1 or previous index\n};\n\nstruct GreedyParam {\n    double gap_w;\n    double bal_w;\n    double noise_w;\n};\n\nstruct Scenario {\n    vector<ll> w, h;\n};\n\nstruct Candidate {\n    vector<Operation> ops;\n    vector<ll> predW, predH, predS; // per scenario\n    double avg = 0.0;\n    uint64_t hash = 0;\n};\n\ninline ll clamp_dim(ll v) {\n    if (v < 1) return 1;\n    if (v > DIM_MAX) return DIM_MAX;\n    return v;\n}\ninline bool overlap(ll l1, ll r1, ll l2, ll r2) {\n    return (l1 < r2) && (l2 < r1);\n}\n\n// Lower bound of final W+H with constraints W>=curW, H>=curH, W*H>=totalA\ninline double lower_bound_wh(ll curW, ll curH, long double totalA, long double sqrtA) {\n    long double w = (long double)curW;\n    long double h = (long double)curH;\n    if (w * h >= totalA) return (double)(w + h);\n\n    long double c1 = w + max(h, totalA / w); // fix W\n    long double c2 = h + max(w, totalA / h); // fix H\n    long double c3 = 1e100L;\n    if (w <= sqrtA && h <= sqrtA) c3 = 2.0L * sqrtA;\n    long double ans = min(c1, min(c2, c3));\n    return (double)ans;\n}\n\npair<ll, ll> simulate_layout(\n    const vector<ll>& baseW, const vector<ll>& baseH, const vector<Operation>& ops\n) {\n    int N = (int)ops.size();\n    array<ll, MAXN> x{}, y{}, w{}, h{};\n    ll BW = 0, BH = 0;\n\n    for (int i = 0; i < N; i++) {\n        const auto& op = ops[i];\n        ll wi = op.r ? baseH[i] : baseW[i];\n        ll hi = op.r ? baseW[i] : baseH[i];\n\n        ll xi = 0, yi = 0;\n        if (op.d == 0) { // U\n            xi = (op.b == -1) ? 0 : (x[op.b] + w[op.b]);\n            ll xr = xi + wi;\n            yi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(xi, xr, x[j], x[j] + w[j])) {\n                    ll cand = y[j] + h[j];\n                    if (cand > yi) yi = cand;\n                }\n            }\n        } else { // L\n            yi = (op.b == -1) ? 0 : (y[op.b] + h[op.b]);\n            ll yb = yi + hi;\n            xi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(yi, yb, y[j], y[j] + h[j])) {\n                    ll cand = x[j] + w[j];\n                    if (cand > xi) xi = cand;\n                }\n            }\n        }\n\n        x[i] = xi;\n        y[i] = yi;\n        w[i] = wi;\n        h[i] = hi;\n\n        BW = max(BW, xi + wi);\n        BH = max(BH, yi + hi);\n    }\n    return {BW, BH};\n}\n\nvector<Operation> build_greedy(\n    const vector<ll>& baseW, const vector<ll>& baseH,\n    const GreedyParam& param, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n    vector<Operation> ops(N);\n\n    array<ll, MAXN> x{}, y{}, w{}, h{};\n    ll curW = 0, curH = 0;\n    long double usedA = 0.0L;\n\n    long double totalA = 0.0L;\n    for (int i = 0; i < N; i++) totalA += (long double)baseW[i] * baseH[i];\n    long double sqrtA = sqrtl(max((long double)1.0, totalA));\n    long double norm = sqrtA + 1.0L;\n\n    for (int i = 0; i < N; i++) {\n        double bestScore = 1e300;\n        ll bestPerim = (1LL << 60);\n\n        Operation bestOp{0, 0, -1};\n        ll bestX = 0, bestY = 0, bestWi = 0, bestHi = 0;\n        ll nextW = 0, nextH = 0;\n\n        for (int rot = 0; rot < 2; rot++) {\n            ll wi = rot ? baseH[i] : baseW[i];\n            ll hi = rot ? baseW[i] : baseH[i];\n\n            for (int dir = 0; dir < 2; dir++) {\n                for (int b = -1; b < i; b++) {\n                    ll xi = 0, yi = 0;\n                    if (dir == 0) { // U\n                        xi = (b == -1) ? 0 : (x[b] + w[b]);\n                        ll xr = xi + wi;\n                        yi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(xi, xr, x[j], x[j] + w[j])) {\n                                ll cand = y[j] + h[j];\n                                if (cand > yi) yi = cand;\n                            }\n                        }\n                    } else { // L\n                        yi = (b == -1) ? 0 : (y[b] + h[b]);\n                        ll yb = yi + hi;\n                        xi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(yi, yb, y[j], y[j] + h[j])) {\n                                ll cand = x[j] + w[j];\n                                if (cand > xi) xi = cand;\n                            }\n                        }\n                    }\n\n                    ll nW = max(curW, xi + wi);\n                    ll nH = max(curH, yi + hi);\n\n                    long double newA = usedA + (long double)wi * hi;\n                    double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                    long double gap = (long double)nW * nH - newA;\n                    if (gap < 0) gap = 0;\n\n                    double score = lb\n                        + param.gap_w * (double)(gap / norm)\n                        + param.bal_w * (double)llabs(nW - nH);\n                    if (param.noise_w > 0.0) score += param.noise_w * rng.uniform01();\n\n                    ll perim = nW + nH;\n                    if (score < bestScore - 1e-12 ||\n                        (fabsl(score - bestScore) <= 1e-12 && perim < bestPerim)) {\n                        bestScore = score;\n                        bestPerim = perim;\n                        bestOp = Operation{(uint8_t)rot, (uint8_t)dir, b};\n                        bestX = xi;\n                        bestY = yi;\n                        bestWi = wi;\n                        bestHi = hi;\n                        nextW = nW;\n                        nextH = nH;\n                    }\n                }\n            }\n        }\n\n        ops[i] = bestOp;\n        x[i] = bestX;\n        y[i] = bestY;\n        w[i] = bestWi;\n        h[i] = bestHi;\n        curW = nextW;\n        curH = nextH;\n        usedA += (long double)bestWi * bestHi;\n    }\n\n    return ops;\n}\n\nvector<Operation> build_linear_chain(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal, bool minimize_cross\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (minimize_cross) {\n            if (horizontal) r = (w[i] < h[i]) ? 1 : 0; // min row height\n            else r = (h[i] < w[i]) ? 1 : 0;            // min col width\n        }\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 0 : 1), (i == 0 ? -1 : i - 1)};\n    }\n    return ops;\n}\n\nvector<Operation> build_single_stack(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal\n) {\n    // horizontal row: (L, -1), vertical column: (U, -1)\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n        else r = (h[i] < w[i]) ? 1 : 0;\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 1 : 0), -1};\n    }\n    return ops;\n}\n\nuint64_t hash_ops(const vector<Operation>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (size_t i = 0; i < ops.size(); i++) {\n        uint64_t v = (uint64_t)ops[i].r;\n        v = v * 3ULL + (uint64_t)ops[i].d;\n        v = v * 1315423911ULL + (uint64_t)(ops[i].b + 2);\n        h ^= splitmix64(v + (i + 1) * 0x9e3779b97f4a7c15ULL);\n    }\n    return h;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    ll sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n\n    vector<ll> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    seed ^= splitmix64((uint64_t)N * 1000003ULL + (uint64_t)T * 10007ULL + (uint64_t)sigma * 911382323ULL);\n    for (int i = 0; i < N; i++) {\n        seed ^= splitmix64((uint64_t)obsW[i] * 1000003ULL + (uint64_t)obsH[i] + (uint64_t)(i + 1) * 19260817ULL);\n    }\n    FastRNG rng(seed);\n\n    auto start_time = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    };\n\n    int S;\n    if (sigma <= 2500) S = 12;\n    else if (sigma <= 6000) S = 18;\n    else S = 24;\n\n    vector<Scenario> scenarios(S);\n    for (int s = 0; s < S; s++) {\n        scenarios[s].w.resize(N);\n        scenarios[s].h.resize(N);\n    }\n\n    // Scenario 0: observed values\n    for (int i = 0; i < N; i++) {\n        scenarios[0].w[i] = obsW[i];\n        scenarios[0].h[i] = obsH[i];\n    }\n    // Scenario 1/2: global +-sigma shifts\n    if (S >= 2) {\n        for (int i = 0; i < N; i++) {\n            scenarios[1].w[i] = clamp_dim(obsW[i] + sigma);\n            scenarios[1].h[i] = clamp_dim(obsH[i] + sigma);\n        }\n    }\n    if (S >= 3) {\n        for (int i = 0; i < N; i++) {\n            scenarios[2].w[i] = clamp_dim(obsW[i] - sigma);\n            scenarios[2].h[i] = clamp_dim(obsH[i] - sigma);\n        }\n    }\n    // Random posterior samples\n    for (int s = 3; s < S; s++) {\n        for (int i = 0; i < N; i++) {\n            ll sw = llround((long double)obsW[i] + (long double)sigma * rng.normal01());\n            ll sh = llround((long double)obsH[i] + (long double)sigma * rng.normal01());\n            scenarios[s].w[i] = clamp_dim(sw);\n            scenarios[s].h[i] = clamp_dim(sh);\n        }\n    }\n\n    int Ptarget = min(120, max(30, T * 2));\n    if (sigma <= 2500) Ptarget = min(Ptarget, 80);\n\n    vector<Candidate> pool;\n    pool.reserve(Ptarget + 16);\n    unordered_set<uint64_t> seen;\n    seen.reserve(Ptarget * 4 + 64);\n\n    auto add_candidate = [&](vector<Operation>&& ops) {\n        uint64_t h = hash_ops(ops);\n        if (seen.insert(h).second) {\n            Candidate c;\n            c.hash = h;\n            c.ops = move(ops);\n            pool.push_back(move(c));\n        }\n    };\n\n    // Baselines\n    add_candidate(build_linear_chain(obsW, obsH, true, true));\n    add_candidate(build_linear_chain(obsW, obsH, false, true));\n    add_candidate(build_single_stack(obsW, obsH, true));\n    add_candidate(build_single_stack(obsW, obsH, false));\n\n    // Deterministic greedy on observed\n    vector<GreedyParam> baseParams = {\n        {0.35, 0.006, 0.0},\n        {0.65, 0.010, 0.0},\n        {0.15, 0.000, 0.0}\n    };\n    for (auto gp : baseParams) {\n        add_candidate(build_greedy(obsW, obsH, gp, rng));\n    }\n\n    // Deterministic greedy on some scenarios\n    int scenarioDetCnt = min(S, max(6, Ptarget / 2));\n    for (int s = 0; s < scenarioDetCnt && (int)pool.size() < Ptarget; s++) {\n        GreedyParam gp{0.45, 0.008, 0.0};\n        add_candidate(build_greedy(scenarios[s].w, scenarios[s].h, gp, rng));\n    }\n\n    // Randomized greedy\n    int attempts = 0;\n    const double genBudgetSec = 1.15;\n    const int minNeed = min(Ptarget, 70);\n\n    while ((int)pool.size() < Ptarget && attempts < Ptarget * 20) {\n        if ((int)pool.size() >= minNeed && elapsed() > genBudgetSec) break;\n\n        int sid = rng.randint(0, S - 1);\n        GreedyParam gp;\n        gp.gap_w = 0.05 + 1.10 * rng.uniform01();\n        gp.bal_w = 0.03 * rng.uniform01();\n        gp.noise_w = (double)sigma * (0.45 * rng.uniform01());\n        if (rng.uniform01() < 0.15) gp.noise_w += (double)sigma * (0.50 * rng.uniform01());\n\n        add_candidate(build_greedy(scenarios[sid].w, scenarios[sid].h, gp, rng));\n        attempts++;\n    }\n\n    if (pool.empty()) {\n        add_candidate(build_greedy(obsW, obsH, GreedyParam{0.40, 0.008, 0.0}, rng));\n    }\n\n    // Precompute each candidate on each scenario\n    for (auto& cand : pool) {\n        cand.predW.resize(S);\n        cand.predH.resize(S);\n        cand.predS.resize(S);\n\n        long double sum = 0.0L;\n        for (int s = 0; s < S; s++) {\n            auto [W, H] = simulate_layout(scenarios[s].w, scenarios[s].h, cand.ops);\n            cand.predW[s] = W;\n            cand.predH[s] = H;\n            cand.predS[s] = W + H;\n            sum += (long double)(W + H);\n        }\n        cand.avg = (double)(sum / (long double)S);\n    }\n\n    // Online planning\n    vector<ll> bestScenario(S, (1LL << 60));\n    vector<double> logWeight(S, 0.0);\n    vector<char> used(pool.size(), 0);\n    int usedCnt = 0;\n\n    const double likeSigma = max(1000.0, (double)sigma * 1.8);\n    const double inv2var = 1.0 / (2.0 * likeSigma * likeSigma);\n    const double alphaPosterior = 0.7;\n\n    vector<double> weights(S, 1.0 / S);\n\n    for (int turn = 0; turn < T; turn++) {\n        double mxLog = *max_element(logWeight.begin(), logWeight.end());\n        double sumW = 0.0;\n        for (int s = 0; s < S; s++) {\n            weights[s] = exp(logWeight[s] - mxLog);\n            sumW += weights[s];\n        }\n        if (sumW <= 0) {\n            for (int s = 0; s < S; s++) weights[s] = 1.0 / S;\n        } else {\n            for (int s = 0; s < S; s++) weights[s] /= sumW;\n        }\n        for (int s = 0; s < S; s++) {\n            weights[s] = (1.0 - alphaPosterior) / S + alphaPosterior * weights[s];\n        }\n\n        bool hasUnused = (usedCnt < (int)pool.size());\n        int chosen = -1;\n        long double bestVal = 1e300L;\n\n        for (int ci = 0; ci < (int)pool.size(); ci++) {\n            if (hasUnused && used[ci]) continue;\n\n            long double val = 0.0L;\n            for (int s = 0; s < S; s++) {\n                ll sc = pool[ci].predS[s];\n                ll cur = (bestScenario[s] < sc) ? bestScenario[s] : sc;\n                val += (long double)weights[s] * (long double)cur;\n            }\n\n            if (chosen == -1 || val < bestVal - 1e-12L ||\n                (fabsl(val - bestVal) <= 1e-12L && pool[ci].avg < pool[chosen].avg)) {\n                bestVal = val;\n                chosen = ci;\n            }\n        }\n        if (chosen == -1) chosen = 0;\n\n        if (!used[chosen]) {\n            used[chosen] = 1;\n            usedCnt++;\n        }\n\n        // Output this turn\n        cout << N << '\\n';\n        for (int i = 0; i < N; i++) {\n            const auto& op = pool[chosen].ops[i];\n            cout << i << ' ' << int(op.r) << ' ' << (op.d == 0 ? 'U' : 'L') << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        // Receive measured W', H'\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        if (Wm == -1 && Hm == -1) return 0;\n\n        // Update best per scenario\n        for (int s = 0; s < S; s++) {\n            if (pool[chosen].predS[s] < bestScenario[s]) bestScenario[s] = pool[chosen].predS[s];\n        }\n\n        // Posterior update\n        for (int s = 0; s < S; s++) {\n            double dw = (double)Wm - (double)pool[chosen].predW[s];\n            double dh = (double)Hm - (double)pool[chosen].predH[s];\n            logWeight[s] += -(dw * dw + dh * dh) * inv2var;\n        }\n\n        // Numerical stabilization\n        double mx2 = *max_element(logWeight.begin(), logWeight.end());\n        for (int s = 0; s < S; s++) logWeight[s] -= mx2;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<vector<int>> g;\n    vector<int> ordDesc, ordAsc;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point startTime;\n\n    struct State {\n        vector<int> d;    // depth labels\n        vector<int> cnt;  // support count: #neighbors with depth d[v]-1 (for d[v] > 0)\n        long long extra = 0; // sum d[v]*A[v]\n    };\n\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        // coordinates are unused in this solver\n        for (int i = 0; i < N; i++) {\n            int x, y;\n            cin >> x >> y;\n        }\n    }\n\n    void shuffle_vec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i >= 1; --i) {\n            int j = rng.next_int(0, i);\n            swap(v[i], v[j]);\n        }\n    }\n\n    void rebuild(State& st) const {\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n        for (int v = 0; v < N; v++) st.extra += 1LL * st.d[v] * A[v];\n\n        for (int v = 0; v < N; v++) {\n            if (st.d[v] == 0) continue;\n            int need = st.d[v] - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n    }\n\n    // Force feasibility by only decreasing depths.\n    void repair_depth(vector<int>& d) const {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int v = 0; v < N; v++) {\n                while (d[v] > 0) {\n                    int need = d[v] - 1;\n                    bool ok = false;\n                    for (int u : g[v]) {\n                        if (d[u] == need) {\n                            ok = true;\n                            break;\n                        }\n                    }\n                    if (ok) break;\n                    --d[v];\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    inline bool feasible_change(const State& st, int v, int nd) const {\n        int od = st.d[v];\n        if (nd == od) return false;\n        if (nd < 0 || nd > H) return false;\n\n        // v itself must be supported when nd > 0\n        if (nd > 0) {\n            bool ok = false;\n            for (int u : g[v]) {\n                if (st.d[u] == nd - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n\n        // neighbors must keep at least one supporter\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            int c = st.cnt[u];\n            if (od == need) --c;\n            if (nd == need) ++c;\n            if (c <= 0) return false;\n        }\n        return true;\n    }\n\n    inline void apply_change(State& st, int v, int nd) const {\n        int od = st.d[v];\n        if (od == nd) return;\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            if (od == need) --st.cnt[u];\n            if (nd == need) ++st.cnt[u];\n        }\n\n        st.d[v] = nd;\n        if (nd == 0) {\n            st.cnt[v] = 0;\n        } else {\n            int need = nd - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n\n        st.extra += 1LL * (nd - od) * A[v];\n    }\n\n    // stepwise=true: try only +1; else: try highest feasible\n    bool greedy_up_pass(State& st, const vector<int>& order, bool stepwise) const {\n        bool changed = false;\n        for (int v : order) {\n            int cur = st.d[v];\n            if (stepwise) {\n                int nd = cur + 1;\n                if (nd <= H && feasible_change(st, v, nd)) {\n                    apply_change(st, v, nd);\n                    changed = true;\n                }\n            } else {\n                for (int nd = H; nd > cur; --nd) {\n                    if (feasible_change(st, v, nd)) {\n                        apply_change(st, v, nd);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n        return changed;\n    }\n\n    State construct_initial_variant(int variant) {\n        State st;\n        st.d.assign(N, 0);\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) key[v] = A[v] * 2048 + rng.next_int(0, 2047);\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 1) {\n            order = ordDesc;\n            int sw = N / 4;\n            for (int i = 0; i < sw; i++) {\n                int x = rng.next_int(0, N - 1), y = rng.next_int(0, N - 1);\n                swap(order[x], order[y]);\n            }\n        } else if (variant == 2) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) {\n                int deg = (int)g[v].size();\n                key[v] = (A[v] * 1000) / (deg + 1) + rng.next_int(0, 199);\n            }\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 3) {\n            order = ordDesc;\n            shuffle_vec(order);\n        } else {\n            order = ordDesc;\n        }\n\n        for (int pass = 0; pass < 28; pass++) {\n            bool step = (pass < 4);\n            bool changed = greedy_up_pass(st, order, step);\n\n            if (pass == 1 || pass == 4 || pass == 8) {\n                if (variant == 3 || variant == 1) shuffle_vec(order);\n            }\n            if (!changed && pass > 7) break;\n        }\n\n        for (int rep = 0; rep < 5; rep++) {\n            if (!greedy_up_pass(st, ordDesc, false)) break;\n        }\n\n        return st;\n    }\n\n    void short_sa_polish(State& st, int iters, double T0, double T1, double timeLimit) {\n        int topK = min(N, 240);\n        vector<int> bestD = st.d;\n        long long bestE = st.extra;\n\n        for (int it = 0; it < iters; it++) {\n            if ((it & 127) == 0) {\n                if (elapsed() >= timeLimit) break;\n            }\n\n            int v = (rng.next_double() < 0.7) ? ordDesc[rng.next_int(0, topK - 1)] : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = st.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != st.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.45) nd = cand[clen - 1];\n            else if (r < 0.58) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(st, v, nd)) continue;\n\n            int delta = (nd - st.d[v]) * A[v];\n            double p = (double)it / max(1, iters - 1);\n            double temp = T0 * pow(T1 / T0, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n            if (!accept) continue;\n\n            apply_change(st, v, nd);\n            if (st.extra > bestE) {\n                bestE = st.extra;\n                bestD = st.d;\n            }\n        }\n\n        if (bestE > st.extra) {\n            st.d = move(bestD);\n            rebuild(st);\n        }\n    }\n\n    void run_feasible_sa(State& cur, State& best, double timeLimit) {\n        double saStart = elapsed();\n        if (saStart >= timeLimit) return;\n\n        const double T0 = 60.0;\n        const double T1 = 0.15;\n        const double ratio = T1 / T0;\n        int topK = min(N, 300);\n\n        long long iter = 0;\n        while (true) {\n            if ((iter & 255LL) == 0) {\n                if (elapsed() >= timeLimit) break;\n            }\n            ++iter;\n\n            int v = (rng.next_double() < 0.62) ? ordDesc[rng.next_int(0, topK - 1)] : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = cur.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != cur.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.48) nd = cand[clen - 1];\n            else if (r < 0.62) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(cur, v, nd)) continue;\n\n            int delta = (nd - cur.d[v]) * A[v];\n            double now = elapsed();\n            double p = (now - saStart) / max(1e-9, timeLimit - saStart);\n            p = max(0.0, min(1.0, p));\n            double temp = T0 * pow(ratio, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n            if (!accept) continue;\n\n            apply_change(cur, v, nd);\n            if (cur.extra > best.extra) best = cur;\n\n            if ((iter & 65535LL) == 0 && cur.extra + 4000 < best.extra) cur = best;\n        }\n    }\n\n    void macro_perturb_search(State& best, double timeLimit) {\n        int topHigh = min(N, 300);\n        int topLow  = min(N, 420);\n        vector<int> order = ordDesc;\n\n        while (elapsed() < timeLimit) {\n            State tmp = best;\n            int mode = rng.next_int(0, 4);\n\n            if (mode == 0) {\n                int k = rng.next_int(1, 4);\n                for (int i = 0; i < k; i++) {\n                    int v = ordDesc[rng.next_int(0, topHigh - 1)];\n                    tmp.d[v] = H;\n                }\n            } else if (mode == 1) {\n                int k = rng.next_int(2, 7);\n                for (int i = 0; i < k; i++) {\n                    int v = ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = 0;\n                }\n            } else if (mode == 2) {\n                int k = rng.next_int(20, 90);\n                for (int i = 0; i < k; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    tmp.d[v] = rng.next_int(0, H);\n                }\n            } else if (mode == 3) {\n                int k = rng.next_int(18, 60);\n                for (int i = 0; i < k; i++) {\n                    bool hi = (rng.next_double() < 0.62);\n                    int v = hi ? ordDesc[rng.next_int(0, topHigh - 1)]\n                               : ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = hi ? H : 0;\n                }\n            } else {\n                int c = rng.next_int(0, N - 1);\n                tmp.d[c] = (rng.next_double() < 0.5 ? 0 : H);\n                for (int u : g[c]) {\n                    if (rng.next_double() < 0.75) tmp.d[u] = rng.next_int(0, H);\n                }\n                int extra = rng.next_int(6, 22);\n                for (int i = 0; i < extra; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    if (rng.next_double() < 0.55) tmp.d[v] = 0;\n                }\n            }\n\n            repair_depth(tmp.d);\n            rebuild(tmp);\n\n            order = ordDesc;\n            for (int pass = 0; pass < 8; pass++) {\n                if (pass == 1 || pass == 4) shuffle_vec(order);\n                else if (pass == 2 || pass == 5) order = ordDesc;\n\n                bool step = (pass < 2);\n                bool changed = greedy_up_pass(tmp, order, step);\n\n                if (!changed && pass >= 4) break;\n                if (elapsed() >= timeLimit) break;\n            }\n\n            if (elapsed() + 0.012 < timeLimit && rng.next_double() < 0.55) {\n                short_sa_polish(tmp, 900, 2.2, 0.35, timeLimit);\n            }\n\n            if (tmp.extra > best.extra) best = move(tmp);\n        }\n    }\n\n    vector<int> optimize_depths() {\n        startTime = chrono::steady_clock::now();\n\n        ordDesc.resize(N);\n        iota(ordDesc.begin(), ordDesc.end(), 0);\n        sort(ordDesc.begin(), ordDesc.end(), [&](int a, int b) {\n            if (A[a] != A[b]) return A[a] > A[b];\n            if (g[a].size() != g[b].size()) return g[a].size() < g[b].size();\n            return a < b;\n        });\n        ordAsc = ordDesc;\n        reverse(ordAsc.begin(), ordAsc.end());\n\n        const double TOTAL_TIME = 1.85;\n        const double INIT_END   = 0.28;\n        const double SA_END     = 1.35;\n\n        State best;\n        best.extra = LLONG_MIN;\n\n        int restart = 0;\n        while (elapsed() < INIT_END) {\n            State st = construct_initial_variant(restart % 5);\n\n            if ((restart & 1) == 0 && elapsed() + 0.01 < INIT_END) {\n                short_sa_polish(st, 500, 5.0, 0.8, INIT_END);\n            }\n\n            if (st.extra > best.extra) best = move(st);\n            restart++;\n        }\n\n        if (best.extra == LLONG_MIN) {\n            best.d.assign(N, 0);\n            best.cnt.assign(N, 0);\n            best.extra = 0;\n        }\n\n        State cur = best;\n        run_feasible_sa(cur, best, SA_END);\n        macro_perturb_search(best, TOTAL_TIME);\n\n        // final safety + polish\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 6; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    vector<int> build_parent_from_depth(const vector<int>& d) const {\n        vector<int> p(N, -1);\n        for (int v = 0; v < N; v++) {\n            if (d[v] == 0) {\n                p[v] = -1;\n                continue;\n            }\n            int target = d[v] - 1;\n            int par = -1;\n            for (int u : g[v]) {\n                if (d[u] == target) {\n                    par = u;\n                    break;\n                }\n            }\n            p[v] = par; // should normally exist\n        }\n        return p;\n    }\n\n    void solve() {\n        read_input();\n        vector<int> depth = optimize_depths();\n        vector<int> parent = build_parent_from_depth(depth);\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << parent[i];\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}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 20;\nconstexpr int MAXC = 80;\nconstexpr int MAXD = 20;\nconstexpr int MAXM = 64;\n\nstruct Chain {\n    char dir, rev;\n    int idx;\n};\nstruct Option {\n    int chain, req;\n};\n\nstruct State {\n    array<uint8_t, MAXC> d{};   // depth per chain\n    array<uint8_t, MAXM> sat{}; // number of satisfied options for each oni\n    uint64_t unsatMask = 0;     // oni not yet covered\n    int cost = 0;               // paired macro cost = 2 * sum(depth)\n};\n\nclass Solver {\npublic:\n    int N, Cn, M;\n    vector<string> board;\n    int initialFuku = 0;\n\n    array<Chain, MAXC> chains{};\n    vector<vector<Option>> opts;                  // size M\n    vector<pair<int,int>> oniPos;                 // size M\n\n    array<int, MAXC> cap{};                       // max useful depth for each chain\n    array<array<uint64_t, MAXD + 1>, MAXC> eqMask{}; // oni with req == d on chain c\n    array<array<uint64_t, MAXD + 1>, MAXC> leMask{}; // oni with req <= d on chain c\n    array<vector<int>, MAXC> usefulDepths{};\n\n    uint64_t fullMask = 0;\n    mt19937 rng;\n\n    Solver(int n, vector<string> b) : N(n), Cn(4*n), board(move(b)) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        build();\n    }\n\n    inline int idUp(int j) const { return j; }\n    inline int idDown(int j) const { return N + j; }\n    inline int idLeft(int i) const { return 2 * N + i; }\n    inline int idRight(int i) const { return 3 * N + i; }\n\n    void build() {\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            if (board[i][j] == 'x') oniPos.push_back({i, j});\n            if (board[i][j] == 'o') initialFuku++;\n        }\n        M = (int)oniPos.size();\n        opts.assign(M, {});\n\n        vector<int> upSafe(N, N), downSafe(N, N), leftSafe(N, N), rightSafe(N, N);\n\n        for (int j = 0; j < N; j++) {\n            for (int i = 0; i < N; i++) if (board[i][j] == 'o') { upSafe[j] = i; break; }\n            for (int i = N - 1; i >= 0; i--) if (board[i][j] == 'o') { downSafe[j] = N - 1 - i; break; }\n        }\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) if (board[i][j] == 'o') { leftSafe[i] = j; break; }\n            for (int j = N - 1; j >= 0; j--) if (board[i][j] == 'o') { rightSafe[i] = N - 1 - j; break; }\n        }\n\n        for (int j = 0; j < N; j++) {\n            chains[idUp(j)]   = {'U', 'D', j};\n            chains[idDown(j)] = {'D', 'U', j};\n        }\n        for (int i = 0; i < N; i++) {\n            chains[idLeft(i)]  = {'L', 'R', i};\n            chains[idRight(i)] = {'R', 'L', i};\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto [r, c] = oniPos[m];\n            int reqU = r + 1;\n            int reqD = N - r;\n            int reqL = c + 1;\n            int reqR = N - c;\n\n            if (reqU <= upSafe[c])    opts[m].push_back({idUp(c), reqU});\n            if (reqD <= downSafe[c])  opts[m].push_back({idDown(c), reqD});\n            if (reqL <= leftSafe[r])  opts[m].push_back({idLeft(r), reqL});\n            if (reqR <= rightSafe[r]) opts[m].push_back({idRight(r), reqR});\n\n            // Safety net: should never happen with problem guarantee.\n            if (opts[m].empty()) opts[m].push_back({idUp(c), min(reqU, N)});\n        }\n\n        for (int c = 0; c < MAXC; c++) {\n            cap[c] = 0;\n            usefulDepths[c].clear();\n            for (int d = 0; d <= MAXD; d++) {\n                eqMask[c][d] = 0;\n                leMask[c][d] = 0;\n            }\n        }\n\n        for (int m = 0; m < M; m++) {\n            for (auto &op : opts[m]) eqMask[op.chain][op.req] |= (1ULL << m);\n        }\n\n        for (int c = 0; c < Cn; c++) {\n            leMask[c][0] = 0;\n            for (int d = 1; d <= N; d++) {\n                leMask[c][d] = leMask[c][d - 1] | eqMask[c][d];\n                if (eqMask[c][d]) {\n                    usefulDepths[c].push_back(d);\n                    cap[c] = d;\n                }\n            }\n        }\n\n        fullMask = (M == 64 ? ~0ULL : ((1ULL << M) - 1ULL));\n    }\n\n    inline State makeZeroState() const {\n        State s;\n        s.d.fill(0);\n        s.sat.fill(0);\n        s.unsatMask = fullMask;\n        s.cost = 0;\n        return s;\n    }\n\n    inline void incChain(State &s, int c) {\n        int nd = (int)s.d[c] + 1;\n        uint64_t bits = eqMask[c][nd];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            if (s.sat[m]++ == 0) s.unsatMask &= ~(1ULL << m);\n        }\n        s.d[c] = (uint8_t)nd;\n        s.cost += 2;\n    }\n\n    inline void decChain(State &s, int c) {\n        int t = (int)s.d[c];\n        uint64_t bits = eqMask[c][t];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            uint8_t v = --s.sat[m];\n            if (v == 0) s.unsatMask |= (1ULL << m);\n        }\n        s.d[c] = (uint8_t)(t - 1);\n        s.cost -= 2;\n    }\n\n    inline void setChain(State &s, int c, int nd) {\n        while ((int)s.d[c] < nd) incChain(s, c);\n        while ((int)s.d[c] > nd) decChain(s, c);\n    }\n\n    State fromDepth(const array<uint8_t, MAXC>& depth) {\n        State s = makeZeroState();\n        for (int c = 0; c < Cn; c++) {\n            for (int t = 0; t < (int)depth[c]; t++) incChain(s, c);\n        }\n        return s;\n    }\n\n    void reduceDepth(State &s, bool randomOrder) {\n        array<int, MAXC> ord{};\n        for (int i = 0; i < Cn; i++) ord[i] = i;\n        if (randomOrder) shuffle(ord.begin(), ord.begin() + Cn, rng);\n\n        for (int ii = 0; ii < Cn; ii++) {\n            int c = ord[ii];\n            while ((int)s.d[c] > 0) {\n                int t = (int)s.d[c];\n                uint64_t bits = eqMask[c][t];\n                bool ok = true;\n                while (bits) {\n                    int m = __builtin_ctzll(bits);\n                    bits &= bits - 1;\n                    if (s.sat[m] == 1) { ok = false; break; }\n                }\n                if (!ok) break;\n                decChain(s, c);\n            }\n        }\n    }\n\n    void greedyRepair(State &s, bool randomized) {\n        while (s.unsatMask) {\n            double bestScore = -1e100;\n            int bc = -1, br = -1;\n            int bg = -1, bdelta = 1e9;\n\n            for (int c = 0; c < Cn; c++) {\n                int dc = (int)s.d[c];\n                if (dc >= cap[c]) continue;\n                for (int r : usefulDepths[c]) {\n                    if (r <= dc) continue;\n                    uint64_t gainMask = leMask[c][r] & s.unsatMask;\n                    int g = __builtin_popcountll(gainMask);\n                    if (g == 0) continue;\n                    int delta = r - dc;\n                    double score = (double)g / (double)delta;\n                    if (randomized) score += (double)(rng() & 1023) * 1e-6;\n\n                    if (score > bestScore + 1e-12 ||\n                        (fabs(score - bestScore) <= 1e-12 && (g > bg || (g == bg && delta < bdelta)))) {\n                        bestScore = score;\n                        bc = c;\n                        br = r;\n                        bg = g;\n                        bdelta = delta;\n                    }\n                }\n            }\n\n            if (bc == -1) {\n                int m = __builtin_ctzll(s.unsatMask);\n                int bestDelta = 1e9;\n                for (auto &op : opts[m]) {\n                    int delta = max(0, op.req - (int)s.d[op.chain]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bc = op.chain;\n                        br = op.req;\n                    }\n                }\n                if (bc == -1) break;\n            }\n\n            setChain(s, bc, br);\n        }\n    }\n\n    int rowSave(const State& s) const {\n        int save = 0;\n        for (int i = 0; i < N; i++) {\n            int l = s.d[idLeft(i)];\n            int r = s.d[idRight(i)];\n            if (l == 0 || r == 0) save += l + r;\n            else save += max(l, r);\n        }\n        return save;\n    }\n\n    int colSave(const State& s) const {\n        int save = 0;\n        for (int j = 0; j < N; j++) {\n            int u = s.d[idUp(j)];\n            int d = s.d[idDown(j)];\n            if (u == 0 || d == 0) save += u + d;\n            else save += max(u, d);\n        }\n        return save;\n    }\n\n    int estimateMoves(const State& s) const {\n        return s.cost - max(rowSave(s), colSave(s));\n    }\n\n    State baselineMinReq() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            depth[op.chain] = max<int>(depth[op.chain], op.req);\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, false);\n        return s;\n    }\n\n    State trialAssign() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n        stable_sort(ord.begin(), ord.end(),\n                    [&](int a, int b){ return opts[a].size() < opts[b].size(); });\n\n        for (int m : ord) {\n            int choose = 0;\n            if ((int)(rng() % 100) < 8) {\n                choose = (int)(rng() % opts[m].size());\n            } else {\n                int bestKey = 1e9;\n                vector<int> cand;\n                for (int i = 0; i < (int)opts[m].size(); i++) {\n                    auto op = opts[m][i];\n                    int delta = max(0, op.req - (int)depth[op.chain]);\n                    int key = delta * 64 + op.req;\n                    if (key < bestKey) {\n                        bestKey = key;\n                        cand.clear();\n                        cand.push_back(i);\n                    } else if (key == bestKey) {\n                        cand.push_back(i);\n                    }\n                }\n                choose = cand[(int)(rng() % cand.size())];\n            }\n\n            auto op = opts[m][choose];\n            if (op.req > depth[op.chain]) depth[op.chain] = op.req;\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, true);\n        if ((rng() % 100) < 30) reduceDepth(s, true);\n        return s;\n    }\n\n    State trialCover(bool randomized) {\n        State s = makeZeroState();\n        greedyRepair(s, randomized);\n        if (s.unsatMask == 0) {\n            reduceDepth(s, true);\n            if (randomized && (rng() % 100) < 30) reduceDepth(s, true);\n        }\n        return s;\n    }\n\n    int pickNonZeroChain(const State& s) {\n        for (int t = 0; t < 24; t++) {\n            int c = (int)(rng() % Cn);\n            if (s.d[c] > 0) return c;\n        }\n        int cnt = 0;\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) cnt++;\n        if (cnt == 0) return -1;\n        int k = (int)(rng() % cnt);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) if (k-- == 0) return c;\n        return -1;\n    }\n\n    vector<pair<char,int>> buildOps(const State& s, bool optimized) const {\n        vector<uint8_t> unpair(Cn, 0);\n\n        if (optimized) {\n            int rs = rowSave(s), cs = colSave(s);\n            bool useRow = (rs >= cs);\n\n            if (useRow) {\n                for (int i = 0; i < N; i++) {\n                    int lc = idLeft(i), rc = idRight(i);\n                    int l = s.d[lc], r = s.d[rc];\n                    if (l > 0 && r > 0) {\n                        if (l >= r) unpair[lc] = 1;\n                        else unpair[rc] = 1;\n                    } else if (l > 0) unpair[lc] = 1;\n                    else if (r > 0) unpair[rc] = 1;\n                }\n            } else {\n                for (int j = 0; j < N; j++) {\n                    int uc = idUp(j), dc = idDown(j);\n                    int u = s.d[uc], d = s.d[dc];\n                    if (u > 0 && d > 0) {\n                        if (u >= d) unpair[uc] = 1;\n                        else unpair[dc] = 1;\n                    } else if (u > 0) unpair[uc] = 1;\n                    else if (d > 0) unpair[dc] = 1;\n                }\n            }\n        }\n\n        vector<pair<char,int>> ops;\n        ops.reserve(1600);\n\n        for (int c = 0; c < Cn; c++) {\n            int k = s.d[c];\n            if (k == 0) continue;\n            if (optimized && unpair[c]) continue;\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].rev, chains[c].idx});\n        }\n        if (optimized) {\n            for (int c = 0; c < Cn; c++) {\n                int k = s.d[c];\n                if (k == 0 || !unpair[c]) continue;\n                for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n            }\n        }\n        return ops;\n    }\n\n    static void applyOne(vector<string>& g, char d, int p) {\n        int N = (int)g.size();\n        if (d == 'L') {\n            for (int j = 0; j + 1 < N; j++) g[p][j] = g[p][j + 1];\n            g[p][N - 1] = '.';\n        } else if (d == 'R') {\n            for (int j = N - 1; j >= 1; j--) g[p][j] = g[p][j - 1];\n            g[p][0] = '.';\n        } else if (d == 'U') {\n            for (int i = 0; i + 1 < N; i++) g[i][p] = g[i + 1][p];\n            g[N - 1][p] = '.';\n        } else { // D\n            for (int i = N - 1; i >= 1; i--) g[i][p] = g[i - 1][p];\n            g[0][p] = '.';\n        }\n    }\n\n    pair<int,int> evaluateOps(const vector<pair<char,int>>& ops) const {\n        vector<string> g = board;\n        for (auto [d, p] : ops) applyOne(g, d, p);\n\n        int xRem = 0, oCnt = 0;\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            if (g[i][j] == 'x') xRem++;\n            else if (g[i][j] == 'o') oCnt++;\n        }\n        int yRem = initialFuku - oCnt;\n        return {xRem, yRem};\n    }\n\n    bool goodOps(const vector<pair<char,int>>& ops) const {\n        if ((int)ops.size() > 4 * N * N) return false;\n        auto [x, y] = evaluateOps(ops);\n        return (x == 0 && y == 0);\n    }\n\n    vector<pair<char,int>> fallbackPerOniOps() const {\n        vector<pair<char,int>> ops;\n        ops.reserve(1600);\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            const auto& ch = chains[op.chain];\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.dir, ch.idx});\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.rev, ch.idx});\n        }\n        return ops;\n    }\n\n    vector<pair<char,int>> solve() {\n        using Clock = chrono::steady_clock;\n        auto ts = Clock::now();\n        auto elapsed = [&]() -> double {\n            return chrono::duration<double>(Clock::now() - ts).count();\n        };\n\n        const double TL = 1.78;\n\n        State best = baselineMinReq();\n        State c0 = trialCover(false);\n        int bestObj = estimateMoves(best);\n        if (c0.unsatMask == 0) {\n            int c0Obj = estimateMoves(c0);\n            if (c0Obj < bestObj || (c0Obj == bestObj && c0.cost < best.cost)) {\n                best = c0;\n                bestObj = c0Obj;\n            }\n        }\n\n        int itInit = 0;\n        while (elapsed() < 0.30) {\n            State cand = (itInit % 2 == 0 ? trialAssign() : trialCover(true));\n            itInit++;\n            if (cand.unsatMask) continue;\n            int obj = estimateMoves(cand);\n            if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = obj;\n            }\n        }\n\n        State cur = best;\n        int curObj = bestObj;\n        int iter = 0;\n        const double lsEnd = TL - 0.10;\n\n        while (true) {\n            if ((iter & 127) == 0) {\n                if (elapsed() >= lsEnd) break;\n            }\n            iter++;\n\n            State cand = cur;\n\n            int k = 1 + (int)(rng() % 4);\n            if ((rng() % 100) < 20) k++;\n\n            for (int t = 0; t < k; t++) {\n                int c = pickNonZeroChain(cand);\n                if (c < 0) break;\n                int old = cand.d[c];\n                int nd;\n                int r = (int)(rng() % 100);\n                if (r < 55) {\n                    nd = old - 1;\n                } else if (r < 85) {\n                    int dec = 1 + (int)(rng() % max(1, min(4, old)));\n                    nd = max(0, old - dec);\n                } else {\n                    nd = (int)(rng() % (old + 1));\n                }\n                setChain(cand, c, nd);\n            }\n\n            if ((rng() % 100) < 10) {\n                int c = (int)(rng() % Cn);\n                if ((int)cand.d[c] < cap[c] && cap[c] > 0) {\n                    int nd = min(cap[c], (int)cand.d[c] + 1 + (int)(rng() % 3));\n                    setChain(cand, c, nd);\n                }\n            }\n\n            greedyRepair(cand, true);\n            if (cand.unsatMask) continue;\n\n            reduceDepth(cand, true);\n            if ((rng() % 100) < 35) reduceDepth(cand, true);\n\n            int candObj = estimateMoves(cand);\n\n            double prog = min(1.0, elapsed() / lsEnd);\n            double temp = 5.0 * pow(0.03 / 5.0, prog);\n            int delta = candObj - curObj;\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-delta / temp);\n                double u = (double)((rng() >> 8) & ((1u << 24) - 1)) / (double)(1u << 24);\n                if (u < prob) accept = true;\n            }\n\n            if (accept) {\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if (candObj < bestObj || (candObj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = candObj;\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if ((iter % 300) == 0 && (rng() % 100) < 40) {\n                cur = best;\n                curObj = bestObj;\n            }\n        }\n\n        vector<int> ord(Cn);\n        iota(ord.begin(), ord.end(), 0);\n        auto sortOrd = [&]() {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return best.d[a] > best.d[b];\n            });\n        };\n        sortOrd();\n\n        bool improved = true;\n        while (improved && elapsed() < TL - 0.02) {\n            improved = false;\n            for (int c : ord) {\n                if (elapsed() >= TL - 0.02) break;\n                if (best.d[c] == 0) continue;\n                State cand = best;\n                setChain(cand, c, 0);\n                greedyRepair(cand, false);\n                if (cand.unsatMask) continue;\n                reduceDepth(cand, true);\n                int obj = estimateMoves(cand);\n                if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                    best = cand;\n                    bestObj = obj;\n                    improved = true;\n                    sortOrd();\n                    break;\n                }\n            }\n        }\n\n        vector<pair<char,int>> ans = buildOps(best, true);\n        bool ok = goodOps(ans);\n\n        if (!ok) {\n            vector<pair<char,int>> paired = buildOps(best, false);\n            if (goodOps(paired)) {\n                ans.swap(paired);\n                ok = true;\n            }\n        }\n        if (!ok) {\n            vector<pair<char,int>> fb = fallbackPerOniOps();\n            if (goodOps(fb)) {\n                ans.swap(fb);\n                ok = true;\n            }\n        }\n        if (!ok) {\n            ans = buildOps(best, false); // last resort\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    Solver solver(N, C);\n    auto ops = solver.solve();\n\n    for (auto [d, p] : ops) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\nstatic inline long long absl(long long x) { return x < 0 ? -x : x; }\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\ntemplate <size_t SZ>\nint sample_weighted(const array<uint64_t, SZ>& w, int n, RNG& rng) {\n    uint64_t sum = 0;\n    for (int i = 0; i < n; i++) sum += w[i];\n    if (sum == 0) return rng.nextInt(n);\n    uint64_t r = rng.nextU64() % sum;\n    uint64_t acc = 0;\n    for (int i = 0; i < n; i++) {\n        acc += w[i];\n        if (r < acc) return i;\n    }\n    return n - 1;\n}\n\nstruct State {\n    array<int, MAXN> a{}, b{};\n    array<int, MAXN> cnt{}, useA{}, useB{};\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstatic inline int get_edge(const array<int, MAXN>& a, const array<int, MAXN>& b, int e) {\n    int i = e >> 1;\n    return (e & 1) ? b[i] : a[i];\n}\nstatic inline void set_edge(array<int, MAXN>& a, array<int, MAXN>& b, int e, int dst) {\n    int i = e >> 1;\n    if (e & 1) b[i] = dst;\n    else a[i] = dst;\n}\n\nlong long simulate(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N, int L,\n    const array<int, MAXN>& T,\n    array<int, MAXN>& cnt,\n    array<int, MAXN>& useA,\n    array<int, MAXN>& useB,\n    int& last\n) {\n    for (int i = 0; i < N; i++) cnt[i] = 0;\n    int cur = 0;\n    cnt[0] = 1; // week 1\n\n    for (int step = 1; step < L; step++) {\n        int s = cur;\n        if (cnt[s] & 1) cur = a[s];\n        else cur = b[s];\n        cnt[cur]++;\n    }\n    last = cur;\n\n    // Derive branch usages from counts + last node\n    for (int i = 0; i < N; i++) {\n        int dep = cnt[i] - (i == last ? 1 : 0);\n        if (dep < 0) dep = 0;\n        useA[i] = (dep + 1) >> 1;\n        useB[i] = dep >> 1;\n    }\n\n    long long e = 0;\n    for (int i = 0; i < N; i++) e += absl((long long)cnt[i] - T[i]);\n    return e;\n}\n\nvoid compute_reach(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N,\n    array<char, MAXN>& fwd,\n    array<char, MAXN>& rev\n) {\n    for (int i = 0; i < N; i++) {\n        fwd[i] = 0;\n        rev[i] = 0;\n    }\n\n    int st[MAXN];\n    int sp = 0;\n    st[sp++] = 0;\n    fwd[0] = 1;\n    while (sp) {\n        int v = st[--sp];\n        int x = a[v];\n        int y = b[v];\n        if (!fwd[x]) { fwd[x] = 1; st[sp++] = x; }\n        if (!fwd[y]) { fwd[y] = 1; st[sp++] = y; }\n    }\n\n    sp = 0;\n    st[sp++] = 0;\n    rev[0] = 1;\n    while (sp) {\n        int v = st[--sp];\n        for (int u = 0; u < N; u++) {\n            if (!rev[u] && (a[u] == v || b[u] == v)) {\n                rev[u] = 1;\n                st[sp++] = u;\n            }\n        }\n    }\n}\n\nbool strong_connected(const array<int, MAXN>& a, const array<int, MAXN>& b, int N) {\n    array<char, MAXN> fwd{}, rev{};\n    compute_reach(a, b, N, fwd, rev);\n    for (int i = 0; i < N; i++) {\n        if (!fwd[i] || !rev[i]) return false;\n    }\n    return true;\n}\n\nvoid recompute_rem(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N,\n    const array<int, MAXN>& T,\n    array<long long, MAXN>& rem\n) {\n    for (int i = 0; i < N; i++) rem[i] = 2LL * T[i];\n    for (int i = 0; i < N; i++) rem[a[i]] -= T[i];\n    for (int i = 0; i < N; i++) rem[b[i]] -= T[i];\n}\n\nvoid local_improve_edges(\n    array<int, MAXN>& a,\n    array<int, MAXN>& b,\n    const vector<int>& edges,\n    array<long long, MAXN>& rem,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    int passes\n) {\n    vector<int> ord = edges;\n    for (int pass = 0; pass < passes; pass++) {\n        bool improved = false;\n        for (int i = (int)ord.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        for (int e : ord) {\n            int src = e >> 1;\n            long long w = T[src];\n            int cur = get_edge(a, b, e);\n\n            int best = cur;\n            long long bestDelta = 0;\n            long long absCur = absl(rem[cur]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == cur) continue;\n                long long delta =\n                    absl(rem[cur] + w) + absl(rem[d] - w) - absCur - absl(rem[d]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = d;\n                }\n            }\n\n            if (best != cur) {\n                rem[cur] += w;\n                rem[best] -= w;\n                set_edge(a, b, e, best);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid build_cycle_candidate(\n    const array<int, MAXN>& order,\n    int N,\n    const array<int, MAXN>& T,\n    const array<int, MAXN>& srcDesc,\n    RNG& rng,\n    array<int, MAXN>& a,\n    array<int, MAXN>& b\n) {\n    array<int, MAXN> pred{};\n    for (int k = 0; k < N; k++) {\n        int u = order[k];\n        int v = order[(k + 1) % N];\n        a[u] = v;\n        pred[v] = u;\n    }\n\n    array<long long, MAXN> rem{};\n    for (int i = 0; i < N; i++) rem[i] = 2LL * T[i] - T[pred[i]];\n\n    for (int idx = 0; idx < N; idx++) {\n        int src = srcDesc[idx];\n        long long w = T[src];\n\n        int best = 0, second = 0;\n        long long bestVal = absl(rem[0] - w), secondVal = (1LL << 60);\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] - w);\n            if (v < bestVal) {\n                second = best;\n                secondVal = bestVal;\n                best = d;\n                bestVal = v;\n            } else if (v < secondVal) {\n                second = d;\n                secondVal = v;\n            }\n        }\n\n        int dst = best;\n        if (second != best && rng.nextDouble() < 0.10) dst = second;\n\n        b[src] = dst;\n        rem[dst] -= w;\n    }\n\n    vector<int> bedges;\n    bedges.reserve(N);\n    for (int i = 0; i < N; i++) bedges.push_back(2 * i + 1);\n    local_improve_edges(a, b, bedges, rem, N, T, rng, 6);\n}\n\nvoid build_free_candidate(\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& a,\n    array<int, MAXN>& b\n) {\n    array<long long, MAXN> rem{};\n    for (int i = 0; i < N; i++) rem[i] = 2LL * T[i];\n\n    vector<int> edges(2 * N);\n    iota(edges.begin(), edges.end(), 0);\n    sort(edges.begin(), edges.end(), [&](int e1, int e2) {\n        int s1 = e1 >> 1, s2 = e2 >> 1;\n        if (T[s1] != T[s2]) return T[s1] > T[s2];\n        return e1 < e2;\n    });\n\n    for (int t = 0; t < 20; t++) {\n        int i = rng.nextInt(2 * N);\n        int j = rng.nextInt(2 * N);\n        swap(edges[i], edges[j]);\n    }\n\n    for (int e : edges) {\n        int src = e >> 1;\n        long long w = T[src];\n\n        int best = 0, second = 0;\n        long long bestVal = absl(rem[0] - w), secondVal = (1LL << 60);\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] - w);\n            if (v < bestVal) {\n                second = best;\n                secondVal = bestVal;\n                best = d;\n                bestVal = v;\n            } else if (v < secondVal) {\n                second = d;\n                secondVal = v;\n            }\n        }\n\n        int dst = best;\n        if (rng.nextDouble() < 0.12) dst = second;\n\n        set_edge(a, b, e, dst);\n        rem[dst] -= w;\n    }\n\n    vector<int> allEdges(2 * N);\n    iota(allEdges.begin(), allEdges.end(), 0);\n    local_improve_edges(a, b, allEdges, rem, N, T, rng, 6);\n\n    auto apply_change = [&](int e, int nd) -> bool {\n        int od = get_edge(a, b, e);\n        if (od == nd) return false;\n        long long w = T[e >> 1];\n        rem[od] += w;\n        rem[nd] -= w;\n        set_edge(a, b, e, nd);\n        return true;\n    };\n\n    array<char, MAXN> fwd{}, rev{};\n    for (int it = 0; it < 80; it++) {\n        compute_reach(a, b, N, fwd, rev);\n        bool ok = true;\n        for (int i = 0; i < N; i++) {\n            if (!fwd[i] || !rev[i]) { ok = false; break; }\n        }\n        if (ok) break;\n\n        bool changed = false;\n\n        int target = -1;\n        for (int i = 0; i < N; i++) {\n            if (!fwd[i]) {\n                if (target == -1 || T[i] > T[target]) target = i;\n            }\n        }\n        if (target != -1) {\n            long long bestScore = (1LL << 62);\n            int bestE = -1;\n            for (int src = 0; src < N; src++) if (fwd[src]) {\n                for (int tp = 0; tp < 2; tp++) {\n                    int e = 2 * src + tp;\n                    int od = get_edge(a, b, e);\n                    if (od == target) continue;\n                    long long w = T[src];\n                    long long delta =\n                        absl(rem[od] + w) + absl(rem[target] - w) - absl(rem[od]) - absl(rem[target]);\n                    long long score = delta * 1024 + w;\n                    if (score < bestScore) {\n                        bestScore = score;\n                        bestE = e;\n                    }\n                }\n            }\n            if (bestE != -1) {\n                apply_change(bestE, target);\n                changed = true;\n            }\n        } else {\n            int src = -1;\n            for (int i = 0; i < N; i++) {\n                if (!rev[i]) {\n                    if (src == -1 || T[i] > T[src]) src = i;\n                }\n            }\n            if (src != -1) {\n                long long bestScore = (1LL << 62);\n                int bestE = -1, bestD = -1;\n                for (int tp = 0; tp < 2; tp++) {\n                    int e = 2 * src + tp;\n                    int od = get_edge(a, b, e);\n                    long long w = T[src];\n                    for (int d = 0; d < N; d++) if (rev[d]) {\n                        if (d == od) continue;\n                        long long delta =\n                            absl(rem[od] + w) + absl(rem[d] - w) - absl(rem[od]) - absl(rem[d]);\n                        long long score = delta * 1024 + (d == 0 ? 0 : 1);\n                        if (score < bestScore) {\n                            bestScore = score;\n                            bestE = e;\n                            bestD = d;\n                        }\n                    }\n                }\n                if (bestE != -1) {\n                    apply_change(bestE, bestD);\n                    changed = true;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n\n    if (!strong_connected(a, b, N)) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int x, int y) {\n            if (T[x] != T[y]) return T[x] < T[y];\n            return x < y;\n        });\n        if (rng.nextDouble() < 0.5) reverse(ord.begin(), ord.end());\n        int sw = rng.nextInt(8);\n        for (int s = 0; s < sw; s++) {\n            int i = rng.nextInt(N);\n            int j = rng.nextInt(N);\n            swap(ord[i], ord[j]);\n        }\n        for (int k = 0; k < N; k++) {\n            int u = ord[k];\n            int v = ord[(k + 1) % N];\n            a[u] = v;\n        }\n\n        recompute_rem(a, b, N, T, rem);\n        vector<int> bedges;\n        bedges.reserve(N);\n        for (int i = 0; i < N; i++) bedges.push_back(2 * i + 1);\n        local_improve_edges(a, b, bedges, rem, N, T, rng, 5);\n    }\n}\n\nvoid shuffle_order(array<int, MAXN>& ord, int N, RNG& rng) {\n    for (int i = N - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    array<int, MAXN> T{};\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    for (int i = 0; i < N; i++) {\n        seed ^= (uint64_t)(T[i] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));\n    }\n    RNG rng(seed);\n\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    const double TIME_LIMIT = 1.92;\n    const double INIT_LIMIT = 0.50;\n\n    // Orders\n    array<int, MAXN> ordNatural{}, ordAsc{}, ordDesc{}, ordMountain{}, ordMountainRev{};\n    for (int i = 0; i < N; i++) ordNatural[i] = i;\n\n    vector<int> idx(N);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        if (T[x] != T[y]) return T[x] < T[y];\n        return x < y;\n    });\n    for (int i = 0; i < N; i++) ordAsc[i] = idx[i];\n    for (int i = 0; i < N; i++) ordDesc[i] = idx[N - 1 - i];\n\n    {\n        int p = 0, l = 0, r = N - 1;\n        while (l <= r) {\n            ordMountain[p++] = ordAsc[l++];\n            if (l <= r) ordMountain[p++] = ordAsc[r--];\n        }\n    }\n    for (int i = 0; i < N; i++) ordMountainRev[i] = ordMountain[N - 1 - i];\n\n    array<int, MAXN> srcDesc = ordDesc;\n\n    State best;\n    vector<State> pool;\n    pool.reserve(6);\n\n    auto add_pool = [&](const State& s) {\n        pool.push_back(s);\n        sort(pool.begin(), pool.end(), [](const State& x, const State& y) {\n            return x.err < y.err;\n        });\n        if ((int)pool.size() > 4) pool.resize(4);\n    };\n\n    auto eval_candidate = [&](const array<int, MAXN>& a, const array<int, MAXN>& b) -> long long {\n        State s;\n        s.a = a;\n        s.b = b;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) best = s;\n        add_pool(s);\n        return s.err;\n    };\n\n    array<int, MAXN> candA{}, candB{};\n    long long bestCycleErr = (1LL << 60);\n    array<int, MAXN> bestOrder = ordAsc;\n\n    auto eval_cycle_order = [&](const array<int, MAXN>& ord) {\n        build_cycle_candidate(ord, N, T, srcDesc, rng, candA, candB);\n        long long e = eval_candidate(candA, candB);\n        if (e < bestCycleErr) {\n            bestCycleErr = e;\n            bestOrder = ord;\n        }\n    };\n\n    // Deterministic candidates\n    eval_cycle_order(ordNatural);\n    eval_cycle_order(ordAsc);\n    eval_cycle_order(ordDesc);\n    eval_cycle_order(ordMountain);\n    eval_cycle_order(ordMountainRev);\n\n    build_free_candidate(N, T, rng, candA, candB);\n    eval_candidate(candA, candB);\n\n    // Init randomized search\n    while (elapsed() < INIT_LIMIT) {\n        if (rng.nextDouble() < 0.65) {\n            array<int, MAXN> ord{};\n            int mode = rng.nextInt(7);\n            if (mode == 0) ord = ordAsc;\n            else if (mode == 1) ord = ordDesc;\n            else if (mode == 2) ord = ordMountain;\n            else if (mode == 3) ord = ordMountainRev;\n            else if (mode == 4) ord = ordNatural;\n            else if (mode == 5) ord = bestOrder;\n            else {\n                ord = ordNatural;\n                shuffle_order(ord, N, rng);\n            }\n\n            int swaps = 1 + rng.nextInt(24);\n            for (int s = 0; s < swaps; s++) {\n                int i = rng.nextInt(N);\n                int j = rng.nextInt(N);\n                swap(ord[i], ord[j]);\n            }\n            if (rng.nextDouble() < 0.22) {\n                int l = rng.nextInt(N), r = rng.nextInt(N);\n                if (l > r) swap(l, r);\n                reverse(ord.begin() + l, ord.begin() + r + 1);\n            }\n\n            build_cycle_candidate(ord, N, T, srcDesc, rng, candA, candB);\n            long long e = eval_candidate(candA, candB);\n            if (e < bestCycleErr) {\n                bestCycleErr = e;\n                bestOrder = ord;\n            }\n        } else {\n            build_free_candidate(N, T, rng, candA, candB);\n            eval_candidate(candA, candB);\n        }\n    }\n\n    if (pool.empty()) pool.push_back(best);\n\n    State cur = best;\n    array<int, MAXN> tmpCnt{}, tmpUseA{}, tmpUseB{};\n    int tmpLast = 0;\n\n    array<uint64_t, 2 * MAXN> wEdge{}, wEdge2{};\n    array<uint64_t, MAXN> wDst{};\n\n    double saStart = elapsed();\n    double saSpan = max(1e-9, TIME_LIMIT - saStart);\n    long long iter = 0;\n\n    while (elapsed() < TIME_LIMIT) {\n        iter++;\n        double now = elapsed();\n        double prog = (now - saStart) / saSpan;\n        if (prog < 0.0) prog = 0.0;\n        if (prog > 1.0) prog = 1.0;\n        double temp = 2200.0 * (1.0 - prog) + 4.0;\n\n        int moveType;\n        double r = rng.nextDouble();\n        if (r < 0.62) moveType = 0;      // guided single-edge move\n        else if (r < 0.84) moveType = 1; // random single-edge move\n        else moveType = 2;               // swap two edges\n\n        bool applied = false;\n        int e = -1, oldDst = -1, newDst = -1;\n        int e1 = -1, e2 = -1, old1 = -1, old2 = -1;\n\n        if (moveType == 0) {\n            for (int i = 0; i < N; i++) {\n                int da = cur.a[i], db = cur.b[i];\n                int overA = cur.cnt[da] - T[da];\n                int overB = cur.cnt[db] - T[db];\n                if (overA < 0) overA = 0;\n                if (overB < 0) overB = 0;\n                wEdge[2 * i] = (uint64_t)(cur.useA[i] + 1) * (uint64_t)(overA + 1);\n                wEdge[2 * i + 1] = (uint64_t)(cur.useB[i] + 1) * (uint64_t)(overB + 1);\n            }\n            e = sample_weighted(wEdge, 2 * N, rng);\n\n            int src = e >> 1;\n            int used = (e & 1) ? cur.useB[src] : cur.useA[src];\n            oldDst = (e & 1) ? cur.b[src] : cur.a[src];\n\n            if (used == 0 && rng.nextDouble() < 0.8) continue;\n\n            long long bestPred = (1LL << 60);\n            newDst = oldDst;\n            long long baseOld = absl((long long)cur.cnt[oldDst] - T[oldDst]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == oldDst) continue;\n                long long pred =\n                    absl((long long)cur.cnt[oldDst] - used - T[oldDst]) +\n                    absl((long long)cur.cnt[d] + used - T[d]) -\n                    baseOld -\n                    absl((long long)cur.cnt[d] - T[d]);\n                if (pred < bestPred) {\n                    bestPred = pred;\n                    newDst = d;\n                }\n            }\n\n            if (newDst == oldDst) continue;\n            if (bestPred >= 0 && rng.nextDouble() < (0.55 + 0.25 * prog)) continue;\n\n            if (rng.nextDouble() < 0.12) {\n                for (int d = 0; d < N; d++) {\n                    int under = T[d] - cur.cnt[d];\n                    if (under < 0) under = 0;\n                    wDst[d] = (uint64_t)(under + 1);\n                }\n                int rnd = sample_weighted(wDst, N, rng);\n                if (rnd != oldDst) newDst = rnd;\n            }\n\n            if (e & 1) cur.b[src] = newDst;\n            else cur.a[src] = newDst;\n            applied = true;\n        } else if (moveType == 1) {\n            e = rng.nextInt(2 * N);\n            int src = e >> 1;\n            int used = (e & 1) ? cur.useB[src] : cur.useA[src];\n            oldDst = (e & 1) ? cur.b[src] : cur.a[src];\n\n            for (int d = 0; d < N; d++) {\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                wDst[d] = (uint64_t)(under + 1);\n            }\n            newDst = sample_weighted(wDst, N, rng);\n            if (newDst == oldDst) continue;\n\n            long long pred =\n                absl((long long)cur.cnt[oldDst] - used - T[oldDst]) +\n                absl((long long)cur.cnt[newDst] + used - T[newDst]) -\n                absl((long long)cur.cnt[oldDst] - T[oldDst]) -\n                absl((long long)cur.cnt[newDst] - T[newDst]);\n\n            if (pred > 0 && rng.nextDouble() < (0.45 + 0.25 * prog)) continue;\n\n            if (e & 1) cur.b[src] = newDst;\n            else cur.a[src] = newDst;\n            applied = true;\n        } else {\n            if (rng.nextDouble() < 0.70) {\n                for (int i = 0; i < N; i++) {\n                    int da = cur.a[i], db = cur.b[i];\n                    int overA = cur.cnt[da] - T[da];\n                    int overB = cur.cnt[db] - T[db];\n                    if (overA < 0) overA = 0;\n                    if (overB < 0) overB = 0;\n                    wEdge[2 * i] = (uint64_t)(cur.useA[i] + 1) * (uint64_t)(overA + 1);\n                    wEdge[2 * i + 1] = (uint64_t)(cur.useB[i] + 1) * (uint64_t)(overB + 1);\n\n                    int underA = T[da] - cur.cnt[da];\n                    int underB = T[db] - cur.cnt[db];\n                    if (underA < 0) underA = 0;\n                    if (underB < 0) underB = 0;\n                    wEdge2[2 * i] = (uint64_t)(cur.useA[i] + 1) * (uint64_t)(underA + 1);\n                    wEdge2[2 * i + 1] = (uint64_t)(cur.useB[i] + 1) * (uint64_t)(underB + 1);\n                }\n                e1 = sample_weighted(wEdge, 2 * N, rng);\n                e2 = sample_weighted(wEdge2, 2 * N, rng);\n                if (e1 == e2) continue;\n            } else {\n                e1 = rng.nextInt(2 * N);\n                e2 = rng.nextInt(2 * N - 1);\n                if (e2 >= e1) e2++;\n            }\n\n            old1 = get_edge(cur.a, cur.b, e1);\n            old2 = get_edge(cur.a, cur.b, e2);\n            if (old1 == old2) continue;\n\n            int s1 = e1 >> 1, s2 = e2 >> 1;\n            int u1 = (e1 & 1) ? cur.useB[s1] : cur.useA[s1];\n            int u2 = (e2 & 1) ? cur.useB[s2] : cur.useA[s2];\n\n            long long pred =\n                absl((long long)cur.cnt[old1] - u1 + u2 - T[old1]) +\n                absl((long long)cur.cnt[old2] - u2 + u1 - T[old2]) -\n                absl((long long)cur.cnt[old1] - T[old1]) -\n                absl((long long)cur.cnt[old2] - T[old2]);\n\n            if (pred > 0 && rng.nextDouble() < (0.50 + 0.25 * prog)) continue;\n\n            set_edge(cur.a, cur.b, e1, old2);\n            set_edge(cur.a, cur.b, e2, old1);\n            applied = true;\n        }\n\n        if (!applied) continue;\n\n        long long newErr = simulate(cur.a, cur.b, N, L, T, tmpCnt, tmpUseA, tmpUseB, tmpLast);\n\n        bool accept = false;\n        if (newErr <= cur.err) {\n            accept = true;\n        } else {\n            double prob = exp((double)(cur.err - newErr) / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.err = newErr;\n            cur.cnt = tmpCnt;\n            cur.useA = tmpUseA;\n            cur.useB = tmpUseB;\n            cur.last = tmpLast;\n\n            if (cur.err < best.err) {\n                best = cur;\n                add_pool(best);\n            }\n        } else {\n            if (moveType <= 1) {\n                int src = e >> 1;\n                if (e & 1) cur.b[src] = oldDst;\n                else cur.a[src] = oldDst;\n            } else {\n                set_edge(cur.a, cur.b, e1, old1);\n                set_edge(cur.a, cur.b, e2, old2);\n            }\n        }\n\n        if ((iter & 255LL) == 0) {\n            if (cur.err > best.err + 2500) {\n                if (!pool.empty() && rng.nextDouble() < 0.35) {\n                    cur = pool[rng.nextInt((int)pool.size())];\n                } else {\n                    cur = best;\n                }\n            }\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\nstruct Solver {\n    int N, M, Q, L, W;\n    vector<int> G;\n    vector<int> lx, rx, ly, ry;\n    vector<int> cx2, cy2, cx, cy;  // center*2 and center\n    vector<uint32_t> zkey;\n    vector<int> dflat; // NxN proxy distances on center*2\n    mt19937 rng;\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffffu;\n        x = (x | (x << 8)) & 0x00FF00FFu;\n        x = (x | (x << 4)) & 0x0F0F0F0Fu;\n        x = (x | (x << 2)) & 0x33333333u;\n        x = (x | (x << 1)) & 0x55555555u;\n        return x;\n    }\n    static uint32_t morton(uint32_t x, uint32_t y) {\n        return part1by1(x) | (part1by1(y) << 1);\n    }\n\n    inline int D(int a, int b) const {\n        return dflat[a * N + b];\n    }\n\n    void input() {\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        cx2.resize(N); cy2.resize(N);\n        cx.resize(N); cy.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            cx2[i] = lx[i] + rx[i];\n            cy2[i] = ly[i] + ry[i];\n            cx[i] = cx2[i] / 2;\n            cy[i] = cy2[i] / 2;\n        }\n    }\n\n    void init_rng() {\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 << 32 | (uint64_t)M);\n        mix((uint64_t)Q << 32 | (uint64_t)L);\n        mix((uint64_t)W);\n        for (int i = 0; i < N; i++) {\n            mix((uint64_t)(cx2[i] + 10007) * 1000003ull + (uint64_t)(cy2[i] + 10009));\n            mix((uint64_t)(rx[i] - lx[i] + 1) * 1000033ull + (uint64_t)(ry[i] - ly[i] + 7));\n        }\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    void preprocess() {\n        zkey.resize(N);\n        for (int i = 0; i < N; i++) {\n            zkey[i] = morton((uint32_t)cx[i], (uint32_t)cy[i]);\n        }\n\n        dflat.assign(N * N, 0);\n        for (int i = 0; i < N; i++) {\n            dflat[i * N + i] = 0;\n            for (int j = i + 1; j < N; j++) {\n                long long dx = (long long)cx2[i] - cx2[j];\n                long long dy = (long long)cy2[i] - cy2[j];\n                long long sq = dx * dx + dy * dy;\n                int d = (int)std::sqrt((double)sq); // proxy distance on doubled coordinates\n                dflat[i * N + j] = dflat[j * N + i] = d;\n            }\n        }\n    }\n\n    long long prim_cost(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return 0;\n\n        const int INF = 1e9;\n        int mn[800];\n        unsigned char used[800];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        long long cost = 0;\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            cost += mn[v];\n\n            int idv = nodes[v];\n            int base = idv * N;\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = dflat[base + nodes[u]];\n                if (w < mn[u]) mn[u] = w;\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> prim_tree(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            edges.push_back(p);\n            return edges;\n        }\n\n        const int INF = 1e9;\n        int mn[800], parent[800];\n        unsigned char used[800];\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            parent[i] = -1;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int idv = nodes[v];\n            int base = idv * N;\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = dflat[base + nodes[u]];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    parent[u] = v;\n                }\n            }\n        }\n\n        edges.reserve(n - 1);\n        for (int i = 1; i < n; i++) {\n            int a = nodes[i], b = nodes[parent[i]];\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        return edges;\n    }\n\n    bool validate_groups(const vector<vector<int>>& groups) const {\n        if ((int)groups.size() != M) return false;\n        vector<int> cnt(N, 0);\n        for (int i = 0; i < M; i++) {\n            if ((int)groups[i].size() != G[i]) return false;\n            for (int c : groups[i]) {\n                if (c < 0 || c >= N) return false;\n                cnt[c]++;\n            }\n        }\n        for (int i = 0; i < N; i++) if (cnt[i] != 1) return false;\n        return true;\n    }\n\n    long long eval_groups(const vector<vector<int>>& groups) const {\n        long long sum = 0;\n        for (int i = 0; i < M; i++) sum += prim_cost(groups[i]);\n        return sum;\n    }\n\n    vector<int> make_city_order(function<bool(int,int)> comp) const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), comp);\n        return ord;\n    }\n\n    vector<int> city_order_projection(double ang) const {\n        double ax = cos(ang), ay = sin(ang);\n        vector<double> key(N);\n        for (int i = 0; i < N; i++) key[i] = ax * cx2[i] + ay * cy2[i];\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            double da = key[a], db = key[b];\n            if (fabs(da - db) > 1e-12) return da < db;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<vector<int>> build_order_trial(const vector<int>& city_order, const vector<int>& group_order) const {\n        vector<vector<int>> out(M);\n        int pos = 0;\n        for (int gid : group_order) {\n            int sz = G[gid];\n            out[gid].assign(city_order.begin() + pos, city_order.begin() + pos + sz);\n            pos += sz;\n        }\n        return out;\n    }\n\n    void rec_assign(vector<int> cities, vector<int> gids, vector<vector<int>>& out, bool randomized) {\n        if ((int)gids.size() == 1) {\n            out[gids[0]] = std::move(cities);\n            return;\n        }\n        int S = (int)cities.size();\n\n        int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;\n        for (int c : cities) {\n            minx = min(minx, cx2[c]);\n            maxx = max(maxx, cx2[c]);\n            miny = min(miny, cy2[c]);\n            maxy = max(maxy, cy2[c]);\n        }\n        int axis = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 30) axis ^= 1;\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            if (axis == 0) {\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                return a < b;\n            } else {\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                return a < b;\n            }\n        });\n\n        vector<int> pg = gids;\n        if (randomized) shuffle(pg.begin(), pg.end(), rng);\n\n        vector<char> dp(S + 1, 0);\n        vector<int> prv(S + 1, -1), item(S + 1, -1);\n        dp[0] = 1;\n        for (int j = 0; j < (int)pg.size(); j++) {\n            int w = G[pg[j]];\n            for (int s = S - w; s >= 0; s--) {\n                if (dp[s] && !dp[s + w]) {\n                    dp[s + w] = 1;\n                    prv[s + w] = s;\n                    item[s + w] = j;\n                }\n            }\n        }\n\n        int target = S / 2;\n        if (randomized) {\n            int rad = max(1, S / 6);\n            target += uniform_int_distribution<int>(-rad, rad)(rng);\n            target = max(1, min(S - 1, target));\n        }\n\n        int bestDiff = INT_MAX;\n        vector<int> candS;\n        for (int s = 1; s <= S - 1; s++) {\n            if (!dp[s]) continue;\n            int diff = abs(s - target);\n            if (diff < bestDiff) {\n                bestDiff = diff;\n                candS.clear();\n                candS.push_back(s);\n            } else if (diff == bestDiff) {\n                candS.push_back(s);\n            }\n        }\n\n        int splitSize = -1;\n        if (!candS.empty()) {\n            splitSize = randomized\n                ? candS[uniform_int_distribution<int>(0, (int)candS.size() - 1)(rng)]\n                : candS[0];\n        }\n\n        vector<int> gA, gB;\n        bool ok = (splitSize > 0 && splitSize < S);\n        if (ok) {\n            vector<char> take(pg.size(), 0);\n            int cur = splitSize;\n            while (cur > 0) {\n                int j = item[cur];\n                if (j < 0 || take[j]) {\n                    ok = false;\n                    break;\n                }\n                take[j] = 1;\n                cur = prv[cur];\n            }\n            if (ok) {\n                int sumA = 0;\n                for (int j = 0; j < (int)pg.size(); j++) {\n                    if (take[j]) {\n                        gA.push_back(pg[j]);\n                        sumA += G[pg[j]];\n                    } else {\n                        gB.push_back(pg[j]);\n                    }\n                }\n                if (gA.empty() || gB.empty() || sumA != splitSize) ok = false;\n            }\n        }\n\n        if (!ok) {\n            gA.clear(); gB.clear();\n            gA.push_back(pg[0]);\n            splitSize = G[pg[0]];\n            for (int j = 1; j < (int)pg.size(); j++) gB.push_back(pg[j]);\n        }\n\n        vector<int> cA(cities.begin(), cities.begin() + splitSize);\n        vector<int> cB(cities.begin() + splitSize, cities.end());\n\n        rec_assign(std::move(cA), std::move(gA), out, randomized);\n        rec_assign(std::move(cB), std::move(gB), out, randomized);\n    }\n\n    vector<vector<int>> build_recursive_trial(bool randomized) {\n        vector<vector<int>> out(M);\n        vector<int> cities(N), gids(M);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        sort(gids.begin(), gids.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 20) {\n            shuffle(gids.begin(), gids.end(), rng);\n        }\n\n        rec_assign(std::move(cities), std::move(gids), out, randomized);\n        return out;\n    }\n\n    vector<vector<int>> make_grouping() {\n        vector<vector<int>> best;\n        long long bestScore = (1LL << 62);\n\n        auto consider = [&](vector<vector<int>> cand) {\n            if (!validate_groups(cand)) return;\n            long long sc = eval_groups(cand);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = std::move(cand);\n            }\n        };\n\n        vector<int> go_orig(M), go_desc(M), go_asc(M);\n        iota(go_orig.begin(), go_orig.end(), 0);\n        go_desc = go_orig;\n        go_asc = go_orig;\n        sort(go_desc.begin(), go_desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        sort(go_asc.begin(), go_asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        vector<vector<int>> groupOrders = {go_desc, go_asc, go_orig};\n\n        vector<vector<int>> cityOrders;\n        cityOrders.push_back(make_city_order([&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        }));\n        cityOrders.push_back(make_city_order([&](int a, int b) {\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        }));\n        cityOrders.push_back(make_city_order([&](int a, int b) {\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        }));\n        cityOrders.push_back(make_city_order([&](int a, int b) {\n            int ka = cx2[a] + cy2[a];\n            int kb = cx2[b] + cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        }));\n        cityOrders.push_back(make_city_order([&](int a, int b) {\n            int ka = cx2[a] - cy2[a];\n            int kb = cx2[b] - cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        }));\n\n        const double PI = acos(-1.0);\n        for (int t = 0; t < 8; t++) {\n            double ang = PI * (double)t / 8.0;\n            cityOrders.push_back(city_order_projection(ang + 0.173));\n        }\n        uniform_real_distribution<double> ud(0.0, PI);\n        for (int t = 0; t < 4; t++) {\n            cityOrders.push_back(city_order_projection(ud(rng)));\n        }\n\n        for (auto& ord : cityOrders) {\n            for (auto& go : groupOrders) {\n                consider(build_order_trial(ord, go));\n            }\n        }\n\n        consider(build_recursive_trial(false));\n        for (int t = 0; t < 12; t++) {\n            consider(build_recursive_trial(true));\n        }\n\n        if (best.empty()) {\n            best = build_order_trial(cityOrders[0], go_desc);\n        }\n        return best;\n    }\n\n    vector<vector<int>> build_knn(int K) const {\n        K = min(K, N - 1);\n        vector<vector<int>> near(N);\n        auto cmp = [](const pair<int,int>& a, const pair<int,int>& b) {\n            if (a.first != b.first) return a.first < b.first;\n            return a.second < b.second;\n        };\n\n        for (int i = 0; i < N; i++) {\n            vector<pair<int,int>> arr;\n            arr.reserve(N - 1);\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                if (i == j) continue;\n                arr.emplace_back(dflat[base + j], j);\n            }\n            if ((int)arr.size() > K) {\n                nth_element(arr.begin(), arr.begin() + K, arr.end(), cmp);\n                arr.resize(K);\n            }\n            sort(arr.begin(), arr.end(), cmp);\n\n            near[i].reserve((int)arr.size());\n            for (auto &p : arr) near[i].push_back(p.second);\n        }\n        return near;\n    }\n\n    void optimize_groups(vector<vector<int>>& groups, double sec_budget) {\n        using Clock = chrono::steady_clock;\n        auto deadline = Clock::now() + chrono::duration<double>(sec_budget);\n\n        vector<int> gid(N), pos(N);\n        for (int g = 0; g < M; g++) {\n            for (int i = 0; i < (int)groups[g].size(); i++) {\n                int c = groups[g][i];\n                gid[c] = g;\n                pos[c] = i;\n            }\n        }\n\n        vector<long long> gcost(M);\n        for (int g = 0; g < M; g++) gcost[g] = prim_cost(groups[g]);\n\n        auto near = build_knn(24);\n\n        long long opBudget = 15000000;\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        auto try_swap = [&](int u, int v) -> bool {\n            int gu = gid[u], gv = gid[v];\n            if (gu == gv) return false;\n\n            int sa = (int)groups[gu].size();\n            int sb = (int)groups[gv].size();\n            long long est = 1LL * sa * sa + 1LL * sb * sb;\n            if (est > opBudget) return false;\n            opBudget -= est;\n\n            int pu = pos[u], pv = pos[v];\n            auto &A = groups[gu];\n            auto &B = groups[gv];\n\n            swap(A[pu], B[pv]);\n            long long newA = prim_cost(A);\n            long long newB = prim_cost(B);\n\n            if (newA + newB < gcost[gu] + gcost[gv]) {\n                gid[u] = gv; gid[v] = gu;\n                pos[u] = pv; pos[v] = pu;\n                gcost[gu] = newA;\n                gcost[gv] = newB;\n                return true;\n            } else {\n                swap(A[pu], B[pv]);\n                return false;\n            }\n        };\n\n        for (int pass = 0; pass < 30; pass++) {\n            if (Clock::now() >= deadline || opBudget <= 0) break;\n\n            bool improved = false;\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int it = 0; it < N; it++) {\n                if ((it & 31) == 0) {\n                    if (Clock::now() >= deadline || opBudget <= 0) break;\n                }\n                int u = order[it];\n                bool moved = false;\n\n                for (int v : near[u]) {\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        moved = true;\n                        break;\n                    }\n                }\n                if (moved) continue;\n\n                for (int t = 0; t < 2; t++) {\n                    int v = uid(rng);\n                    if (v == u) continue;\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        moved = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        cout << \"? \" << subset.size();\n        for (int c : subset) cout << \" \" << c;\n        cout << \"\\n\";\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)subset.size() - 1);\n        for (int i = 0; i < (int)subset.size() - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            ret.emplace_back(a, b);\n        }\n        return ret;\n    }\n\n    int query_need_for_group(int g) const {\n        if (g <= 2) return 0;\n        return (g - 2) / (L - 1) + 1; // ceil((g-1)/(L-1))\n    }\n\n    int choose_medoid_index(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        int bestIdx = 0;\n        long long bestSum = (1LL << 62);\n\n        for (int i = 0; i < n; i++) {\n            long long s = 0;\n            int a = nodes[i];\n            int base = a * N;\n            for (int j = 0; j < n; j++) {\n                s += dflat[base + nodes[j]];\n                if (s >= bestSum) break;\n            }\n            if (s < bestSum) {\n                bestSum = s;\n                bestIdx = i;\n            }\n        }\n        return bestIdx;\n    }\n\n    vector<pair<int,int>> build_edges_for_group(const vector<int>& nodes, int& q_used) {\n        int g = (int)nodes.size();\n        if (g <= 1) return {};\n        if (g == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            return {p};\n        }\n\n        int need = query_need_for_group(g);\n        if (q_used + need > Q) {\n            return prim_tree(nodes);\n        }\n\n        vector<int> ord = nodes;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        if (g <= L) {\n            auto ret = do_query(ord);\n            q_used++;\n            return ret;\n        }\n\n        vector<pair<int,int>> edges;\n        edges.reserve(g - 1);\n\n        int root = choose_medoid_index(ord);\n\n        vector<char> connected(g, 0);\n        vector<int> nearestDist(g, 1e9), nearestAnchor(g, -1);\n\n        connected[root] = 1;\n        int rem = g - 1;\n        for (int i = 0; i < g; i++) if (i != root) {\n            nearestDist[i] = D(ord[root], ord[i]);\n            nearestAnchor[i] = root;\n        }\n\n        while (rem > 0) {\n            int u = -1, best = 1e9;\n            for (int i = 0; i < g; i++) {\n                if (!connected[i] && nearestDist[i] < best) {\n                    best = nearestDist[i];\n                    u = i;\n                }\n            }\n            if (u == -1) break;\n\n            int anchor = nearestAnchor[u];\n            if (anchor < 0) anchor = root;\n\n            int addCount = min(L - 1, rem);\n            vector<int> add;\n            add.reserve(addCount);\n            add.push_back(u);\n\n            int extra = addCount - 1;\n            if (extra > 0) {\n                priority_queue<pair<int,int>> pq; // (dist, idx), max-heap\n                for (int i = 0; i < g; i++) {\n                    if (connected[i] || i == u) continue;\n                    int d = D(ord[anchor], ord[i]);\n                    if ((int)pq.size() < extra) {\n                        pq.push({d, i});\n                    } else if (d < pq.top().first || (d == pq.top().first && i < pq.top().second)) {\n                        pq.pop();\n                        pq.push({d, i});\n                    }\n                }\n                vector<pair<int,int>> tmp;\n                while (!pq.empty()) {\n                    tmp.push_back(pq.top());\n                    pq.pop();\n                }\n                sort(tmp.begin(), tmp.end(), [&](auto &a, auto &b) {\n                    if (a.first != b.first) return a.first < b.first;\n                    return a.second < b.second;\n                });\n                for (auto &p : tmp) add.push_back(p.second);\n            }\n\n            vector<int> subset;\n            subset.reserve(1 + (int)add.size());\n            subset.push_back(ord[anchor]);\n            for (int idx : add) subset.push_back(ord[idx]);\n\n            auto ret = do_query(subset);\n            q_used++;\n            edges.insert(edges.end(), ret.begin(), ret.end());\n\n            for (int idx : add) {\n                if (!connected[idx]) {\n                    connected[idx] = 1;\n                    rem--;\n                }\n            }\n\n            for (int i = 0; i < g; i++) {\n                if (connected[i]) continue;\n                for (int idx : add) {\n                    int d = D(ord[i], ord[idx]);\n                    if (d < nearestDist[i]) {\n                        nearestDist[i] = d;\n                        nearestAnchor[i] = idx;\n                    }\n                }\n            }\n        }\n\n        if ((int)edges.size() != g - 1) {\n            return prim_tree(nodes);\n        }\n        return edges;\n    }\n\n    void solve() {\n        input();\n        preprocess();\n        init_rng();\n\n        auto groups = make_grouping();\n        if (!validate_groups(groups)) {\n            vector<int> ord(N), go(M);\n            iota(ord.begin(), ord.end(), 0);\n            iota(go.begin(), go.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                return a < b;\n            });\n            groups = build_order_trial(ord, go);\n        }\n\n        auto base_groups = groups;\n        optimize_groups(groups, 0.90);\n        if (!validate_groups(groups)) {\n            groups = base_groups;\n        }\n\n        vector<vector<pair<int,int>>> edges(M);\n        vector<int> gid_order(M);\n        iota(gid_order.begin(), gid_order.end(), 0);\n        sort(gid_order.begin(), gid_order.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        int q_used = 0;\n        for (int gid : gid_order) {\n            edges[gid] = build_edges_for_group(groups[gid], q_used);\n        }\n\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            if ((int)edges[k].size() != (int)groups[k].size() - 1) {\n                edges[k] = prim_tree(groups[k]);\n            }\n\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n\n            for (auto [a, b] : edges[k]) {\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\nstruct Action {\n    char a, d;\n};\n\nclass Solver {\n    static constexpr int MAXN = 20;\n    static constexpr int INF = 1e9;\n\n    int N, M, LIMIT, n2;\n    vector<Point> pts;           // pts[0] = start, pts[1..] = targets\n    vector<int> pid;             // cell id of pts[i]\n    vector<int> cellR, cellC;    // id -> r,c\n    vector<array<int,4>> to;     // neighbors\n    vector<int> targetIdxAtCell; // cell id -> index in pts, or -1\n\n    array<uint32_t, MAXN> lowMask{}, highMask{};\n\n    const array<int,4> DR{{-1, 1, 0, 0}};\n    const array<int,4> DC{{0, 0, -1, 1}};\n    const array<char,4> DCH{{'U','D','L','R'}};\n\n    struct Node {\n        array<uint32_t, MAXN> row{}, col{};\n        int cost = INF;\n        int parent = -1;      // index in previous layer\n        uint8_t op = 0;       // 0:none, 1:A(d1), 2:M(d1)+A(d2)\n        uint8_t d1 = 0, d2 = 0;\n        uint16_t bcnt = 0;\n        int eval = 0;\n    };\n\n    inline bool isBlocked(const array<uint32_t,MAXN>& row, int id) const {\n        return (row[cellR[id]] >> cellC[id]) & 1u;\n    }\n\n    inline void toggleCell(array<uint32_t,MAXN>& row, array<uint32_t,MAXN>& col, int id) const {\n        int r = cellR[id], c = cellC[id];\n        row[r] ^= (1u << c);\n        col[c] ^= (1u << r);\n    }\n\n    inline int rowCompare(const array<uint32_t,MAXN>& a, const array<uint32_t,MAXN>& b) const {\n        return memcmp(a.data(), b.data(), N * sizeof(uint32_t));\n    }\n\n    inline bool isEmptyBoard(const array<uint32_t,MAXN>& row) const {\n        for (int r = 0; r < N; r++) if (row[r]) return false;\n        return true;\n    }\n\n    inline bool canToggleCell(int cell, int k) const {\n        // For safety, forbid toggling future targets directly.\n        int idx = targetIdxAtCell[cell];\n        return !(idx != -1 && idx > k);\n    }\n\n    int bfsDist(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col, int s, int g) const {\n        if (s == g) return 0;\n\n        int dist[400];\n        for (int i = 0; i < n2; i++) dist[i] = -1;\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            // Move\n            for (int d = 0; d < 4; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du;\n                if (v == g) return du;\n                q[tail++] = v;\n            }\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n        }\n        return INF;\n    }\n\n    bool bfsPath(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                 int s, int g, vector<Action>& out) const {\n        out.clear();\n        if (s == g) return true;\n\n        int dist[400], par[400];\n        uint8_t pdir[400];\n        char pact[400];\n        for (int i = 0; i < n2; i++) {\n            dist[i] = -1;\n            par[i] = -1;\n        }\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        par[s] = s;\n        q[tail++] = s;\n\n        bool found = false;\n\n        while (head < tail && !found) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            auto relax = [&](int v, char act, int d)->bool {\n                if (v == u) return false;\n                if (dist[v] != -1) return false;\n                dist[v] = du;\n                par[v] = u;\n                pact[v] = act;\n                pdir[v] = static_cast<uint8_t>(d);\n                q[tail++] = v;\n                return v == g;\n            };\n\n            // Move\n            for (int d = 0; d < 4 && !found; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (relax(v, 'M', d)) found = true;\n            }\n            if (found) break;\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 0)) found = true;\n                }\n            }\n            if (found) break;\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 1)) found = true;\n                }\n            }\n            if (found) break;\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 2)) found = true;\n                }\n            }\n            if (found) break;\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 3)) found = true;\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        vector<Action> rev;\n        int cur = g;\n        while (cur != s) {\n            if (cur < 0 || par[cur] < 0) return false;\n            rev.push_back(Action{pact[cur], DCH[pdir[cur]]});\n            cur = par[cur];\n        }\n        reverse(rev.begin(), rev.end());\n        out.swap(rev);\n        return true;\n    }\n\n    vector<Action> fallbackManhattan() const {\n        vector<Action> ans;\n        int r = pts[0].r, c = pts[0].c;\n        for (int k = 1; k < M; k++) {\n            int tr = pts[k].r, tc = pts[k].c;\n            while (r < tr) { ans.push_back({'M','D'}); r++; }\n            while (r > tr) { ans.push_back({'M','U'}); r--; }\n            while (c < tc) { ans.push_back({'M','R'}); c++; }\n            while (c > tc) { ans.push_back({'M','L'}); c--; }\n        }\n        return ans;\n    }\n\n    vector<Action> fallbackNoBlock() const {\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u); col.fill(0u);\n\n        vector<Action> ans;\n        int cur = pid[0];\n        for (int k = 0; k < M - 1; k++) {\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, pid[k+1], path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = pid[k+1];\n        }\n        return ans;\n    }\n\n    bool validate(const vector<Action>& acts) const {\n        if ((int)acts.size() > LIMIT) return false;\n\n        vector<vector<uint8_t>> blk(N, vector<uint8_t>(N, 0));\n        int r = pts[0].r, c = pts[0].c;\n        int nxtTarget = 1;\n\n        auto dirId = [&](char ch)->int {\n            if (ch == 'U') return 0;\n            if (ch == 'D') return 1;\n            if (ch == 'L') return 2;\n            if (ch == 'R') return 3;\n            return -1;\n        };\n\n        for (const auto& ac : acts) {\n            int d = dirId(ac.d);\n            if (d < 0) return false;\n\n            if (ac.a == 'M') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                if (blk[nr][nc]) return false;\n                r = nr; c = nc;\n            } else if (ac.a == 'S') {\n                int nr = r, nc = c;\n                while (true) {\n                    int tr = nr + DR[d], tc = nc + DC[d];\n                    if (!(0 <= tr && tr < N && 0 <= tc && tc < N)) break;\n                    if (blk[tr][tc]) break;\n                    nr = tr; nc = tc;\n                }\n                r = nr; c = nc;\n            } else if (ac.a == 'A') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                blk[nr][nc] ^= 1;\n            } else {\n                return false;\n            }\n\n            if (nxtTarget < M && r == pts[nxtTarget].r && c == pts[nxtTarget].c) {\n                nxtTarget++;\n            }\n        }\n\n        return nxtTarget == M;\n    }\n\n    vector<Action> runBeam(int upperBound) {\n        // Search only paths strictly shorter than upperBound.\n        if (upperBound <= 0) return {};\n\n        const int WIDTH = 170;\n        const int PRE = WIDTH * 6;\n\n        vector<vector<Node>> layers(M);\n        layers[0].reserve(1);\n        Node init;\n        init.row.fill(0u);\n        init.col.fill(0u);\n        init.cost = 0;\n        init.parent = -1;\n        init.op = 0;\n        init.bcnt = 0;\n        layers[0].push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            int s = pid[k];\n            int g = pid[k + 1];\n\n            vector<Node> cands;\n            cands.reserve((int)layers[k].size() * 24 + 16);\n\n            for (int si = 0; si < (int)layers[k].size(); si++) {\n                const Node& st = layers[k][si];\n\n                // 0) No prep\n                {\n                    int d = bfsDist(st.row, st.col, s, g);\n                    if (d < INF) {\n                        int total = st.cost + d;\n                        if (total < upperBound) {\n                            Node nd = st;\n                            nd.cost = total;\n                            nd.parent = si;\n                            nd.op = 0;\n                            nd.d1 = nd.d2 = 0;\n                            nd.eval = 0;\n                            cands.push_back(std::move(nd));\n                        }\n                    }\n                }\n\n                // 1) A once at current\n                for (int d1 = 0; d1 < 4; d1++) {\n                    int tcell = to[s][d1];\n                    if (tcell == -1) continue;\n                    if (!canToggleCell(tcell, k)) continue;\n\n                    Node nd;\n                    nd.row = st.row;\n                    nd.col = st.col;\n\n                    bool was = isBlocked(st.row, tcell);\n                    toggleCell(nd.row, nd.col, tcell);\n\n                    int d = bfsDist(nd.row, nd.col, s, g);\n                    if (d >= INF) continue;\n                    int total = st.cost + 1 + d;\n                    if (total >= upperBound) continue;\n\n                    nd.cost = total;\n                    nd.parent = si;\n                    nd.op = 1;\n                    nd.d1 = static_cast<uint8_t>(d1);\n                    nd.d2 = 0;\n                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                    nd.bcnt = (uint16_t)max(0, nb);\n                    nd.eval = 0;\n                    cands.push_back(std::move(nd));\n                }\n\n                // 2) M once, then A once\n                for (int md = 0; md < 4; md++) {\n                    int ncell = to[s][md];\n                    if (ncell == -1) continue;\n                    if (isBlocked(st.row, ncell)) continue;\n\n                    for (int ad = 0; ad < 4; ad++) {\n                        int tcell = to[ncell][ad];\n                        if (tcell == -1) continue;\n                        if (!canToggleCell(tcell, k)) continue;\n\n                        Node nd;\n                        nd.row = st.row;\n                        nd.col = st.col;\n\n                        bool was = isBlocked(st.row, tcell);\n                        toggleCell(nd.row, nd.col, tcell);\n\n                        int d = bfsDist(nd.row, nd.col, ncell, g);\n                        if (d >= INF) continue;\n                        int total = st.cost + 2 + d;\n                        if (total >= upperBound) continue;\n\n                        nd.cost = total;\n                        nd.parent = si;\n                        nd.op = 2;\n                        nd.d1 = static_cast<uint8_t>(md);\n                        nd.d2 = static_cast<uint8_t>(ad);\n                        int nb = (int)st.bcnt + (was ? -1 : +1);\n                        nd.bcnt = (uint16_t)max(0, nb);\n                        nd.eval = 0;\n                        cands.push_back(std::move(nd));\n                    }\n                }\n            }\n\n            if (cands.empty()) return {};\n\n            // Dedup by exact board\n            sort(cands.begin(), cands.end(), [&](const Node& a, const Node& b) {\n                int cmp = rowCompare(a.row, b.row);\n                if (cmp != 0) return cmp < 0;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                return a.bcnt > b.bcnt;\n            });\n\n            vector<Node> uniq;\n            uniq.reserve(cands.size());\n            for (auto& nd : cands) {\n                if (uniq.empty() || rowCompare(uniq.back().row, nd.row) != 0) {\n                    uniq.push_back(nd);\n                } else {\n                    Node& cur = uniq.back();\n                    if (nd.cost < cur.cost || (nd.cost == cur.cost && nd.bcnt > cur.bcnt)) {\n                        cur = nd;\n                    }\n                }\n            }\n\n            sort(uniq.begin(), uniq.end(), [](const Node& a, const Node& b) {\n                if (a.cost != b.cost) return a.cost < b.cost;\n                return a.bcnt > b.bcnt;\n            });\n\n            if ((int)uniq.size() > PRE) uniq.resize(PRE);\n\n            if ((int)uniq.size() > WIDTH) {\n                int nextFrom = pid[k + 1];\n                int nextTo = (k + 2 < M ? pid[k + 2] : -1);\n\n                for (auto& nd : uniq) {\n                    int h = 0;\n                    if (nextTo != -1) {\n                        h = bfsDist(nd.row, nd.col, nextFrom, nextTo);\n                        if (h >= INF) h = 60;\n                    }\n                    // mild lookahead + slight encouragement for richer stopper sets\n                    nd.eval = nd.cost * 3 + h * 2 - (int)nd.bcnt / 2;\n                }\n\n                vector<int> ordEval(uniq.size());\n                iota(ordEval.begin(), ordEval.end(), 0);\n                sort(ordEval.begin(), ordEval.end(), [&](int i, int j) {\n                    const Node& a = uniq[i];\n                    const Node& b = uniq[j];\n                    if (a.eval != b.eval) return a.eval < b.eval;\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                vector<Node> chosen;\n                chosen.reserve(WIDTH);\n                vector<char> used(uniq.size(), 0);\n\n                int elite = max(1, WIDTH / 2); // preserve strong pure-cost states\n                elite = min(elite, (int)uniq.size());\n\n                for (int i = 0; i < elite; i++) {\n                    chosen.push_back(uniq[i]);\n                    used[i] = 1;\n                }\n                for (int idx : ordEval) {\n                    if ((int)chosen.size() >= WIDTH) break;\n                    if (used[idx]) continue;\n                    chosen.push_back(uniq[idx]);\n                    used[idx] = 1;\n                }\n\n                // keep empty-board state if it exists (safety/diversity)\n                bool hasEmpty = false;\n                for (const auto& nd : chosen) {\n                    if (isEmptyBoard(nd.row)) { hasEmpty = true; break; }\n                }\n                if (!hasEmpty) {\n                    for (int i = 0; i < (int)uniq.size(); i++) {\n                        if (isEmptyBoard(uniq[i].row)) {\n                            if (!chosen.empty()) chosen.back() = uniq[i];\n                            else chosen.push_back(uniq[i]);\n                            break;\n                        }\n                    }\n                }\n\n                uniq.swap(chosen);\n            }\n\n            if (uniq.empty()) return {};\n            layers[k + 1].swap(uniq);\n        }\n\n        if (layers[M - 1].empty()) return {};\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)layers[M - 1].size(); i++) {\n            if (layers[M - 1][i].cost < layers[M - 1][bestIdx].cost) bestIdx = i;\n        }\n\n        struct Dec { uint8_t op, d1, d2; };\n        vector<Dec> dec(max(0, M - 1));\n\n        int idx = bestIdx;\n        for (int k = M - 2; k >= 0; k--) {\n            const Node& nd = layers[k + 1][idx];\n            dec[k] = Dec{nd.op, nd.d1, nd.d2};\n            idx = nd.parent;\n            if (idx < 0 && k > 0) return {};\n        }\n        if (M >= 2 && idx < 0) return {};\n\n        // Reconstruct full action sequence.\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u);\n        col.fill(0u);\n\n        int cur = pid[0];\n        vector<Action> ans;\n        ans.reserve(layers[M - 1][bestIdx].cost + 16);\n\n        for (int k = 0; k < M - 1; k++) {\n            int s = pid[k], g = pid[k + 1];\n            if (cur != s) return {};\n\n            if (dec[k].op == 1) {\n                int tcell = to[s][dec[k].d1];\n                if (tcell == -1) return {};\n                ans.push_back({'A', DCH[dec[k].d1]});\n                toggleCell(row, col, tcell);\n            } else if (dec[k].op == 2) {\n                int ncell = to[s][dec[k].d1];\n                if (ncell == -1 || isBlocked(row, ncell)) return {};\n                ans.push_back({'M', DCH[dec[k].d1]});\n                cur = ncell;\n\n                int tcell = to[ncell][dec[k].d2];\n                if (tcell == -1) return {};\n                ans.push_back({'A', DCH[dec[k].d2]});\n                toggleCell(row, col, tcell);\n            }\n\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, g, path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = g;\n        }\n\n        return ans;\n    }\n\n    void init() {\n        n2 = N * N;\n        LIMIT = 2 * N * M;\n\n        pid.resize(M);\n        for (int i = 0; i < M; i++) pid[i] = pts[i].r * N + pts[i].c;\n\n        cellR.resize(n2);\n        cellC.resize(n2);\n        to.assign(n2, array<int,4>{-1,-1,-1,-1});\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                cellR[id] = r;\n                cellC[id] = c;\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + DR[d], nc = c + DC[d];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                        to[id][d] = nr * N + nc;\n                    }\n                }\n            }\n        }\n\n        lowMask.fill(0u);\n        highMask.fill(0u);\n        for (int i = 0; i < N; i++) {\n            lowMask[i] = (i == 0 ? 0u : ((1u << i) - 1u));\n            highMask[i] = ~((1u << (i + 1)) - 1u);\n        }\n\n        targetIdxAtCell.assign(n2, -1);\n        for (int i = 0; i < M; i++) {\n            targetIdxAtCell[pid[i]] = i;\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        pts.resize(M);\n        for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n        init();\n\n        vector<Action> base = fallbackNoBlock();\n        if (base.empty() || (int)base.size() > LIMIT || !validate(base)) {\n            base = fallbackManhattan();\n        }\n\n        vector<Action> beam = runBeam((int)base.size());\n\n        vector<Action> ans = base;\n        if (!beam.empty() && (int)beam.size() <= LIMIT && validate(beam)) {\n            if (beam.size() < ans.size()) ans.swap(beam);\n        }\n\n        if ((int)ans.size() > LIMIT || !validate(ans)) {\n            ans = fallbackManhattan();\n        }\n\n        for (const auto& ac : ans) {\n            cout << ac.a << ' ' << ac.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}"},"4":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int BOARD = 10000;\nenum Side { LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3 };\n\nstruct Company {\n    int x, y, r; // desired point cell (x,y), target area r\n};\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n};\n\nstruct State {\n    vector<Rect> rects;\n    vector<long long> area;\n    vector<double> p;\n    double total = 0.0;\n};\n\nint n;\nvector<Company> C;\nchrono::steady_clock::time_point gStart;\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - gStart).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed ? seed : 88172645463325252ull) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int l, int r) {\n        if (l >= r) return l;\n        uint64_t span = (uint64_t)(r - l + 1);\n        return l + (int)(nextU64() % span);\n    }\n};\n\ninline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\ninline long long rectArea(const Rect& rc) {\n    return 1LL * (rc.r - rc.l) * (rc.t - rc.b);\n}\n\ninline double satisfaction(long long s, long long target) {\n    if (s <= 0) return 0.0;\n    double ratio = (s < target) ? (double)s / (double)target : (double)target / (double)s;\n    double d = 1.0 - ratio;\n    return 1.0 - d * d;\n}\n\ninline int getCoord(const Rect& rc, int side) {\n    if (side == LEFT) return rc.l;\n    if (side == RIGHT) return rc.r;\n    if (side == BOTTOM) return rc.b;\n    return rc.t;\n}\n\ninline void setCoord(Rect& rc, int side, int v) {\n    if (side == LEFT) rc.l = v;\n    else if (side == RIGHT) rc.r = v;\n    else if (side == BOTTOM) rc.b = v;\n    else rc.t = v;\n}\n\ninline long long areaWithSide(const Rect& rc, int side, int v) {\n    if (side == LEFT) return 1LL * (rc.r - v) * (rc.t - rc.b);\n    if (side == RIGHT) return 1LL * (v - rc.l) * (rc.t - rc.b);\n    if (side == BOTTOM) return 1LL * (rc.r - rc.l) * (rc.t - v);\n    return 1LL * (rc.r - rc.l) * (v - rc.b);\n}\n\nState makeState(const vector<Rect>& rects) {\n    State st;\n    st.rects = rects;\n    st.area.resize(n);\n    st.p.resize(n);\n    st.total = 0.0;\n    for (int i = 0; i < n; ++i) {\n        st.area[i] = rectArea(st.rects[i]);\n        st.p[i] = satisfaction(st.area[i], C[i].r);\n        st.total += st.p[i];\n    }\n    return st;\n}\n\nbool validateRects(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = rects[i];\n        if (!(0 <= a.l && a.l < a.r && a.r <= BOARD && 0 <= a.b && a.b < a.t && a.t <= BOARD)) return false;\n        if (!(a.l <= C[i].x && C[i].x + 1 <= a.r && a.b <= C[i].y && C[i].y + 1 <= a.t)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect& a = rects[i];\n            const Rect& b = rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && overlap1D(a.b, a.t, b.b, b.t)) return false;\n        }\n    }\n    return true;\n}\n\n// Movable range for one side, optionally ignoring one rectangle (for pair moves).\npair<int, int> sideRange(const State& st, int i, int side, int ignore = -1) {\n    const Rect& a = st.rects[i];\n\n    if (side == LEFT) {\n        int L = 0;\n        int U = min(C[i].x, a.r - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.l < a.r) L = max(L, b.r);\n        }\n        return {L, U};\n    }\n\n    if (side == RIGHT) {\n        int L = max(C[i].x + 1, a.l + 1);\n        int U = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.r > a.l) U = min(U, b.l);\n        }\n        return {L, U};\n    }\n\n    if (side == BOTTOM) {\n        int L = 0;\n        int U = min(C[i].y, a.t - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && b.b < a.t) L = max(L, b.t);\n        }\n        return {L, U};\n    }\n\n    int L = max(C[i].y + 1, a.b + 1);\n    int U = BOARD;\n    for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n        const Rect& b = st.rects[j];\n        if (overlap1D(a.l, a.r, b.l, b.r) && b.t > a.b) U = min(U, b.b);\n    }\n    return {L, U};\n}\n\npair<int, int> shiftRangeX(const State& st, int i) {\n    const Rect& a = st.rects[i];\n\n    int LB = -a.l;\n    int UB = BOARD - a.r;\n\n    // point containment\n    LB = max(LB, C[i].x + 1 - a.r);\n    UB = min(UB, C[i].x - a.l);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.b, a.t, b.b, b.t)) continue;\n        if (b.r <= a.l) LB = max(LB, b.r - a.l);\n        else if (b.l >= a.r) UB = min(UB, b.l - a.r);\n        else return {1, 0}; // invalid state\n    }\n    return {LB, UB};\n}\n\npair<int, int> shiftRangeY(const State& st, int i) {\n    const Rect& a = st.rects[i];\n\n    int LB = -a.b;\n    int UB = BOARD - a.t;\n\n    // point containment\n    LB = max(LB, C[i].y + 1 - a.t);\n    UB = min(UB, C[i].y - a.b);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.l, a.r, b.l, b.r)) continue;\n        if (b.t <= a.b) LB = max(LB, b.t - a.b);\n        else if (b.b >= a.t) UB = min(UB, b.b - a.t);\n        else return {1, 0}; // invalid state\n    }\n    return {LB, UB};\n}\n\nconstexpr int MAX_CAND = 24;\n\ninline void addCand(int arr[], int& m, int v, int L, int U) {\n    if (v < L || v > U) return;\n    for (int i = 0; i < m; ++i) if (arr[i] == v) return;\n    if (m < MAX_CAND) arr[m++] = v;\n}\n\nvoid fillCandidatesForSide(const State& st, int i, int side, int L, int U, int arr[], int& m, RNG* rng = nullptr) {\n    m = 0;\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n\n    addCand(arr, m, cur, L, U);\n    addCand(arr, m, L, L, U);\n    addCand(arr, m, U, L, U);\n    addCand(arr, m, (L + U) >> 1, L, U);\n\n    long long target = C[i].r;\n    if (side == LEFT || side == RIGHT) {\n        int h = a.t - a.b;\n        if (h > 0) {\n            int w0 = (int)llround((double)target / (double)h);\n            for (int dw = -2; dw <= 2; ++dw) {\n                int w = w0 + dw;\n                if (w < 1) continue;\n                int v = (side == LEFT) ? (a.r - w) : (a.l + w);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    } else {\n        int w = a.r - a.l;\n        if (w > 0) {\n            int h0 = (int)llround((double)target / (double)w);\n            for (int dh = -2; dh <= 2; ++dh) {\n                int h = h0 + dh;\n                if (h < 1) continue;\n                int v = (side == BOTTOM) ? (a.t - h) : (a.b + h);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    }\n\n    if (rng && U > L) {\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n    }\n}\n\nint bestCoordForSide(const State& st, int i, int side, int L, int U) {\n    int cands[MAX_CAND], m;\n    fillCandidatesForSide(st, i, side, L, U, cands, m, nullptr);\n\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n    int best = cur;\n    double bestP = st.p[i];\n\n    for (int k = 0; k < m; ++k) {\n        int v = cands[k];\n        long long ar = areaWithSide(a, side, v);\n        double np = satisfaction(ar, C[i].r);\n        if (np > bestP + 1e-15 || (fabs(np - bestP) <= 1e-15 && abs(v - cur) < abs(best - cur))) {\n            bestP = np;\n            best = v;\n        }\n    }\n    return best;\n}\n\ninline void applySingleSide(State& st, int i, int side, int v) {\n    st.total -= st.p[i];\n    setCoord(st.rects[i], side, v);\n    st.area[i] = rectArea(st.rects[i]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.total += st.p[i];\n}\n\nint pickRect(const State& st, RNG& rng) {\n    int best = rng.nextInt(0, n - 1);\n    for (int t = 0; t < 4; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nint pickRect2(const State& st, RNG& rng, int avoid) {\n    int best = rng.nextInt(0, n - 1);\n    if (best == avoid) best = (best + 1) % n;\n    for (int t = 0; t < 4; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (j == avoid) continue;\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nstruct PairMove {\n    int i = -1, j = -1;\n    int sideI = -1, sideJ = -1;\n    int vI = 0, vJ = 0;\n    double delta = 0.0;\n    bool valid = false;\n};\n\nbool proposeHorizontal(const State& st, int left, int right, RNG& rng, bool greedy, PairMove& out) {\n    // left is left of right (in x): left.r <= right.l\n    auto [L1, U1] = sideRange(st, left, RIGHT, right);\n    auto [L2, U2] = sideRange(st, right, LEFT, left);\n\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false;\n\n    int curX = st.rects[left].r;\n    int curY = st.rects[right].l;\n    double oldS = st.p[left] + st.p[right];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, left, RIGHT, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, right, LEFT, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n                long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n                double s = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n        long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n        double ns = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposeVertical(const State& st, int bottom, int top, RNG& rng, bool greedy, PairMove& out) {\n    // bottom is below top (in y): bottom.t <= top.b\n    auto [L1, U1] = sideRange(st, bottom, TOP, top);\n    auto [L2, U2] = sideRange(st, top, BOTTOM, bottom);\n\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false;\n\n    int curX = st.rects[bottom].t;\n    int curY = st.rects[top].b;\n    double oldS = st.p[bottom] + st.p[top];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, bottom, TOP, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, top, BOTTOM, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n                long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n                double s = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n        long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n        double ns = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposePairMove(const State& st, int i, int j, RNG& rng, bool greedy, PairMove& out) {\n    if (i == j) return false;\n    const Rect& a = st.rects[i];\n    const Rect& b = st.rects[j];\n\n    bool found = false;\n    PairMove best;\n\n    // Horizontal relation\n    if (overlap1D(a.b, a.t, b.b, b.t)) {\n        if (a.r <= b.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, i, j, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        } else if (b.r <= a.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, j, i, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        }\n    }\n\n    // Vertical relation\n    if (overlap1D(a.l, a.r, b.l, b.r)) {\n        if (a.t <= b.b) {\n            PairMove mv;\n            if (proposeVertical(st, i, j, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        } else if (b.t <= a.b) {\n            PairMove mv;\n            if (proposeVertical(st, j, i, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        }\n    }\n\n    if (!found) return false;\n    out = best;\n    return true;\n}\n\ninline void applyPairMove(State& st, const PairMove& mv) {\n    int i = mv.i, j = mv.j;\n    st.total -= st.p[i] + st.p[j];\n\n    setCoord(st.rects[i], mv.sideI, mv.vI);\n    setCoord(st.rects[j], mv.sideJ, mv.vJ);\n\n    st.area[i] = rectArea(st.rects[i]);\n    st.area[j] = rectArea(st.rects[j]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.p[j] = satisfaction(st.area[j], C[j].r);\n\n    st.total += st.p[i] + st.p[j];\n}\n\n// Build neighbor-focused pair list (nearest left/right/up/down for each rectangle)\nvector<pair<int, int>> buildNeighborPairs(const State& st) {\n    vector<pair<int, int>> pairs;\n    vector<unsigned char> used(n * n, 0);\n    auto addPair = [&](int a, int b) {\n        if (a < 0 || b < 0 || a == b) return;\n        if (a > b) swap(a, b);\n        int id = a * n + b;\n        if (!used[id]) {\n            used[id] = 1;\n            pairs.push_back({a, b});\n        }\n    };\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = st.rects[i];\n\n        int leftJ = -1, leftV = -1;\n        int rightJ = -1, rightV = BOARD + 1;\n        int downJ = -1, downV = -1;\n        int upJ = -1, upV = BOARD + 1;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& b = st.rects[j];\n\n            if (overlap1D(a.b, a.t, b.b, b.t)) {\n                if (b.r <= a.l && b.r > leftV) {\n                    leftV = b.r;\n                    leftJ = j;\n                }\n                if (b.l >= a.r && b.l < rightV) {\n                    rightV = b.l;\n                    rightJ = j;\n                }\n            }\n\n            if (overlap1D(a.l, a.r, b.l, b.r)) {\n                if (b.t <= a.b && b.t > downV) {\n                    downV = b.t;\n                    downJ = j;\n                }\n                if (b.b >= a.t && b.b < upV) {\n                    upV = b.b;\n                    upJ = j;\n                }\n            }\n        }\n\n        addPair(i, leftJ);\n        addPair(i, rightJ);\n        addPair(i, downJ);\n        addPair(i, upJ);\n    }\n\n    return pairs;\n}\n\npair<int, int> pickNeighborPair(const State& st, const vector<pair<int, int>>& pairs, RNG& rng) {\n    if (pairs.empty()) return {-1, -1};\n    int m = (int)pairs.size();\n\n    int bestIdx = rng.nextInt(0, m - 1);\n    double bestScore = -1e100;\n\n    int trials = min(6, m);\n    for (int t = 0; t < trials; ++t) {\n        int idx = rng.nextInt(0, m - 1);\n        auto [i, j] = pairs[idx];\n\n        double e1 = (double)st.area[i] / (double)C[i].r - 1.0;\n        double e2 = (double)st.area[j] / (double)C[j].r - 1.0;\n        double opposite = max(0.0, -e1 * e2); // useful for area transfer\n        double score = (1.0 - st.p[i]) + (1.0 - st.p[j]) + 0.25 * opposite;\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestIdx = idx;\n        }\n    }\n    return pairs[bestIdx];\n}\n\nvoid greedyOptimize(State& st, RNG& rng, int maxPass) {\n    vector<int> ord(n);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (st.p[a] != st.p[b]) return st.p[a] < st.p[b];\n            return a < b;\n        });\n\n        int rndSwap = max(1, n / 12);\n        for (int s = 0; s < rndSwap; ++s) {\n            int i = rng.nextInt(0, n - 1);\n            int j = rng.nextInt(0, n - 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int idx = 0; idx < n; ++idx) {\n            int i = ord[idx];\n            double oldP = st.p[i];\n\n            int bestSide = -1;\n            int bestV = 0;\n            double bestDelta = 1e-12;\n\n            for (int side = 0; side < 4; ++side) {\n                auto [L, U] = sideRange(st, i, side);\n                if (L > U) continue;\n\n                int curV = getCoord(st.rects[i], side);\n                int v = bestCoordForSide(st, i, side, L, U);\n                if (v == curV) continue;\n\n                long long ar = areaWithSide(st.rects[i], side, v);\n                double np = satisfaction(ar, C[i].r);\n                double delta = np - oldP;\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSide = side;\n                    bestV = v;\n                }\n            }\n\n            if (bestSide != -1) {\n                applySingleSide(st, i, bestSide, bestV);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid pairGreedyOptimize(State& st, RNG& rng, int maxPass) {\n    for (int pass = 0; pass < maxPass; ++pass) {\n        auto pairs = buildNeighborPairs(st);\n        if (pairs.empty()) break;\n\n        for (int i = (int)pairs.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(0, i);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        for (auto [a, b] : pairs) {\n            PairMove mv;\n            if (!proposePairMove(st, a, b, rng, true, mv)) continue;\n            if (mv.delta > 1e-12) {\n                applyPairMove(st, mv);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\n// -------- Randomized guillotine initializer --------\nstruct SplitCand {\n    int ori; // 0 vertical, 1 horizontal\n    int k;\n    int t;\n    double cost;\n};\n\nint buildCallCount = 0;\nconstexpr int BUILD_CALL_LIMIT = 80000;\n\nbool buildPartitionRec(const vector<int>& ids, int L, int B, int R, int T, vector<Rect>& out, RNG& rng) {\n    if (++buildCallCount > BUILD_CALL_LIMIT) return false;\n\n    int m = (int)ids.size();\n    if (m == 0) return true;\n    if (L >= R || B >= T) return false;\n    if (1LL * (R - L) * (T - B) < m) return false;\n\n    if (m == 1) {\n        int id = ids[0];\n        if (!(L <= C[id].x && C[id].x + 1 <= R && B <= C[id].y && C[id].y + 1 <= T)) return false;\n        out[id] = {L, B, R, T};\n        return true;\n    }\n\n    int W = R - L, H = T - B;\n    if (W <= 0 || H <= 0) return false;\n\n    vector<int> ox = ids, oy = ids;\n    sort(ox.begin(), ox.end(), [](int a, int b) {\n        if (C[a].x != C[b].x) return C[a].x < C[b].x;\n        return C[a].y < C[b].y;\n    });\n    sort(oy.begin(), oy.end(), [](int a, int b) {\n        if (C[a].y != C[b].y) return C[a].y < C[b].y;\n        return C[a].x < C[b].x;\n    });\n\n    vector<long long> px(m + 1, 0), py(m + 1, 0);\n    for (int i = 0; i < m; ++i) {\n        px[i + 1] = px[i] + C[ox[i]].r;\n        py[i + 1] = py[i] + C[oy[i]].r;\n    }\n    long long totalR = px[m];\n\n    vector<SplitCand> cands;\n    cands.reserve(2 * (m - 1));\n\n    // Vertical split\n    if (W >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int xl = C[ox[k - 1]].x;\n            int xr = C[ox[k]].x;\n            int low = max(L + 1, xl + 1);\n            int high = min(R - 1, xr);\n            if (low > high) continue;\n\n            long long leftR = px[k];\n            long long rightR = totalR - leftR;\n\n            int t = (int)llround(L + (double)leftR / (double)H);\n            t = max(low, min(high, t));\n\n            long long leftArea = 1LL * (t - L) * H;\n            long long rightArea = 1LL * (R - t) * H;\n\n            double cost = fabs((double)(leftArea - leftR)) + fabs((double)(rightArea - rightR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({0, k, t, cost});\n        }\n    }\n\n    // Horizontal split\n    if (H >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int yb = C[oy[k - 1]].y;\n            int yt = C[oy[k]].y;\n            int low = max(B + 1, yb + 1);\n            int high = min(T - 1, yt);\n            if (low > high) continue;\n\n            long long botR = py[k];\n            long long topR = totalR - botR;\n\n            int t = (int)llround(B + (double)botR / (double)W);\n            t = max(low, min(high, t));\n\n            long long botArea = 1LL * (t - B) * W;\n            long long topArea = 1LL * (T - t) * W;\n\n            double cost = fabs((double)(botArea - botR)) + fabs((double)(topArea - topR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({1, k, t, cost});\n        }\n    }\n\n    if (cands.empty()) return false;\n\n    sort(cands.begin(), cands.end(), [](const SplitCand& a, const SplitCand& b) {\n        return a.cost < b.cost;\n    });\n\n    int lim = min((int)cands.size(), 18);\n    for (int i = 0; i < lim; ++i) {\n        int span = min(3, lim - 1 - i);\n        if (span > 0) {\n            int j = i + rng.nextInt(0, span);\n            swap(cands[i], cands[j]);\n        }\n    }\n\n    for (int idx = 0; idx < lim; ++idx) {\n        const SplitCand& c = cands[idx];\n\n        if (c.ori == 0) {\n            long long areaL = 1LL * (c.t - L) * (T - B);\n            long long areaR = 1LL * (R - c.t) * (T - B);\n            if (areaL < c.k || areaR < (m - c.k)) continue;\n\n            vector<int> leftIds(ox.begin(), ox.begin() + c.k);\n            vector<int> rightIds(ox.begin() + c.k, ox.end());\n\n            if (buildPartitionRec(leftIds, L, B, c.t, T, out, rng) &&\n                buildPartitionRec(rightIds, c.t, B, R, T, out, rng)) {\n                return true;\n            }\n        } else {\n            long long areaB = 1LL * (R - L) * (c.t - B);\n            long long areaT = 1LL * (R - L) * (T - c.t);\n            if (areaB < c.k || areaT < (m - c.k)) continue;\n\n            vector<int> botIds(oy.begin(), oy.begin() + c.k);\n            vector<int> topIds(oy.begin() + c.k, oy.end());\n\n            if (buildPartitionRec(botIds, L, B, R, c.t, out, rng) &&\n                buildPartitionRec(topIds, L, c.t, R, T, out, rng)) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid addPool(vector<State>& pool, const State& st, int cap = 8) {\n    pool.push_back(st);\n    sort(pool.begin(), pool.end(), [](const State& a, const State& b) {\n        return a.total > b.total;\n    });\n    if ((int)pool.size() > cap) pool.resize(cap);\n}\n\nvoid anneal(State& cur, State& bestGlobal, RNG& rng,\n            double tEnd, double T0, double T1, bool allowKick) {\n    double tStart = elapsedSec();\n    if (tEnd <= tStart + 1e-4) return;\n    double span = tEnd - tStart;\n\n    State bestLocal = cur;\n    auto neighborPairs = buildNeighborPairs(cur);\n\n    double nextRebuild = tStart + 0.22;\n    double nextRefine = tStart + 0.58;\n    double lastImprove = tStart;\n\n    long long iter = 0;\n    double temp = T0;\n\n    while (true) {\n        double t = 0.0;\n        if ((iter & 255LL) == 0) {\n            t = elapsedSec();\n            if (t >= tEnd) break;\n\n            double prog = (t - tStart) / span;\n            if (prog < 0.0) prog = 0.0;\n            if (prog > 1.0) prog = 1.0;\n            temp = T0 * pow(T1 / T0, prog);\n\n            if (t >= nextRebuild) {\n                neighborPairs = buildNeighborPairs(cur);\n                nextRebuild = t + 0.22;\n            }\n\n            if (t >= nextRefine) {\n                pairGreedyOptimize(cur, rng, 1);\n                greedyOptimize(cur, rng, 2);\n\n                if (cur.total > bestLocal.total + 1e-15) {\n                    bestLocal = cur;\n                    if (bestLocal.total > bestGlobal.total) bestGlobal = bestLocal;\n                    lastImprove = t;\n                }\n\n                nextRefine = t + 0.58;\n            }\n\n            if (allowKick && t - lastImprove > 0.90) {\n                if (bestLocal.total > cur.total + 1e-12) cur = bestLocal;\n\n                // light random perturb\n                for (int z = 0; z < 3; ++z) {\n                    int i = pickRect(cur, rng);\n                    int side = rng.nextInt(0, 3);\n                    auto [L, U] = sideRange(cur, i, side);\n                    if (L <= U) {\n                        int v = rng.nextInt(L, U);\n                        if (v != getCoord(cur.rects[i], side)) applySingleSide(cur, i, side, v);\n                    }\n                }\n                neighborPairs = buildNeighborPairs(cur);\n                lastImprove = t;\n            }\n        }\n\n        double op = rng.nextDouble();\n\n        if (op < 0.56) {\n            // Single side move\n            int i = pickRect(cur, rng);\n            int side = rng.nextInt(0, 3);\n\n            auto [L, U] = sideRange(cur, i, side);\n            if (L > U) { ++iter; continue; }\n\n            int curV = getCoord(cur.rects[i], side);\n            int v = curV;\n\n            double mode = rng.nextDouble();\n            if (mode < 0.55) {\n                v = bestCoordForSide(cur, i, side, L, U);\n            } else if (mode < 0.85) {\n                int spanv = U - L;\n                int step = max(1, (int)(spanv * 0.35));\n                int d = rng.nextInt(-step, step);\n                v = curV + d;\n                if (v < L) v = L;\n                if (v > U) v = U;\n            } else {\n                v = rng.nextInt(L, U);\n            }\n\n            if (v != curV) {\n                long long newA = areaWithSide(cur.rects[i], side, v);\n                double newP = satisfaction(newA, C[i].r);\n                double delta = newP - cur.p[i];\n\n                if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                    cur.total += delta;\n                    cur.p[i] = newP;\n                    cur.area[i] = newA;\n                    setCoord(cur.rects[i], side, v);\n                }\n            }\n\n        } else if (op < 0.86) {\n            // Pair move\n            int i = -1, j = -1;\n            if (!neighborPairs.empty() && rng.nextDouble() < 0.86) {\n                auto pr = pickNeighborPair(cur, neighborPairs, rng);\n                i = pr.first; j = pr.second;\n            } else {\n                i = pickRect(cur, rng);\n                j = pickRect2(cur, rng, i);\n            }\n\n            if (i >= 0 && j >= 0 && i != j) {\n                PairMove mv;\n                bool greedySel = (rng.nextDouble() < 0.68);\n                if (proposePairMove(cur, i, j, rng, greedySel, mv)) {\n                    double delta = mv.delta;\n                    if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                        applyPairMove(cur, mv);\n                    }\n                }\n            }\n\n        } else if (op < 0.93) {\n            // Shift X\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeX(cur, i);\n            if (LB <= UB) {\n                int dx = 0;\n                if (LB == UB) dx = LB;\n                else if (rng.nextDouble() < 0.55) dx = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dx = rng.nextInt(LB, UB);\n\n                if (dx != 0) {\n                    cur.rects[i].l += dx;\n                    cur.rects[i].r += dx;\n                }\n            }\n\n        } else {\n            // Shift Y\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeY(cur, i);\n            if (LB <= UB) {\n                int dy = 0;\n                if (LB == UB) dy = LB;\n                else if (rng.nextDouble() < 0.55) dy = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dy = rng.nextInt(LB, UB);\n\n                if (dy != 0) {\n                    cur.rects[i].b += dy;\n                    cur.rects[i].t += dy;\n                }\n            }\n        }\n\n        if (cur.total > bestLocal.total + 1e-15) {\n            bestLocal = cur;\n            if (bestLocal.total > bestGlobal.total) bestGlobal = bestLocal;\n        }\n\n        ++iter;\n    }\n\n    cur = bestLocal;\n    if (cur.total > bestGlobal.total) bestGlobal = cur;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    C.resize(n);\n\n    uint64_t seed = 1469598103934665603ull ^ (uint64_t)n * 1000003ull;\n    for (int i = 0; i < n; ++i) {\n        cin >> C[i].x >> C[i].y >> C[i].r;\n        seed ^= (uint64_t)(C[i].x + 1) * 1000003ull;\n        seed ^= (uint64_t)(C[i].y + 1) * 1009837ull;\n        seed ^= (uint64_t)(C[i].r + 3) * 10000019ull;\n        seed *= 1099511628211ull;\n    }\n    RNG rng(seed);\n\n    gStart = chrono::steady_clock::now();\n\n    vector<State> pool;\n    pool.reserve(10);\n\n    // Base 1x1 state\n    vector<Rect> baseRects(n);\n    for (int i = 0; i < n; ++i) {\n        baseRects[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n    }\n    State base = makeState(baseRects);\n    addPool(pool, base, 8);\n\n    // Multiple 1x1-polished variants\n    for (int rep = 0; rep < 4; ++rep) {\n        if (elapsedSec() > 0.55) break;\n        State st = base;\n        greedyOptimize(st, rng, 32 + rep * 4);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 10);\n        addPool(pool, st, 8);\n    }\n\n    // Randomized guillotine initial states\n    const double INIT_END = 1.10;\n    int attempts = 0;\n    while (elapsedSec() < INIT_END && attempts < 26) {\n        ++attempts;\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n);\n\n        buildCallCount = 0;\n        bool ok = buildPartitionRec(ids, 0, 0, BOARD, BOARD, rects, rng);\n        if (!ok) continue;\n        if (!validateRects(rects)) continue;\n\n        State st = makeState(rects);\n        greedyOptimize(st, rng, 26);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 8);\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const State& a, const State& b) {\n        return a.total > b.total;\n    });\n\n    State bestInit = pool[0];\n    State bestGlobal = bestInit;\n\n    // Portfolio SA on top few candidates\n    const double PORT_END = 2.75;\n    int K = min((int)pool.size(), 3);\n    for (int idx = 0; idx < K; ++idx) {\n        double now = elapsedSec();\n        if (now >= PORT_END) break;\n        double end = now + (PORT_END - now) / (double)(K - idx);\n\n        State cur = pool[idx];\n        anneal(cur, bestGlobal, rng, end, 0.085, 0.0018, true);\n\n        if (elapsedSec() < PORT_END - 0.04) {\n            pairGreedyOptimize(cur, rng, 1);\n            greedyOptimize(cur, rng, 8);\n            if (cur.total > bestGlobal.total) bestGlobal = cur;\n        }\n    }\n\n    // Final intensification SA\n    State cur = bestGlobal;\n    const double FINAL_SA_END = 4.72;\n    if (elapsedSec() < FINAL_SA_END) {\n        anneal(cur, bestGlobal, rng, FINAL_SA_END, 0.045, 0.00005, true);\n    }\n\n    // Final polish\n    if (elapsedSec() < 4.82) {\n        pairGreedyOptimize(bestGlobal, rng, 2);\n        greedyOptimize(bestGlobal, rng, 24);\n    }\n    if (elapsedSec() < 4.90) {\n        pairGreedyOptimize(bestGlobal, rng, 1);\n        greedyOptimize(bestGlobal, rng, 12);\n    }\n\n    bestGlobal = makeState(bestGlobal.rects);\n\n    // Safety fallback\n    if (!validateRects(bestGlobal.rects)) {\n        if (validateRects(bestInit.rects)) {\n            bestGlobal = bestInit;\n        } else {\n            vector<Rect> safe(n);\n            for (int i = 0; i < n; ++i) safe[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n            bestGlobal = makeState(safe);\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& rc = bestGlobal.rects[i];\n        cout << rc.l << ' ' << rc.b << ' ' << rc.r << ' ' << rc.t << '\\n';\n    }\n\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 N = H * W;\nstatic constexpr int MAXT = 2500;\nstatic constexpr int WORDS = (MAXT + 63) / 64; // 40\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) { // inclusive\n        return l + int(next_u64() % uint64_t(r - l + 1));\n    }\n};\n\nstruct Policy {\n    double wVal, wLook, wDeg, wPair, wRand, eps, deadPenalty;\n};\n\nstruct RunParam {\n    Policy pol;\n    int evalRollouts;   // 1..3\n    int evalDepth;      // <=0 => full playout to dead-end\n    double mixBest;     // 0..1\n    double evalNoise;\n};\n\nstruct Result {\n    long long score = LLONG_MIN;\n    string path;\n};\n\nint tileId[N], pval[N], pairLoss[N];\nint degCell[N];\nint nxtCell[N][4];\nchar nxtDir[N][4];\nint nextAll[N][4];\nint M, startCell;\n\ninline bool bit_get(const uint64_t* bs, int t) {\n    return (bs[t >> 6] >> (t & 63)) & 1ULL;\n}\ninline void bit_set(uint64_t* bs, int t) {\n    bs[t >> 6] |= 1ULL << (t & 63);\n}\ninline void bit_clear_all(uint64_t* bs) {\n    memset(bs, 0, sizeof(uint64_t) * WORDS);\n}\n\ninline int charToDir(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\ninline int gatherMoves(int cur, const uint64_t* vis, int outCands[4], char outDirs[4]) {\n    int nc = 0;\n    for (int k = 0; k < degCell[cur]; k++) {\n        int to = nxtCell[cur][k];\n        if (!bit_get(vis, tileId[to])) {\n            outCands[nc] = to;\n            outDirs[nc] = nxtDir[cur][k];\n            nc++;\n        }\n    }\n    return nc;\n}\n\n// return index in [0, nc)\ninline int selectByPolicy(const int cands[4], int nc, const uint64_t* vis, const Policy& pol, XorShift64& rng) {\n    if (nc == 1) return 0;\n    if (rng.next_double() < pol.eps) return rng.next_int(0, nc - 1);\n\n    double bestScore = -1e100;\n    int bestIdx = 0;\n\n    for (int i = 0; i < nc; i++) {\n        int v = cands[i];\n        int degNext = 0;\n        int bestNextVal = 0;\n\n        for (int k = 0; k < degCell[v]; k++) {\n            int u = nxtCell[v][k];\n            if (!bit_get(vis, tileId[u])) {\n                degNext++;\n                if (pval[u] > bestNextVal) bestNextVal = pval[u];\n            }\n        }\n\n        double s = pol.wVal * pval[v]\n                 + pol.wLook * bestNextVal\n                 - pol.wDeg * degNext\n                 - pol.wPair * pairLoss[v]\n                 + pol.wRand * rng.next_double();\n\n        if (degNext == 0) s -= pol.deadPenalty;\n\n        if (s > bestScore + 1e-12) {\n            bestScore = s;\n            bestIdx = i;\n        } else if (fabs(s - bestScore) <= 1e-12) {\n            if (rng.next_u64() & 1ULL) bestIdx = i;\n        }\n    }\n    return bestIdx;\n}\n\nint playoutGain(\n    int cur,\n    uint64_t* vis,\n    const Policy& pol,\n    XorShift64& rng,\n    int maxDepth,\n    const chrono::steady_clock::time_point& deadline\n) {\n    int gain = 0;\n    int step = 0;\n\n    while (true) {\n        if (maxDepth > 0 && step >= maxDepth) break;\n\n        int cands[4];\n        char dirs[4];\n        int nc = gatherMoves(cur, vis, cands, dirs);\n        if (nc == 0) break;\n\n        int idx = selectByPolicy(cands, nc, vis, pol, rng);\n        int nxt = cands[idx];\n\n        bit_set(vis, tileId[nxt]);\n        cur = nxt;\n        gain += pval[cur];\n        step++;\n\n        if ((step & 63) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n    }\n\n    return gain;\n}\n\nResult simulate(\n    const RunParam& rp,\n    const string* basePath,\n    int cut,\n    XorShift64& rng,\n    const chrono::steady_clock::time_point& deadline\n) {\n    Result res;\n    uint64_t vis[WORDS];\n    bit_clear_all(vis);\n\n    string path;\n    path.reserve(2600);\n\n    int cur = startCell;\n    long long score = pval[cur];\n    bit_set(vis, tileId[cur]);\n\n    // Replay prefix from elite path (if any)\n    if (basePath && cut > 0) {\n        int L = min<int>(cut, basePath->size());\n        for (int i = 0; i < L; i++) {\n            int d = charToDir((*basePath)[i]);\n            if (d < 0) break;\n            int to = nextAll[cur][d];\n            if (to < 0) break;\n            if (bit_get(vis, tileId[to])) break;\n\n            path.push_back((*basePath)[i]);\n            cur = to;\n            bit_set(vis, tileId[cur]);\n            score += pval[cur];\n        }\n    }\n\n    int stepMain = 0;\n    while (true) {\n        if ((stepMain & 31) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n\n        int cands[4];\n        char dirs[4];\n        int nc = gatherMoves(cur, vis, cands, dirs);\n        if (nc == 0) break;\n\n        int pickIdx = 0;\n\n        if (nc == 1) {\n            pickIdx = 0;\n        } else {\n            if (chrono::steady_clock::now() >= deadline) {\n                pickIdx = selectByPolicy(cands, nc, vis, rp.pol, rng);\n            } else {\n                double bestEval = -1e100;\n                pickIdx = 0;\n\n                for (int i = 0; i < nc; i++) {\n                    int cand = cands[i];\n                    long long sumGain = 0;\n                    long long bestGain = LLONG_MIN;\n                    int done = 0;\n\n                    for (int r = 0; r < rp.evalRollouts; r++) {\n                        if ((r & 1) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n                        uint64_t vis2[WORDS];\n                        memcpy(vis2, vis, sizeof(vis2));\n                        bit_set(vis2, tileId[cand]);\n\n                        uint64_t mixSeed = rng.next_u64();\n                        mixSeed ^= (uint64_t)cand * 11995408973635179863ULL;\n                        mixSeed ^= (uint64_t)(r + 1) * 10150724397891781847ULL;\n                        XorShift64 rr(mixSeed);\n\n                        long long g = pval[cand];\n                        g += playoutGain(cand, vis2, rp.pol, rr, rp.evalDepth, deadline);\n\n                        sumGain += g;\n                        if (g > bestGain) bestGain = g;\n                        done++;\n                    }\n\n                    double ev;\n                    if (done == 0) {\n                        // fallback static heuristic\n                        int degNext = 0;\n                        int bestNextVal = 0;\n                        for (int k = 0; k < degCell[cand]; k++) {\n                            int u = nxtCell[cand][k];\n                            if (!bit_get(vis, tileId[u])) {\n                                degNext++;\n                                bestNextVal = max(bestNextVal, pval[u]);\n                            }\n                        }\n                        ev = 2.0 * pval[cand] + 0.8 * bestNextVal - 6.0 * degNext - 0.2 * pairLoss[cand];\n                    } else {\n                        double avg = (double)sumGain / (double)done;\n                        ev = (1.0 - rp.mixBest) * avg + rp.mixBest * (double)bestGain;\n\n                        // tiny static tie-break\n                        int degNext = 0;\n                        for (int k = 0; k < degCell[cand]; k++) {\n                            int u = nxtCell[cand][k];\n                            if (!bit_get(vis, tileId[u])) degNext++;\n                        }\n                        ev += 0.10 * pval[cand] - 0.8 * degNext - 0.03 * pairLoss[cand];\n                        ev += rp.evalNoise * rng.next_double();\n                    }\n\n                    if (ev > bestEval + 1e-9) {\n                        bestEval = ev;\n                        pickIdx = i;\n                    } else if (fabs(ev - bestEval) <= 1e-9) {\n                        if (rng.next_u64() & 1ULL) pickIdx = i;\n                    }\n                }\n            }\n        }\n\n        int nxt = cands[pickIdx];\n        path.push_back(dirs[pickIdx]);\n        cur = nxt;\n        bit_set(vis, tileId[cur]);\n        score += pval[cur];\n        stepMain++;\n    }\n\n    res.score = score;\n    res.path = std::move(path);\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    if (!(cin >> si >> sj)) return 0;\n\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x;\n            cin >> x;\n            tileId[i * W + j] = x;\n            maxTile = max(maxTile, x);\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[i * W + j];\n        }\n    }\n\n    startCell = si * W + sj;\n\n    // tile -> cells (1 or 2)\n    vector<int> c1(M, -1), c2(M, -1);\n    for (int v = 0; v < N; v++) {\n        int t = tileId[v];\n        if (c1[t] == -1) c1[t] = v;\n        else c2[t] = v;\n    }\n\n    // pair loss\n    for (int v = 0; v < N; v++) pairLoss[v] = 0;\n    for (int t = 0; t < M; t++) {\n        if (c1[t] != -1 && c2[t] != -1) {\n            int a = c1[t], b = c2[t];\n            pairLoss[a] = max(0, pval[b] - pval[a]);\n            pairLoss[b] = max(0, pval[a] - pval[b]);\n        }\n    }\n\n    // build adjacency\n    for (int v = 0; v < N; v++) {\n        degCell[v] = 0;\n        for (int d = 0; d < 4; d++) nextAll[v][d] = -1;\n    }\n\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    const char dc[4] = {'U', 'D', 'L', 'R'};\n\n    auto inside = [&](int r, int c) {\n        return (0 <= r && r < H && 0 <= c && c < W);\n    };\n\n    for (int r = 0; r < H; r++) {\n        for (int c = 0; c < W; c++) {\n            int v = r * W + c;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + di[d], nc = c + dj[d];\n                if (!inside(nr, nc)) continue;\n                int to = nr * W + nc;\n                nextAll[v][d] = to;\n\n                if (tileId[to] != tileId[v]) {\n                    int k = degCell[v]++;\n                    nxtCell[v][k] = to;\n                    nxtDir[v][k] = dc[d];\n                }\n            }\n        }\n    }\n\n    using Clock = chrono::steady_clock;\n    auto deadline = Clock::now() + chrono::milliseconds(1920);\n\n    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)startCell * 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < N; i += 53) {\n        seed ^= (uint64_t)(tileId[i] + 131 * pval[i] + i * 17) * 0xbf58476d1ce4e5b9ULL;\n        seed = (seed << 7) | (seed >> 57);\n    }\n    XorShift64 rng(seed);\n\n    auto randomParam = [&](XorShift64& rr) -> RunParam {\n        RunParam rp;\n        rp.pol.wVal = 0.8 + 1.8 * rr.next_double();\n        rp.pol.wLook = 0.0 + 1.4 * rr.next_double();\n        rp.pol.wDeg = 0.4 + 5.0 * rr.next_double();\n        rp.pol.wPair = 0.0 + 1.8 * rr.next_double();\n        rp.pol.wRand = 0.0 + 10.0 * rr.next_double();\n        rp.pol.eps = 0.00 + 0.12 * rr.next_double();\n        rp.pol.deadPenalty = 0.0 + 28.0 * rr.next_double();\n\n        double q = rr.next_double();\n        if (q < 0.70) rp.evalRollouts = 1;\n        else if (q < 0.95) rp.evalRollouts = 2;\n        else rp.evalRollouts = 3;\n\n        // pilot style mostly full playout\n        if (rr.next_double() < 0.75) rp.evalDepth = 0;\n        else rp.evalDepth = 60 + rr.next_int(0, 140);\n\n        rp.mixBest = 0.35 + 0.60 * rr.next_double();\n        rp.evalNoise = 0.0 + 60.0 * rr.next_double();\n        return rp;\n    };\n\n    // baseline\n    RunParam base;\n    base.pol = Policy{1.4, 0.8, 2.8, 0.5, 2.0, 0.02, 14.0};\n    base.evalRollouts = 2;\n    base.evalDepth = 0;  // full\n    base.mixBest = 0.65;\n    base.evalNoise = 0.0;\n\n    Result best = simulate(base, nullptr, 0, rng, deadline);\n\n    vector<Result> elites;\n    elites.push_back(best);\n\n    auto better = [](const Result& a, const Result& b) {\n        if (a.score != b.score) return a.score > b.score;\n        return a.path.size() > b.path.size();\n    };\n\n    auto pushElite = [&](Result&& r) {\n        elites.push_back(std::move(r));\n        sort(elites.begin(), elites.end(), better);\n\n        vector<Result> tmp;\n        tmp.reserve(elites.size());\n        for (auto& e : elites) {\n            bool dup = false;\n            for (auto& f : tmp) {\n                if (e.path == f.path) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) tmp.push_back(std::move(e));\n        }\n        elites.swap(tmp);\n\n        const int K = 8;\n        if ((int)elites.size() > K) elites.resize(K);\n    };\n\n    while (Clock::now() < deadline) {\n        RunParam rp = randomParam(rng);\n\n        const string* basePath = nullptr;\n        int cut = 0;\n\n        if (!elites.empty() && rng.next_double() < 0.72) {\n            int top = min<int>((int)elites.size(), 5);\n            double rsel = rng.next_double();\n            int idx = int(rsel * rsel * top);\n            if (idx >= top) idx = top - 1;\n\n            basePath = &elites[idx].path;\n            int L = (int)basePath->size();\n            if (L > 0) {\n                double rc = rng.next_double();\n                if (rc < 0.55) {\n                    int lo = max(0, L - 220);\n                    cut = rng.next_int(lo, L);\n                } else if (rc < 0.88) {\n                    int lo = max(0, L - 700);\n                    cut = rng.next_int(lo, L);\n                } else {\n                    cut = rng.next_int(0, L);\n                }\n            }\n        }\n\n        Result cur = simulate(rp, basePath, cut, rng, deadline);\n\n        if (better(cur, best)) best = cur;\n        pushElite(std::move(cur));\n    }\n\n    cout << best.path << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr int Q = 1000;\n\n    static constexpr double COST_MIN = 1000.0;\n    static constexpr double COST_MAX = 9000.0;\n\n    static constexpr double PRIOR_CNT = 1.0;\n    static constexpr double DELTA_CLIP = 4200.0;\n\n    static constexpr int WARMUP_MONO = 45;\n    static constexpr int REFIT_INTERVAL = 20;\n\n    using HMatD = array<array<double, N - 1>, N>;\n    using VMatD = array<array<double, N>, N - 1>;\n    using HMatI = array<array<int, N - 1>, N>;\n    using VMatI = array<array<int, N>, N - 1>;\n\n    struct EdgeRef {\n        bool horiz; // true: H edge, false: V edge\n        int i, j;\n    };\n\n    struct FitInfo {\n        double mean1 = 5000.0;\n        int split = -1; // 1..28\n        double meanL = 5000.0;\n        double meanR = 5000.0;\n        double ratio = 0.0; // (sse1 - sse2) / sse1\n        double diff = 0.0;  // |meanL - meanR|\n        int cLeft = 0;\n        int cRight = 0;\n    };\n\n    // Base model (piecewise line parameters)\n    array<double, N> row0{}, row1{}, col0{}, col1{};\n    array<int, N> rowSplit{}, colSplit{}; // split=29 => effectively 1 segment\n\n    // Local residuals\n    HMatD deltaH{};\n    VMatD deltaV{};\n\n    // Visit counts\n    HMatI cntH{};\n    VMatI cntV{};\n\n    bool m2Likely = false;\n\n    mt19937 rng;\n    uniform_real_distribution<double> urd;\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 int vid(int i, int j) { return i * N + j; }\n\n    double rndSym() {\n        return urd(rng) * 2.0 - 1.0;\n    }\n\n    inline double baseH(int i, int j) const {\n        return (j < rowSplit[i]) ? row0[i] : row1[i];\n    }\n\n    inline double baseV(int i, int j) const {\n        return (i < colSplit[j]) ? col0[j] : col1[j];\n    }\n\n    inline double edgeEstH(int i, int j) const {\n        double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n        double c = baseH(i, j) + sh * deltaH[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    inline double edgeEstV(int i, int j) const {\n        double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n        double c = baseV(i, j) + sh * deltaV[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    string directPath(int si, int sj, int ti, int tj) const {\n        string p;\n        if (ti > si) p.append(ti - si, 'D');\n        else p.append(si - ti, 'U');\n        if (tj > sj) p.append(tj - sj, 'R');\n        else p.append(sj - tj, 'L');\n        return p;\n    }\n\n    void buildCostTables(int q, HMatD& baseHMat, VMatD& baseVMat, HMatD& searchHMat, VMatD& searchVMat) {\n        double stepPenalty = (q < 140) ? (180.0 * (140 - q) / 140.0) : 0.0;\n        double bonusCoef = (q < 240) ? (360.0 * (240 - q) / 240.0) : 0.0;\n        double jitter = (q < 220) ? (0.025 * (220 - q) / 220.0) : 0.0;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                double b = edgeEstH(i, j);\n                baseHMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntH[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchHMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                double b = edgeEstV(i, j);\n                baseVMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntV[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchVMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n    }\n\n    string dijkstraPath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        constexpr double INF = 1e100;\n        array<double, N * N> dist;\n        array<int, N * N> prv;\n        array<char, N * N> pmv;\n        dist.fill(INF);\n        prv.fill(-1);\n        pmv.fill(0);\n\n        int S = vid(si, sj), T = vid(ti, tj);\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[S] = 0.0;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == T) break;\n\n            int i = u / N, j = u % N;\n\n            if (i > 0) {\n                int to = vid(i - 1, j);\n                double nd = d + v[i - 1][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'U';\n                    pq.push({nd, to});\n                }\n            }\n            if (i + 1 < N) {\n                int to = vid(i + 1, j);\n                double nd = d + v[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'D';\n                    pq.push({nd, to});\n                }\n            }\n            if (j > 0) {\n                int to = vid(i, j - 1);\n                double nd = d + h[i][j - 1];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'L';\n                    pq.push({nd, to});\n                }\n            }\n            if (j + 1 < N) {\n                int to = vid(i, j + 1);\n                double nd = d + h[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'R';\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        if (prv[T] == -1) return directPath(si, sj, ti, tj);\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmv[cur]);\n            cur = prv[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Best among monotone-only paths (length = Manhattan)\n    string bestMonotoneDP(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        if (si == ti && sj == tj) return \"\";\n\n        int di = (ti > si) ? 1 : (ti < si ? -1 : 0);\n        int dj = (tj > sj) ? 1 : (tj < sj ? -1 : 0);\n\n        int R = abs(ti - si) + 1;\n        int C = abs(tj - sj) + 1;\n\n        const double INF = 1e100;\n        vector<vector<double>> dp(R, vector<double>(C, INF));\n        vector<vector<char>> pre(R, vector<char>(C, 0));\n        dp[0][0] = 0.0;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = 0; b < C; b++) {\n                if (dp[a][b] >= INF / 2) continue;\n                int i = si + di * a;\n                int j = sj + dj * b;\n\n                if (a + 1 < R) {\n                    double w = (di == 1) ? v[i][j] : v[i - 1][j];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a + 1][b]) {\n                        dp[a + 1][b] = nd;\n                        pre[a + 1][b] = 'V';\n                    }\n                }\n                if (b + 1 < C) {\n                    double w = (dj == 1) ? h[i][j] : h[i][j - 1];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a][b + 1]) {\n                        dp[a][b + 1] = nd;\n                        pre[a][b + 1] = 'H';\n                    }\n                }\n            }\n        }\n\n        string path;\n        int a = R - 1, b = C - 1;\n        while (a > 0 || b > 0) {\n            char p = pre[a][b];\n            if (p == 'V') {\n                path.push_back(di == 1 ? 'D' : 'U');\n                --a;\n            } else {\n                path.push_back(dj == 1 ? 'R' : 'L');\n                --b;\n            }\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Warmup monotone exploration\n    string biasedMonotonePath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) {\n        int i = si, j = sj;\n        string path;\n        path.reserve(abs(ti - si) + abs(tj - sj));\n\n        while (i != ti || j != tj) {\n            bool canV = (i != ti);\n            bool canH = (j != tj);\n\n            if (canV && canH) {\n                double cv, ch;\n                int nv, nh;\n\n                if (ti > i) { // D\n                    cv = v[i][j];\n                    nv = cntV[i][j];\n                } else {      // U\n                    cv = v[i - 1][j];\n                    nv = cntV[i - 1][j];\n                }\n\n                if (tj > j) { // R\n                    ch = h[i][j];\n                    nh = cntH[i][j];\n                } else {      // L\n                    ch = h[i][j - 1];\n                    nh = cntH[i][j - 1];\n                }\n\n                double sv = (1.0 / (cv + 1e-9)) * (1.0 + 1.2 / sqrt(nv + 1.0));\n                double sh = (1.0 / (ch + 1e-9)) * (1.0 + 1.2 / sqrt(nh + 1.0));\n\n                double r = urd(rng) * (sv + sh);\n                if (r < sv) {\n                    if (ti > i) { path.push_back('D'); ++i; }\n                    else { path.push_back('U'); --i; }\n                } else {\n                    if (tj > j) { path.push_back('R'); ++j; }\n                    else { path.push_back('L'); --j; }\n                }\n            } else if (canV) {\n                if (ti > i) { path.push_back('D'); ++i; }\n                else { path.push_back('U'); --i; }\n            } else {\n                if (tj > j) { path.push_back('R'); ++j; }\n                else { path.push_back('L'); --j; }\n            }\n        }\n\n        return path;\n    }\n\n    void pathToEdges(\n        int si, int sj, const string& path, vector<EdgeRef>& edges,\n        array<int, N>& row0Cnt, array<int, N>& row1Cnt,\n        array<int, N>& col0Cnt, array<int, N>& col1Cnt\n    ) const {\n        row0Cnt.fill(0);\n        row1Cnt.fill(0);\n        col0Cnt.fill(0);\n        col1Cnt.fill(0);\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int i = si, j = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                --i;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                ++i;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                --j;\n            } else { // 'R'\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                ++j;\n            }\n        }\n    }\n\n    FitInfo fitLine29(const array<double, N - 1>& val, const array<int, N - 1>& cnt) const {\n        const double W0 = 0.35;\n\n        array<double, N> pw{}, ps{}, ps2{};\n        array<int, N> pc{};\n        for (int k = 0; k < N - 1; k++) {\n            double w = cnt[k] + W0;\n            double x = val[k];\n            pw[k + 1] = pw[k] + w;\n            ps[k + 1] = ps[k] + w * x;\n            ps2[k + 1] = ps2[k] + w * x * x;\n            pc[k + 1] = pc[k] + cnt[k];\n        }\n\n        FitInfo f;\n\n        double W = pw[N - 1];\n        double S = ps[N - 1];\n        double Qv = ps2[N - 1];\n        if (W <= 1e-12) {\n            f.mean1 = 5000.0;\n            return f;\n        }\n\n        f.mean1 = S / W;\n        double sse1 = max(0.0, Qv - S * S / W);\n\n        double bestSSE = 1e100;\n        int bestS = -1;\n        double bestL = f.mean1, bestR = f.mean1;\n\n        for (int s = 1; s <= N - 2; s++) { // 1..28\n            double WL = pw[s], WR = pw[N - 1] - pw[s];\n            if (WL <= 1e-12 || WR <= 1e-12) continue;\n\n            double SL = ps[s], SR = ps[N - 1] - ps[s];\n            double QL = ps2[s], QR = ps2[N - 1] - ps2[s];\n\n            double mL = SL / WL, mR = SR / WR;\n            double sse = max(0.0, QL - SL * SL / WL) + max(0.0, QR - SR * SR / WR);\n\n            if (sse < bestSSE) {\n                bestSSE = sse;\n                bestS = s;\n                bestL = mL;\n                bestR = mR;\n            }\n        }\n\n        f.split = bestS;\n        if (bestS == -1) {\n            f.meanL = f.meanR = f.mean1;\n            f.ratio = 0.0;\n            f.diff = 0.0;\n            return f;\n        }\n\n        f.meanL = bestL;\n        f.meanR = bestR;\n        f.diff = fabs(bestL - bestR);\n        f.cLeft = pc[bestS];\n        f.cRight = pc[N - 1] - pc[bestS];\n        f.ratio = (sse1 - bestSSE) / max(1.0, sse1);\n        if (f.ratio < 0.0) f.ratio = 0.0;\n\n        return f;\n    }\n\n    void refitStructure(int q) {\n        // 1) Current effective estimates\n        HMatD effH;\n        VMatD effV;\n        for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) effH[i][j] = edgeEstH(i, j);\n        for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) effV[i][j] = edgeEstV(i, j);\n\n        // 2) Fit each row/column as 1-seg vs best 2-seg\n        array<FitInfo, N> rowFit, colFit;\n\n        for (int i = 0; i < N; i++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int j = 0; j < N - 1; j++) {\n                val[j] = effH[i][j];\n                cnt[j] = cntH[i][j];\n            }\n            rowFit[i] = fitLine29(val, cnt);\n        }\n\n        for (int j = 0; j < N; j++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int i = 0; i < N - 1; i++) {\n                val[i] = effV[i][j];\n                cnt[i] = cntV[i][j];\n            }\n            colFit[j] = fitLine29(val, cnt);\n        }\n\n        // 3) Infer whether M=2 is likely globally\n        int strong = 0, considered = 0;\n        auto countStrong = [&](const FitInfo& f) {\n            if (f.split < 1 || f.split > N - 2) return;\n            int mc = min(f.cLeft, f.cRight);\n            if (mc < 5) return;\n            considered++;\n            if (f.ratio > 0.09 && f.diff > 500.0) strong++;\n        };\n        for (int i = 0; i < N; i++) countStrong(rowFit[i]);\n        for (int j = 0; j < N; j++) countStrong(colFit[j]);\n\n        if (q >= 70 && considered >= 20) {\n            if (strong >= 18) m2Likely = true;\n            else if (strong <= 8) m2Likely = false;\n        }\n\n        auto useTwoSeg = [&](const FitInfo& f) -> bool {\n            if (f.split < 1 || f.split > N - 2) return false;\n            if (q < 55) return false;\n            int mc = min(f.cLeft, f.cRight);\n\n            if (m2Likely) {\n                double thrRatio = (q < 220) ? 0.07 : 0.045;\n                double thrDiff = (q < 220) ? 450.0 : 300.0;\n                int thrCnt = (q < 220) ? 5 : 3;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            } else {\n                // strict mode for likely M=1, but allow very strong evidence\n                if (f.ratio > 0.22 && f.diff > 1200.0 && mc >= 8) return true;\n                double thrRatio = (q < 320) ? 0.16 : 0.12;\n                double thrDiff = (q < 320) ? 800.0 : 650.0;\n                int thrCnt = (q < 320) ? 10 : 7;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            }\n        };\n\n        // 4) Update base model\n        for (int i = 0; i < N; i++) {\n            const auto& f = rowFit[i];\n            if (useTwoSeg(f)) {\n                rowSplit[i] = f.split;\n                row0[i] = clampd(f.meanL, COST_MIN, COST_MAX);\n                row1[i] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                rowSplit[i] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                row0[i] = m;\n                row1[i] = m;\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            const auto& f = colFit[j];\n            if (useTwoSeg(f)) {\n                colSplit[j] = f.split;\n                col0[j] = clampd(f.meanL, COST_MIN, COST_MAX);\n                col1[j] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                colSplit[j] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                col0[j] = m;\n                col1[j] = m;\n            }\n        }\n\n        // 5) Re-center local residuals around the new base\n        //    (trusted edges mostly preserved; low-count edges pulled to new base)\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                if (cntH[i][j] == 0) {\n                    deltaH[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseH(i, j);\n                double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaH[i][j] = clampd((effH[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                if (cntV[i][j] == 0) {\n                    deltaV[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseV(i, j);\n                double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaV[i][j] = clampd((effV[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n    }\n\npublic:\n    Solver() : rng(20240315), urd(0.0, 1.0) {\n        row0.fill(5000.0);\n        row1.fill(5000.0);\n        col0.fill(5000.0);\n        col1.fill(5000.0);\n        rowSplit.fill(N - 1);\n        colSplit.fill(N - 1);\n\n        for (auto& r : deltaH) r.fill(0.0);\n        for (auto& r : deltaV) r.fill(0.0);\n        for (auto& r : cntH) r.fill(0);\n        for (auto& r : cntV) r.fill(0);\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int q = 0; q < Q; q++) {\n            if (q > 0 && q % REFIT_INTERVAL == 0) {\n                refitStructure(q);\n            }\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            HMatD baseHMat, searchHMat;\n            VMatD baseVMat, searchVMat;\n            buildCostTables(q, baseHMat, baseVMat, searchHMat, searchVMat);\n\n            string path;\n            if (q < WARMUP_MONO) {\n                path = biasedMonotonePath(si, sj, ti, tj, baseHMat, baseVMat);\n            } else {\n                path = dijkstraPath(si, sj, ti, tj, searchHMat, searchVMat);\n\n                int md = abs(si - ti) + abs(sj - tj);\n                int detourLimit = (q < 200) ? 10 : 16;\n                if ((int)path.size() > md + detourLimit) {\n                    path = bestMonotoneDP(si, sj, ti, tj, baseHMat, baseVMat);\n                }\n            }\n\n            cout << path << '\\n' << flush;\n\n            int obsInt;\n            if (!(cin >> obsInt)) return;\n            if (obsInt < 0) return; // interactive guard\n            double obs = static_cast<double>(obsInt);\n\n            vector<EdgeRef> edges;\n            array<int, N> row0Cnt, row1Cnt, col0Cnt, col1Cnt;\n            pathToEdges(si, sj, path, edges, row0Cnt, row1Cnt, col0Cnt, col1Cnt);\n\n            if (edges.empty()) continue;\n\n            // Prediction before update\n            double pred = 0.0;\n            for (const auto& e : edges) {\n                pred += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double err = obs - pred;\n\n            // Segment-level base update\n            double norm = 1e-9;\n            for (int i = 0; i < N; i++) {\n                norm += 1.0 * row0Cnt[i] * row0Cnt[i];\n                norm += 1.0 * row1Cnt[i] * row1Cnt[i];\n            }\n            for (int j = 0; j < N; j++) {\n                norm += 1.0 * col0Cnt[j] * col0Cnt[j];\n                norm += 1.0 * col1Cnt[j] * col1Cnt[j];\n            }\n\n            double etaBase = 0.40 * exp(-0.0022 * q) + 0.06;\n\n            for (int i = 0; i < N; i++) {\n                if (row0Cnt[i]) {\n                    row0[i] += etaBase * err * row0Cnt[i] / norm;\n                    row0[i] = clampd(row0[i], COST_MIN, COST_MAX);\n                }\n                if (row1Cnt[i]) {\n                    row1[i] += etaBase * err * row1Cnt[i] / norm;\n                    row1[i] = clampd(row1[i], COST_MIN, COST_MAX);\n                }\n            }\n            for (int j = 0; j < N; j++) {\n                if (col0Cnt[j]) {\n                    col0[j] += etaBase * err * col0Cnt[j] / norm;\n                    col0[j] = clampd(col0[j], COST_MIN, COST_MAX);\n                }\n                if (col1Cnt[j]) {\n                    col1[j] += etaBase * err * col1Cnt[j] / norm;\n                    col1[j] = clampd(col1[j], COST_MIN, COST_MAX);\n                }\n            }\n\n            // Residual after base update\n            double pred2 = 0.0;\n            for (const auto& e : edges) {\n                pred2 += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double residual = obs - pred2;\n\n            // Local residual update (uncertainty weighted)\n            double etaDelta = 0.60 * exp(-0.0015 * q) + 0.18;\n\n            vector<double> w(edges.size());\n            double sw = 0.0;\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                int c = e.horiz ? cntH[e.i][e.j] : cntV[e.i][e.j];\n                w[idx] = 1.0 / sqrt(c + 1.0);\n                sw += w[idx];\n            }\n            if (sw < 1e-12) sw = 1.0;\n\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                double d = etaDelta * residual * w[idx] / sw;\n                if (e.horiz) {\n                    deltaH[e.i][e.j] = clampd(deltaH[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntH[e.i][e.j]++;\n                } else {\n                    deltaV[e.i][e.j] = clampd(deltaV[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntV[e.i][e.j]++;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M;\n    int CELL, PPS, P;\n\n    vector<vector<uint8_t>> strs;\n    vector<uint8_t> len;\n    vector<int> groupLen;\n\n    // For each cell, entries are grouped by sid.\n    // packed = (pid << 3) | reqChar(0..7)\n    vector<vector<uint32_t>> cellEntries;\n\n    vector<int16_t> matchCount;       // per placement\n    vector<array<int, 13>> hist;      // per string, distribution of matchCount\n    vector<uint8_t> best;             // best matchCount per string\n\n    // Exact c-phase\n    vector<int> fullCnt;              // #full-matched placements per string\n    int cCur = 0;                     // #strings with fullCnt>0\n\n    vector<uint8_t> grid;\n    vector<uint8_t> bestGrid;\n\n    int bestC = -1;\n    int bestSoft = -1;\n\n    int g1[13];                       // 2^x for smooth objective\n    int scoreTbl[13][13];             // phase2 score table\n\n    vector<int> order;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 2.90;\n\n    Solver(int N_, int M_, const vector<string>& S): N(N_), M(M_) {\n        CELL = N * N;\n        PPS = 2 * CELL;\n        P = M * PPS;\n\n        strs.resize(M);\n        len.resize(M);\n        groupLen.resize(M);\n\n        for (int i = 0; i < M; i++) {\n            len[i] = (uint8_t)S[i].size();\n            groupLen[i] = 2 * (int)len[i];\n            strs[i].resize(len[i]);\n            for (int j = 0; j < (int)len[i]; j++) strs[i][j] = (uint8_t)(S[i][j] - 'A');\n        }\n\n        cellEntries.assign(CELL, {});\n        buildEntries();\n\n        matchCount.assign(P, 0);\n        hist.resize(M);\n        for (auto &a : hist) a.fill(0);\n        best.assign(M, 0);\n\n        fullCnt.assign(M, 0);\n\n        grid.assign(CELL, 0);\n        bestGrid.assign(CELL, 0);\n\n        order.resize(CELL);\n        iota(order.begin(), order.end(), 0);\n\n        g1[0] = 1;\n        for (int i = 1; i <= 12; i++) g1[i] = g1[i - 1] << 1;\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        seed ^= (uint64_t)P * 1009ULL;\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline int randInt(int l, int r) {\n        return l + (int)(rng() % (uint32_t)(r - l + 1));\n    }\n\n    void buildEntries() {\n        int perCell = 0;\n        for (int i = 0; i < M; i++) perCell += groupLen[i];\n        for (int c = 0; c < CELL; c++) cellEntries[c].reserve(perCell);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            int k = len[sid];\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    int start = r * N + c;\n                    int pidH = base + start;\n                    int pidV = base + CELL + start;\n                    for (int p = 0; p < k; p++) {\n                        uint32_t req = strs[sid][p];\n                        int ch = r * N + ((c + p) % N);\n                        int cv = ((r + p) % N) * N + c;\n                        cellEntries[ch].push_back((uint32_t(pidH) << 3) | req);\n                        cellEntries[cv].push_back((uint32_t(pidV) << 3) | req);\n                    }\n                }\n            }\n        }\n    }\n\n    void initRandom() {\n        for (int i = 0; i < CELL; i++) grid[i] = (uint8_t)(rng() & 7);\n    }\n\n    void initFromBest() {\n        grid = bestGrid;\n\n        int mut;\n        if (bestC >= (int)(0.75 * M)) mut = randInt(6, 24);\n        else if (bestC >= (int)(0.60 * M)) mut = randInt(10, 40);\n        else mut = randInt(20, 80);\n\n        for (int i = 0; i < mut; i++) {\n            int cell = randInt(0, CELL - 1);\n            grid[cell] = (uint8_t)randInt(0, 7);\n        }\n\n        // Torus shift (objective invariant), diversify basin.\n        if (randInt(0, 1)) {\n            int dr = randInt(0, N - 1), dc = randInt(0, N - 1);\n            vector<uint8_t> tmp = grid;\n            for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n                int nr = (r + dr) % N, nc = (c + dc) % N;\n                grid[nr * N + nc] = tmp[r * N + c];\n            }\n        }\n        // Occasional transpose (also objective invariant).\n        if (randInt(0, 9) == 0) {\n            vector<uint8_t> tmp = grid;\n            for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n                grid[c * N + r] = tmp[r * N + c];\n            }\n        }\n    }\n\n    void recomputeMatchCount() {\n        fill(matchCount.begin(), matchCount.end(), 0);\n        for (int cell = 0; cell < CELL; cell++) {\n            int ch = grid[cell];\n            if (ch > 7) continue;\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                if ((int)(x & 7u) == ch) {\n                    int pid = (int)(x >> 3);\n                    matchCount[pid]++;\n                }\n            }\n        }\n    }\n\n    int phase1Sweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 15) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            long long bonus[8] = {0,0,0,0,0,0,0,0};\n\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n                int base = mc - ((old == req) ? 1 : 0);\n                bonus[req] += (long long)g1[base + 1] - g1[base];\n            }\n\n            int nw = old;\n            long long bestv = bonus[old];\n            int tie = 1;\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                if (bonus[a] > bestv) {\n                    bestv = bonus[a];\n                    nw = a;\n                    tie = 1;\n                } else if (bonus[a] == bestv && bonus[a] > bonus[old]) {\n                    tie++;\n                    if ((int)(rng() % tie) == 0) nw = a;\n                }\n            }\n            if (nw == old) continue;\n\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                if (req == old) matchCount[pid]--;\n                else if (req == nw) matchCount[pid]++;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildHistBest() {\n        for (int sid = 0; sid < M; sid++) hist[sid].fill(0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            for (int t = 0; t < PPS; t++) {\n                int mc = matchCount[base + t];\n                hist[sid][mc]++;\n            }\n        }\n\n        for (int sid = 0; sid < M; sid++) {\n            int b = len[sid];\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    inline int calcC() const {\n        int c = 0;\n        for (int sid = 0; sid < M; sid++) if (best[sid] == len[sid]) c++;\n        return c;\n    }\n    inline int calcSoft() const {\n        int s = 0;\n        for (int sid = 0; sid < M; sid++) s += best[sid];\n        return s;\n    }\n\n    void updateGlobal() {\n        int c = calcC();\n        int soft = calcSoft();\n        if (c > bestC || (c == bestC && soft > bestSoft)) {\n            bestC = c;\n            bestSoft = soft;\n            bestGrid = grid;\n        }\n    }\n\n    void updateGlobalByCOnly() {\n        if (cCur > bestC) {\n            bestC = cCur;\n            bestSoft = -1;\n            bestGrid = grid;\n        }\n    }\n\n    void buildScoreTbl(int fullBonus) {\n        for (int k = 0; k <= 12; k++) {\n            for (int b = 0; b <= 12; b++) {\n                if (b > k) scoreTbl[k][b] = -1000000000;\n                else scoreTbl[k][b] = b * b + ((b == k) ? fullBonus : 0);\n            }\n        }\n    }\n\n    pair<int, long long> chooseLetterPhase2(int cell) {\n        int old = grid[cell];\n        long long delta[8] = {0,0,0,0,0,0,0,0};\n\n        const auto &vec = cellEntries[cell];\n        int pos = 0;\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            int gsz = groupLen[sid];\n\n            int cnt[8][3];\n            memset(cnt, 0, sizeof(cnt));\n\n            for (int t = 0; t < gsz; t++) {\n                uint32_t x = vec[pos + t];\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n\n                if (b > 0 && mc == b - 1) cnt[req][0]++;\n                if (mc == b) cnt[req][1]++;\n                if (b < k && mc == b + 1) cnt[req][2]++;\n            }\n            pos += gsz;\n\n            int baseScore = scoreTbl[k][b];\n            int hb = hist[sid][b];\n            int hbp1 = (b < k ? hist[sid][b + 1] : 0);\n\n            int old0 = cnt[old][1];\n            int oldp1 = cnt[old][2];\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                int nb;\n\n                if (b < k) {\n                    int cb1 = hbp1 - oldp1 + cnt[a][1];\n                    if (cb1 > 0) {\n                        nb = b + 1;\n                    } else {\n                        int cb = hb - old0 + oldp1 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                        nb = (cb > 0 ? b : b - 1);\n                        if (nb < 0) nb = 0;\n                    }\n                } else {\n                    int cb = hb - old0 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                    nb = (cb > 0 ? b : b - 1);\n                    if (nb < 0) nb = 0;\n                }\n\n                delta[a] += (long long)scoreTbl[k][nb] - baseScore;\n            }\n        }\n\n        int nw = old;\n        long long bestD = 0;\n        int tie = 1;\n        for (int a = 0; a < 8; a++) {\n            if (a == old) continue;\n            if (delta[a] > bestD) {\n                bestD = delta[a];\n                nw = a;\n                tie = 1;\n            } else if (delta[a] == bestD && bestD > 0) {\n                tie++;\n                if ((int)(rng() % tie) == 0) nw = a;\n            }\n        }\n        return {nw, bestD};\n    }\n\n    int phase2Sweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 7) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            auto [nw, gain] = chooseLetterPhase2(cell);\n            if (nw == old || gain <= 0) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc + 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc + 1]++;\n                    }\n                }\n                pos += gsz;\n\n                int b = best[sid];\n                int k = len[sid];\n                if (b < k && hist[sid][b + 1] > 0) b++;\n                else if (b > 0 && hist[sid][b] == 0) b--;\n                best[sid] = (uint8_t)b;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildFullCnt() {\n        cCur = 0;\n        fill(fullCnt.begin(), fullCnt.end(), 0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int base = sid * PPS;\n            int cnt = 0;\n            for (int t = 0; t < PPS; t++) {\n                if (matchCount[base + t] == k) cnt++;\n            }\n            fullCnt[sid] = cnt;\n            if (cnt > 0) cCur++;\n        }\n    }\n\n    // Phase 3: exact c-oriented move (lexicographic: deltaC, then smooth tie-break)\n    int exactSweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 7) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n\n            int deltaC[8] = {0,0,0,0,0,0,0,0};\n            long long sm[8] = {0,0,0,0,0,0,0,0};\n\n            int pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                int k = len[sid];\n                int fc = fullCnt[sid];\n                int was = (fc > 0);\n\n                int cntF[8]  = {0,0,0,0,0,0,0,0};\n                int cntM1[8] = {0,0,0,0,0,0,0,0};\n\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n                    int mc = matchCount[pid];\n\n                    int base = mc - ((old == req) ? 1 : 0);\n                    sm[req] += (long long)g1[base + 1] - g1[base];\n\n                    if (mc == k) cntF[req]++;\n                    else if (mc == k - 1) cntM1[req]++;\n                }\n                pos += gsz;\n\n                int oldLose = cntF[old];\n                for (int a = 0; a < 8; a++) {\n                    if (a == old) continue;\n                    int newFc = fc - oldLose + cntM1[a];\n                    int now = (newFc > 0);\n                    deltaC[a] += (now - was);\n                }\n            }\n\n            int nw = old;\n            int bestDC = 0;\n            long long bestSM = 0;\n            int tie = 1;\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                if (deltaC[a] > bestDC) {\n                    bestDC = deltaC[a];\n                    bestSM = sm[a];\n                    nw = a;\n                    tie = 1;\n                } else if (deltaC[a] == bestDC) {\n                    if (sm[a] > bestSM) {\n                        bestSM = sm[a];\n                        nw = a;\n                        tie = 1;\n                    } else if (sm[a] == bestSM && (bestDC > 0 || bestSM > 0)) {\n                        tie++;\n                        if ((int)(rng() % tie) == 0) nw = a;\n                    }\n                }\n            }\n\n            if (nw == old) continue;\n            if (bestDC == 0 && bestSM <= 0) continue;\n\n            // Apply old -> nw, updating matchCount/fullCnt/cCur incrementally\n            pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                bool before = (fullCnt[sid] > 0);\n                int k = len[sid];\n                int gsz = groupLen[sid];\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        int mc = matchCount[pid];\n                        if (mc == k) fullCnt[sid]--;\n                        matchCount[pid] = (int16_t)(mc - 1);\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        if (mc == k - 1) fullCnt[sid]++;\n                        matchCount[pid] = (int16_t)(mc + 1);\n                    }\n                }\n                pos += gsz;\n\n                bool after = (fullCnt[sid] > 0);\n                if (before != after) cCur += after ? 1 : -1;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void runOne(double deadline, bool fromBest) {\n        if (fromBest && bestC >= 0) initFromBest();\n        else initRandom();\n\n        recomputeMatchCount();\n\n        int p1 = fromBest ? 2 + randInt(0, 1) : 5 + randInt(0, 1);\n        for (int i = 0; i < p1; i++) {\n            if (elapsed() >= deadline) return;\n            int ch = phase1Sweep(deadline);\n            if (ch == 0) break;\n        }\n\n        if (elapsed() >= deadline) return;\n        buildHistBest();\n        updateGlobal();\n\n        const int bonus[4] = {0, 200, 5000, 120000};\n        const int sweeps[4] = {2, 3, 3, 3};\n\n        for (int st = 0; st < 4; st++) {\n            if (elapsed() >= deadline) return;\n            buildScoreTbl(bonus[st]);\n\n            int lim = sweeps[st];\n            if (fromBest && st == 0) lim = max(1, lim - 1);\n\n            for (int it = 0; it < lim; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n        }\n\n        // Kick & recover\n        if (elapsed() < deadline - 0.07) {\n            int mut = fromBest ? randInt(6, 20) : randInt(12, 36);\n            for (int i = 0; i < mut; i++) {\n                int cell = randInt(0, CELL - 1);\n                grid[cell] = (uint8_t)randInt(0, 7);\n            }\n\n            recomputeMatchCount();\n            if (elapsed() < deadline - 0.05) phase1Sweep(deadline - 0.04);\n\n            if (elapsed() >= deadline) return;\n            buildHistBest();\n            updateGlobal();\n\n            buildScoreTbl(8000);\n            for (int it = 0; it < 2; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n\n            buildScoreTbl(180000);\n            for (int it = 0; it < 2; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n        }\n\n        // Exact c-polish\n        if (elapsed() < deadline - 0.02) {\n            buildFullCnt();\n            updateGlobalByCOnly();\n\n            int lim = fromBest ? 2 : 3;\n            for (int it = 0; it < lim; it++) {\n                if (elapsed() >= deadline) break;\n                int ch = exactSweep(deadline);\n                updateGlobalByCOnly();\n                if (ch == 0) break;\n            }\n\n            if (elapsed() < deadline) {\n                buildHistBest();\n                updateGlobal();\n            }\n        }\n    }\n\n    void dotPostprocessIfPossible() {\n        if (bestC != M) return;\n        if (elapsed() > TL - 0.03) return;\n\n        grid = bestGrid;\n        recomputeMatchCount();\n        buildHistBest();\n        if (calcC() != M) return;\n\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 15) == 0 && elapsed() > TL - 0.005) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            bool touched = false;\n\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    if (req == old) {\n                        int pid = (int)(x >> 3);\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                        touched = true;\n                    }\n                }\n                pos += gsz;\n\n                int b = best[sid];\n                int k = len[sid];\n                if (b < k && hist[sid][b + 1] > 0) b++;\n                else if (b > 0 && hist[sid][b] == 0) b--;\n                best[sid] = (uint8_t)b;\n            }\n\n            if (!touched) {\n                grid[cell] = 8;\n                continue;\n            }\n\n            if (calcC() == M) {\n                grid[cell] = 8;\n            } else {\n                // revert\n                pos = 0;\n                for (int sid = 0; sid < M; sid++) {\n                    int gsz = groupLen[sid];\n                    for (int t = 0; t < gsz; t++) {\n                        uint32_t x = vec[pos + t];\n                        int req = (int)(x & 7u);\n                        if (req == old) {\n                            int pid = (int)(x >> 3);\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc + 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc + 1]++;\n                        }\n                    }\n                    pos += gsz;\n\n                    int b = best[sid];\n                    int k = len[sid];\n                    if (b < k && hist[sid][b + 1] > 0) b++;\n                    else if (b > 0 && hist[sid][b] == 0) b--;\n                    best[sid] = (uint8_t)b;\n                }\n            }\n        }\n\n        bestGrid = grid;\n        bestSoft = calcSoft();\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        int restart = 0;\n        while (true) {\n            double now = elapsed();\n            double rem = TL - now;\n            if (rem < 0.12) break;\n\n            double budget;\n            if (restart == 0) budget = min(1.15, rem - 0.03);\n            else if (restart < 4) budget = min(0.52, rem - 0.03);\n            else budget = min(0.30, rem - 0.02);\n\n            if (budget < 0.08) break;\n\n            bool fromBest;\n            if (restart == 0 || bestC < 0) fromBest = false;\n            else if (restart % 5 == 0) fromBest = false; // forced random exploration\n            else fromBest = (randInt(0, 99) < 78);\n\n            runOne(now + budget, fromBest);\n            restart++;\n        }\n\n        if (bestC < 0) {\n            initRandom();\n            bestGrid = grid;\n            bestC = 0;\n            bestSoft = 0;\n        }\n\n        // final polish from best\n        if (elapsed() < TL - 0.03) {\n            grid = bestGrid;\n            recomputeMatchCount();\n            buildHistBest();\n            updateGlobal();\n\n            buildScoreTbl(260000);\n            bool kicked = false;\n            while (elapsed() < TL - 0.015) {\n                int ch = phase2Sweep(TL - 0.010);\n                updateGlobal();\n                if (ch == 0) {\n                    if (!kicked && elapsed() < TL - 0.05) {\n                        kicked = true;\n                        int mut = randInt(8, 24);\n                        for (int i = 0; i < mut; i++) {\n                            int cell = randInt(0, CELL - 1);\n                            grid[cell] = (uint8_t)randInt(0, 7);\n                        }\n                        recomputeMatchCount();\n                        buildHistBest();\n                        updateGlobal();\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (elapsed() < TL - 0.006) {\n                buildFullCnt();\n                updateGlobalByCOnly();\n                while (elapsed() < TL - 0.003) {\n                    int ch = exactSweep(TL - 0.002);\n                    updateGlobalByCOnly();\n                    if (ch == 0) break;\n                }\n            }\n\n            if (elapsed() < TL - 0.002) {\n                buildHistBest();\n                updateGlobal();\n            }\n        }\n\n        dotPostprocessIfPossible();\n    }\n\n    void output() const {\n        for (int r = 0; r < N; r++) {\n            string line(N, '.');\n            for (int c = 0; c < N; c++) {\n                int v = bestGrid[r * N + c];\n                line[c] = (0 <= v && v < 8) ? char('A' + v) : '.';\n            }\n            cout << line << '\\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<string> S(M);\n    for (int i = 0; i < M; i++) cin >> S[i];\n\n    Solver solver(N, M, S);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    using ull = unsigned long long;\n    static constexpr int INF = 1e9;\n\n    inline static constexpr int DI[4] = {-1, 1, 0, 0};\n    inline static constexpr int DJ[4] = {0, 0, -1, 1};\n    inline static constexpr char MV[4] = {'U', 'D', 'L', 'R'};\n    inline static constexpr int OPP[4] = {1, 0, 3, 2};\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0;\n    int startRid = -1;\n\n    vector<vector<int>> id;      // grid -> road id\n    vector<int> ri, rj;          // road id -> row,col\n    vector<int> enterCost;       // entering cost\n    vector<array<int,4>> nbr;    // neighbors by direction\n\n    int B = 0;\n    vector<ull> allBits;\n    vector<vector<ull>> roadVisBits; // road id -> visibility bitset\n    vector<int> roadVisCnt;          // popcount visibility\n\n    vector<int> candRid;             // candidate idx -> road id\n    vector<vector<ull>> candBits;    // candidate visibility bits\n    vector<vector<int>> candVisList; // candidate visibility list\n    vector<char> inCand;             // road id flag\n\n    vector<vector<int>> distC;       // candidate shortest cost (directed)\n    vector<vector<int>> symC;        // sym cost: distC[i][j] + w(i)\n    vector<vector<int>> prevFrom;    // source candidate -> predecessor road-id tree\n\n    chrono::steady_clock::time_point t0;\n\n    long long elapsed_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - t0\n        ).count();\n    }\n\n    void read_input() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void build_graph() {\n        id.assign(N, vector<int>(N, -1));\n        ri.clear(); rj.clear(); enterCost.clear();\n\n        R = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    ri.push_back(i);\n                    rj.push_back(j);\n                    enterCost.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n        startRid = id[si][sj];\n\n        nbr.assign(R, array<int,4>{-1,-1,-1,-1});\n        for (int u = 0; u < R; u++) {\n            int i = ri[u], j = rj[u];\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                    nbr[u][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void init_bits() {\n        B = (R + 63) >> 6;\n        allBits.assign(B, ~0ULL);\n        if (B > 0 && (R & 63)) allBits.back() = (1ULL << (R & 63)) - 1ULL;\n    }\n\n    void build_road_visibility() {\n        roadVisBits.assign(R, vector<ull>(B, 0ULL));\n        roadVisCnt.assign(R, 0);\n\n        for (int rid = 0; rid < R; rid++) {\n            auto &bits = roadVisBits[rid];\n\n            auto add = [&](int v) {\n                bits[v >> 6] |= (1ULL << (v & 63));\n            };\n\n            int i = ri[rid], j = rj[rid];\n            add(rid);\n\n            for (int y = j - 1; y >= 0; y--) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int y = j + 1; y < N; y++) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i - 1; x >= 0; x--) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i + 1; x < N; x++) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n\n            int cnt = 0;\n            for (int b = 0; b < B; b++) cnt += __builtin_popcountll(bits[b]);\n            roadVisCnt[rid] = cnt;\n        }\n    }\n\n    vector<int> bits_to_list(const vector<ull>& bits) const {\n        vector<int> res;\n        for (int b = 0; b < B; b++) {\n            ull x = bits[b];\n            while (x) {\n                int t = __builtin_ctzll(x);\n                int v = (b << 6) + t;\n                if (v < R) res.push_back(v);\n                x &= (x - 1);\n            }\n        }\n        return res;\n    }\n\n    bool is_straight_2deg(int rid) const {\n        int deg = 0;\n        for (int d = 0; d < 4; d++) if (nbr[rid][d] != -1) deg++;\n        if (deg != 2) return false;\n        bool U = (nbr[rid][0] != -1);\n        bool D = (nbr[rid][1] != -1);\n        bool L = (nbr[rid][2] != -1);\n        bool Rr = (nbr[rid][3] != -1);\n        return (U && D) || (L && Rr);\n    }\n\n    void add_candidate(int rid) {\n        if (inCand[rid]) return;\n        inCand[rid] = 1;\n        candRid.push_back(rid);\n        candBits.push_back(roadVisBits[rid]);\n        candVisList.push_back(bits_to_list(roadVisBits[rid]));\n    }\n\n    void add_extra_candidates() {\n        int C0 = (int)candRid.size();\n        int addLimit = 0;\n        if (C0 < 220) addLimit = 48;\n        else if (C0 < 320) addLimit = 32;\n        else if (C0 < 420) addLimit = 16;\n        else addLimit = 0;\n\n        int maxC = 520;\n        addLimit = min(addLimit, maxC - C0);\n        if (addLimit <= 0) return;\n\n        vector<int> pool;\n        pool.reserve(R);\n        for (int rid = 0; rid < R; rid++) if (!inCand[rid]) pool.push_back(rid);\n\n        sort(pool.begin(), pool.end(), [&](int a, int b) {\n            if (roadVisCnt[a] != roadVisCnt[b]) return roadVisCnt[a] > roadVisCnt[b];\n            return enterCost[a] < enterCost[b];\n        });\n\n        int added = 0;\n        for (int pass = 0; pass < 2 && added < addLimit; pass++) {\n            for (int rid : pool) {\n                if (added >= addLimit) break;\n                if (inCand[rid]) continue;\n                if (pass == 0 && !is_straight_2deg(rid)) continue;\n                add_candidate(rid);\n                added++;\n            }\n        }\n    }\n\n    void build_candidates() {\n        candRid.clear();\n        candBits.clear();\n        candVisList.clear();\n        inCand.assign(R, 0);\n\n        // start must be candidate[0]\n        add_candidate(startRid);\n\n        // basic structural candidates\n        for (int u = 0; u < R; u++) {\n            if (u == startRid) continue;\n\n            int deg = 0;\n            for (int d = 0; d < 4; d++) if (nbr[u][d] != -1) deg++;\n\n            bool isCand = false;\n            if (deg != 2) {\n                isCand = true; // branch/end\n            } else {\n                bool straight = is_straight_2deg(u);\n                isCand = !straight; // turn\n            }\n            if (isCand) add_candidate(u);\n        }\n\n        // safety completion: every road visible by at least one candidate\n        vector<ull> uni(B, 0ULL);\n        for (int c = 0; c < (int)candRid.size(); c++) {\n            for (int b = 0; b < B; b++) uni[b] |= candBits[c][b];\n        }\n\n        for (int b = 0; b < B; b++) {\n            ull miss = allBits[b] & (~uni[b]);\n            while (miss) {\n                int t = __builtin_ctzll(miss);\n                int rid = (b << 6) + t;\n                if (rid < R) add_candidate(rid);\n                miss &= (miss - 1);\n            }\n        }\n\n        // add a few strong interior candidates (for replacement flexibility)\n        add_extra_candidates();\n    }\n\n    void dijkstra_candidate(int sIdx, vector<int>& dist, vector<int>& prev) {\n        int src = candRid[sIdx];\n\n        dist.assign(R, INF);\n        prev.assign(R, -1);\n        vector<int> score(R, -1); // tie-break objective on equal dist\n\n        using State = tuple<int,int,int>; // dist, -score, node\n        priority_queue<State, vector<State>, greater<State>> pq;\n\n        dist[src] = 0;\n        score[src] = roadVisCnt[src];\n        prev[src] = src;\n        pq.push({0, -score[src], src});\n\n        while (!pq.empty()) {\n            auto [du, negSc, u] = pq.top();\n            pq.pop();\n            int su = -negSc;\n            if (du != dist[u] || su != score[u]) continue;\n\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1) continue;\n\n                int nd = du + enterCost[v];\n                int ns = su + roadVisCnt[v];\n\n                if (nd < dist[v] ||\n                    (nd == dist[v] && (ns > score[v] ||\n                                       (ns == score[v] && (prev[v] == -1 || u < prev[v]))))) {\n                    dist[v] = nd;\n                    score[v] = ns;\n                    prev[v] = u;\n                    pq.push({nd, -ns, v});\n                }\n            }\n        }\n    }\n\n    void precompute_shortest_paths() {\n        int C = (int)candRid.size();\n        distC.assign(C, vector<int>(C, INF));\n        symC.assign(C, vector<int>(C, INF));\n        prevFrom.assign(C, vector<int>(R, -1));\n\n        vector<int> dist, prev;\n        for (int s = 0; s < C; s++) {\n            dijkstra_candidate(s, dist, prev);\n            prevFrom[s].swap(prev);\n\n            for (int t = 0; t < C; t++) {\n                int d = dist[candRid[t]];\n                distC[s][t] = d;\n                if (d < INF / 4) symC[s][t] = d + enterCost[candRid[s]];\n            }\n        }\n    }\n\n    inline int edge_cost(int a, int b) const { return distC[a][b]; }\n    inline int sym_cost(int a, int b) const { return symC[a][b]; }\n\n    bool bits_empty(const vector<ull>& bits) const {\n        for (ull x : bits) if (x) return false;\n        return true;\n    }\n\n    int gain_of_candidate(int c, const vector<ull>& unc) const {\n        int g = 0;\n        for (int b = 0; b < B; b++) g += __builtin_popcountll(candBits[c][b] & unc[b]);\n        return g;\n    }\n\n    struct Choice {\n        double score;\n        int cidx;\n        int pos;\n        int gain;\n        int inc;\n    };\n\n    void repair_cover(\n        vector<int>& seq,\n        vector<char>& used,\n        vector<ull>& unc,\n        double alpha,\n        double beta,\n        int topk,\n        double noise,\n        XorShift64& rng\n    ) {\n        int C = (int)candRid.size();\n\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            vector<Choice> top;\n            top.reserve(topk + 2);\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n\n                int gain = gain_of_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int bestInc = INF, bestPos = 0;\n                if (m == 1) {\n                    bestInc = edge_cost(seq[0], c) + edge_cost(c, seq[0]);\n                    bestPos = 0;\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < bestInc) {\n                            bestInc = inc;\n                            bestPos = p;\n                        }\n                    }\n                }\n\n                if (bestInc >= INF / 4) continue;\n\n                double num = (alpha == 1.0 ? (double)gain :\n                              (alpha == 2.0 ? (double)gain * gain : pow((double)gain, alpha)));\n                double den = (beta == 1.0 ? (double)(bestInc + 1) : pow((double)(bestInc + 1), beta));\n                double sc = num / den;\n\n                if (noise > 0.0) {\n                    double z = rng.next_double() * 2.0 - 1.0;\n                    sc *= (1.0 + noise * z);\n                }\n\n                Choice ch{sc, c, bestPos, gain, bestInc};\n\n                if ((int)top.size() < topk) {\n                    top.push_back(ch);\n                    int z = (int)top.size() - 1;\n                    while (z > 0 && top[z].score > top[z - 1].score) {\n                        swap(top[z], top[z - 1]);\n                        --z;\n                    }\n                } else if (ch.score > top.back().score) {\n                    top.back() = ch;\n                    int z = (int)top.size() - 1;\n                    while (z > 0 && top[z].score > top[z - 1].score) {\n                        swap(top[z], top[z - 1]);\n                        --z;\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            int pick = 0;\n            if ((int)top.size() > 1) {\n                int sz = (int)top.size();\n                int total = sz * (sz + 1) / 2;\n                int r = rng.next_int(1, total);\n                for (int i = 0; i < sz; i++) {\n                    int w = sz - i;\n                    r -= w;\n                    if (r <= 0) {\n                        pick = i;\n                        break;\n                    }\n                }\n            }\n\n            Choice ch = top[pick];\n            seq.insert(seq.begin() + ch.pos + 1, ch.cidx);\n            used[ch.cidx] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[ch.cidx][b];\n        }\n\n        // deterministic completion\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            int bestC = -1, bestPos = 0;\n            int bestGain = -1, bestInc = INF;\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n                int gain = gain_of_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int incMin = INF, pos = 0;\n                if (m == 1) {\n                    incMin = edge_cost(seq[0], c) + edge_cost(c, seq[0]);\n                    pos = 0;\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < incMin) {\n                            incMin = inc;\n                            pos = p;\n                        }\n                    }\n                }\n\n                if (gain > bestGain || (gain == bestGain && incMin < bestInc)) {\n                    bestGain = gain;\n                    bestInc = incMin;\n                    bestC = c;\n                    bestPos = pos;\n                }\n            }\n\n            if (bestC == -1) break;\n            seq.insert(seq.begin() + bestPos + 1, bestC);\n            used[bestC] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[bestC][b];\n        }\n    }\n\n    vector<int> build_cover(double alpha, double beta, int topk, double noise, XorShift64& rng) {\n        int C = (int)candRid.size();\n\n        vector<int> seq = {0};\n        vector<char> used(C, 0);\n        used[0] = 1;\n\n        vector<ull> unc = allBits;\n        for (int b = 0; b < B; b++) unc[b] &= ~candBits[0][b];\n\n        repair_cover(seq, used, unc, alpha, beta, topk, noise, rng);\n        return seq;\n    }\n\n    long long cycle_cost(const vector<int>& seq) const {\n        int m = (int)seq.size();\n        if (m <= 1) return 0;\n        long long c = 0;\n        for (int i = 0; i < m; i++) c += edge_cost(seq[i], seq[(i + 1) % m]);\n        return c;\n    }\n\n    void prune_waypoint_cost(vector<int>& seq) {\n        if (seq.size() <= 1) return;\n\n        vector<int> cnt(R, 0);\n        for (int x : seq) for (int rid : candVisList[x]) cnt[rid]++;\n\n        while (true) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestPos = -1;\n            long long bestSave = LLONG_MIN;\n\n            for (int p = 1; p < m; p++) {\n                int x = seq[p];\n\n                bool removable = true;\n                for (int rid : candVisList[x]) {\n                    if (cnt[rid] <= 1) {\n                        removable = false;\n                        break;\n                    }\n                }\n                if (!removable) continue;\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n                long long save = (long long)edge_cost(pr, x) + edge_cost(x, nx) - edge_cost(pr, nx);\n\n                if (save > bestSave) {\n                    bestSave = save;\n                    bestPos = p;\n                }\n            }\n\n            if (bestPos == -1 || bestSave < 0) break;\n\n            int x = seq[bestPos];\n            for (int rid : candVisList[x]) cnt[rid]--;\n            seq.erase(seq.begin() + bestPos);\n        }\n    }\n\n    bool improve_relocate1(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n\n            int x = seq[i];\n            int p = seq[(i - 1 + m) % m];\n            int n = seq[(i + 1) % m];\n\n            long long rem = -(long long)edge_cost(p, x) - edge_cost(x, n) + edge_cost(p, n);\n\n            for (int j = 0; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n                if (j == i) continue;\n                if (j == (i - 1 + m) % m) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n                long long delta = rem - (long long)edge_cost(a, b) + edge_cost(a, x) + edge_cost(x, b);\n\n                if (delta < 0) {\n                    int node = seq[i];\n                    seq.erase(seq.begin() + i);\n                    int jj = j;\n                    if (jj > i) jj--;\n                    seq.insert(seq.begin() + jj + 1, node);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool improve_swap(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n\n                long long delta = 0;\n                if (i + 1 == j) {\n                    int p = seq[i - 1], a = seq[i], b = seq[j], n = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(p, a) + edge_cost(a, b) + edge_cost(b, n);\n                    long long newc = (long long)edge_cost(p, b) + edge_cost(b, a) + edge_cost(a, n);\n                    delta = newc - oldc;\n                } else {\n                    int pi = seq[i - 1], a = seq[i], ni = seq[(i + 1) % m];\n                    int pj = seq[j - 1], b = seq[j], nj = seq[(j + 1) % m];\n\n                    long long oldc = (long long)edge_cost(pi, a) + edge_cost(a, ni)\n                                   + (long long)edge_cost(pj, b) + edge_cost(b, nj);\n                    long long newc = (long long)edge_cost(pi, b) + edge_cost(b, ni)\n                                   + (long long)edge_cost(pj, a) + edge_cost(a, nj);\n                    delta = newc - oldc;\n                }\n\n                if (delta < 0) {\n                    swap(seq[i], seq[j]);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool improve_2opt_sym(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 4) return false;\n\n        for (int i = 1; i < m - 1; i++) {\n            if (elapsed_ms() > endMs) return false;\n            int a = seq[i - 1];\n            int b = seq[i];\n\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n                if (i == 1 && j == m - 1) continue; // full reverse except start: no gain\n\n                int c = seq[j];\n                int d = seq[(j + 1) % m];\n\n                long long delta = (long long)sym_cost(a, c) + sym_cost(b, d)\n                                - sym_cost(a, b) - sym_cost(c, d);\n\n                if (delta < 0) {\n                    reverse(seq.begin() + i, seq.begin() + j + 1);\n                    curCost += delta; // equivalent objective difference\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    void local_search(vector<int>& seq, long long& curCost, long long endMs) {\n        if (seq.size() <= 2) return;\n\n        int it = 0;\n        while (elapsed_ms() < endMs) {\n            bool imp = false;\n\n            if ((it & 1) == 0) {\n                if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_2opt_sym(seq, curCost, endMs)) imp = true;\n                else if (improve_swap(seq, curCost, endMs)) imp = true;\n            } else {\n                if (improve_2opt_sym(seq, curCost, endMs)) imp = true;\n                else if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_swap(seq, curCost, endMs)) imp = true;\n            }\n\n            if (!imp) break;\n            if ((it & 31) == 31) curCost = cycle_cost(seq);\n            if (++it > 250000) break;\n        }\n\n        curCost = cycle_cost(seq);\n    }\n\n    bool replace_candidatewise(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 1) return false;\n        int C = (int)candRid.size();\n\n        vector<int> cnt(R, 0);\n        vector<char> used(C, 0);\n        for (int x : seq) {\n            used[x] = 1;\n            for (int rid : candVisList[x]) cnt[rid]++;\n        }\n\n        vector<ull> uniq(B, 0ULL);\n        bool improvedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            bool improved = false;\n\n            for (int p = 1; p < m; p++) {\n                if ((p & 7) == 0 && elapsed_ms() > endMs) break;\n\n                int old = seq[p];\n\n                fill(uniq.begin(), uniq.end(), 0ULL);\n                for (int rid : candVisList[old]) {\n                    if (cnt[rid] == 1) uniq[rid >> 6] |= (1ULL << (rid & 63));\n                }\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n\n                long long bestDelta = 0;\n                int bestQ = -1;\n\n                for (int q = 0; q < C; q++) {\n                    if (used[q]) continue;\n\n                    bool ok = true;\n                    for (int b = 0; b < B; b++) {\n                        if (uniq[b] & ~candBits[q][b]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) continue;\n\n                    int c1 = edge_cost(pr, q), c2 = edge_cost(q, nx);\n                    if (c1 >= INF / 4 || c2 >= INF / 4) continue;\n\n                    long long delta = -(long long)edge_cost(pr, old) - edge_cost(old, nx) + c1 + c2;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestQ = q;\n                    }\n                }\n\n                if (bestQ != -1) {\n                    used[old] = 0;\n                    used[bestQ] = 1;\n                    for (int rid : candVisList[old]) cnt[rid]--;\n                    for (int rid : candVisList[bestQ]) cnt[rid]++;\n                    seq[p] = bestQ;\n                    curCost += bestDelta;\n                    improved = true;\n                    improvedAny = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        curCost = cycle_cost(seq);\n        return improvedAny;\n    }\n\n    vector<int> ruin_recreate(const vector<int>& base, XorShift64& rng) {\n        vector<int> seq = base;\n        int m = (int)seq.size();\n\n        if (m > 1) {\n            double ratio = 0.12 + 0.30 * rng.next_double();\n            int k = max(1, (int)((m - 1) * ratio));\n            k = min(k, m - 1);\n\n            vector<int> rem;\n            bool informed = (rng.next_double() < 0.70 && m >= 8);\n\n            if (informed) {\n                vector<int> cnt(R, 0);\n                for (int x : seq) for (int rid : candVisList[x]) cnt[rid]++;\n\n                struct Info {\n                    double key;\n                    int pos;\n                };\n                vector<Info> info;\n                info.reserve(m - 1);\n\n                for (int p = 1; p < m; p++) {\n                    int x = seq[p];\n\n                    int uniq = 0;\n                    for (int rid : candVisList[x]) if (cnt[rid] == 1) uniq++;\n\n                    int pr = seq[(p - 1 + m) % m];\n                    int nx = seq[(p + 1) % m];\n                    long long save = (long long)edge_cost(pr, x) + edge_cost(x, nx) - edge_cost(pr, nx);\n\n                    // lower is easier to remove\n                    double key = uniq * 900.0\n                               - 3.5 * max(0LL, save)\n                               + 1.2 * max(0LL, -save)\n                               + 10.0 * rng.next_double();\n\n                    info.push_back({key, p});\n                }\n\n                sort(info.begin(), info.end(), [](const Info& a, const Info& b) {\n                    return a.key < b.key;\n                });\n\n                vector<char> picked(m, 0);\n                int det = min((int)info.size(), max(1, (int)(k * 0.7)));\n\n                for (int i = 0; i < det; i++) {\n                    rem.push_back(info[i].pos);\n                    picked[info[i].pos] = 1;\n                }\n\n                vector<int> rest;\n                for (int i = det; i < (int)info.size(); i++) {\n                    if (!picked[info[i].pos]) rest.push_back(info[i].pos);\n                }\n\n                while ((int)rem.size() < k && !rest.empty()) {\n                    int idx = rng.next_int(0, (int)rest.size() - 1);\n                    rem.push_back(rest[idx]);\n                    rest[idx] = rest.back();\n                    rest.pop_back();\n                }\n            } else {\n                vector<int> pos(m - 1);\n                for (int i = 0; i < m - 1; i++) pos[i] = i + 1;\n                for (int i = (int)pos.size() - 1; i > 0; i--) {\n                    int j = rng.next_int(0, i);\n                    swap(pos[i], pos[j]);\n                }\n                pos.resize(k);\n                rem.swap(pos);\n            }\n\n            sort(rem.begin(), rem.end());\n            rem.erase(unique(rem.begin(), rem.end()), rem.end());\n            sort(rem.rbegin(), rem.rend());\n            for (int p : rem) seq.erase(seq.begin() + p);\n        }\n\n        int C = (int)candRid.size();\n        vector<char> used(C, 0);\n        for (int x : seq) used[x] = 1;\n\n        vector<ull> unc = allBits;\n        for (int x : seq) {\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[x][b];\n        }\n\n        static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.3};\n        static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n        static const int KS[] = {1, 2, 3, 4, 6};\n\n        double alpha = AS[rng.next_int(0, 5)];\n        double beta  = BS[rng.next_int(0, 3)];\n        int topk     = KS[rng.next_int(0, 4)];\n        double noise = 0.12;\n\n        repair_cover(seq, used, unc, alpha, beta, topk, noise, rng);\n        return seq;\n    }\n\n    bool coverage_full_route_skip(const vector<int>& seq, int skipPos) const {\n        if (seq.empty()) return false;\n\n        vector<ull> cov(B, 0ULL);\n        vector<int> rev;\n        rev.reserve(256);\n\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int b = 0; b < B; b++) cov[b] |= vb[b];\n        };\n\n        auto addEdge = [&](int sCand, int tCand, bool includeSrc) -> bool {\n            int src = candRid[sCand];\n            int dst = candRid[tCand];\n\n            if (includeSrc) addRid(src);\n            if (src == dst) return true;\n\n            rev.clear();\n            int cur = dst;\n            while (cur != src) {\n                rev.push_back(cur);\n                cur = prevFrom[sCand][cur];\n                if (cur < 0) return false;\n            }\n\n            for (int k = (int)rev.size() - 1; k >= 0; k--) addRid(rev[k]);\n            return true;\n        };\n\n        int first = -1, prev = -1;\n        bool firstEdge = true;\n\n        for (int i = 0; i < (int)seq.size(); i++) {\n            if (i == skipPos) continue;\n            int c = seq[i];\n            if (first == -1) {\n                first = c;\n                prev = c;\n            } else {\n                if (!addEdge(prev, c, firstEdge)) return false;\n                firstEdge = false;\n                prev = c;\n            }\n        }\n\n        if (first == -1) return false;\n        if (!addEdge(prev, first, firstEdge)) return false;\n\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    void route_aware_prune_topk(vector<int>& seq, long long endMs, int K = 12) {\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            vector<pair<long long,int>> cands;\n            cands.reserve(max(0, m - 1));\n\n            for (int p = 1; p < m; p++) {\n                int pr = seq[(p - 1 + m) % m];\n                int cur = seq[p];\n                int nx = seq[(p + 1) % m];\n                long long save = (long long)edge_cost(pr, cur) + edge_cost(cur, nx) - edge_cost(pr, nx);\n                if (save >= 0) cands.push_back({save, p});\n            }\n\n            if (cands.empty()) break;\n\n            int kk = min(K, (int)cands.size());\n            nth_element(\n                cands.begin(),\n                cands.begin() + (kk - 1),\n                cands.end(),\n                [](const auto& a, const auto& b) { return a.first > b.first; }\n            );\n            cands.resize(kk);\n            sort(cands.begin(), cands.end(),\n                 [](const auto& a, const auto& b) { return a.first > b.first; });\n\n            bool removed = false;\n            for (auto [save, pos] : cands) {\n                (void)save;\n                if (elapsed_ms() > endMs) break;\n                if (coverage_full_route_skip(seq, pos)) {\n                    seq.erase(seq.begin() + pos);\n                    removed = true;\n                    break;\n                }\n            }\n\n            if (!removed) break;\n        }\n    }\n\n    char move_char(int u, int v) const {\n        if (ri[v] == ri[u] - 1 && rj[v] == rj[u]) return 'U';\n        if (ri[v] == ri[u] + 1 && rj[v] == rj[u]) return 'D';\n        if (ri[v] == ri[u] && rj[v] == rj[u] - 1) return 'L';\n        if (ri[v] == ri[u] && rj[v] == rj[u] + 1) return 'R';\n        return '?';\n    }\n\n    string build_answer(const vector<int>& seq) const {\n        string ans;\n        int m = (int)seq.size();\n        if (m <= 1) return ans;\n\n        long long c = cycle_cost(seq);\n        ans.reserve((size_t)(max(1LL, c / 6) + 64));\n\n        vector<int> rev;\n        rev.reserve(256);\n\n        for (int i = 0; i < m; i++) {\n            int sCand = seq[i];\n            int tCand = seq[(i + 1) % m];\n\n            int src = candRid[sCand];\n            int dst = candRid[tCand];\n            if (src == dst) continue;\n\n            rev.clear();\n            int cur = dst;\n            while (cur != src) {\n                rev.push_back(cur);\n                cur = prevFrom[sCand][cur];\n                if (cur < 0) return \"\";\n            }\n\n            int u = src;\n            for (int k = (int)rev.size() - 1; k >= 0; k--) {\n                int v = rev[k];\n                char ch = move_char(u, v);\n                if (ch == '?') return \"\";\n                ans.push_back(ch);\n                u = v;\n            }\n        }\n\n        return ans;\n    }\n\n    int dir_id(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    bool validate_ans(const string& ans) const {\n        if (startRid < 0) return false;\n\n        vector<ull> cov(B, 0ULL);\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int b = 0; b < B; b++) cov[b] |= vb[b];\n        };\n\n        int cur = startRid;\n        addRid(cur);\n\n        for (char ch : ans) {\n            int d = dir_id(ch);\n            if (d < 0) return false;\n            int nx = nbr[cur][d];\n            if (nx == -1) return false;\n            cur = nx;\n            addRid(cur);\n        }\n\n        if (cur != startRid) return false;\n\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    string fallback_dfs_tour() const {\n        vector<char> vis(R, 0);\n        string out;\n        out.reserve(max(0, 2 * R + 8));\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1 || vis[v]) continue;\n                out.push_back(MV[d]);\n                dfs(v);\n                out.push_back(MV[OPP[d]]);\n            }\n        };\n\n        dfs(startRid);\n        return out;\n    }\n\n    uint64_t calc_seed() const {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)si);\n        mix((uint64_t)sj);\n        mix((uint64_t)R);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                mix((uint64_t)(unsigned char)grid[i][j]\n                    + ((uint64_t)i << 8)\n                    + ((uint64_t)j << 16));\n            }\n        }\n        return h;\n    }\n\n    string solve() {\n        t0 = chrono::steady_clock::now();\n\n        build_graph();\n        if (R == 0) return \"\";\n\n        init_bits();\n        build_road_visibility();\n        build_candidates();\n        precompute_shortest_paths();\n\n        XorShift64 rng(calc_seed());\n\n        vector<int> bestSeq = {0};\n        long long bestCost = (1LL << 60);\n\n        auto update_best = [&](const vector<int>& seq) {\n            if (seq.empty()) return;\n            long long c = cycle_cost(seq);\n            if (c < bestCost) {\n                bestCost = c;\n                bestSeq = seq;\n            }\n        };\n\n        // Initial deterministic\n        {\n            auto seq = build_cover(2.0, 1.0, 1, 0.0, rng);\n            prune_waypoint_cost(seq);\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(1750LL, elapsed_ms() + 180));\n            if (elapsed_ms() < 2100) replace_candidatewise(seq, c, min(2150LL, elapsed_ms() + 40));\n            prune_waypoint_cost(seq);\n            update_best(seq);\n        }\n\n        if (elapsed_ms() < 1400) {\n            auto seq = build_cover(1.4, 1.0, 3, 0.05, rng);\n            prune_waypoint_cost(seq);\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(1850LL, elapsed_ms() + 120));\n            prune_waypoint_cost(seq);\n            update_best(seq);\n        }\n\n        // Multi-start constructive\n        const long long T_CONSTRUCT = 1300;\n        while (elapsed_ms() < T_CONSTRUCT) {\n            static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.3};\n            static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n            static const int KS[] = {1, 2, 3, 4, 6};\n\n            double alpha = AS[rng.next_int(0, 5)];\n            double beta  = BS[rng.next_int(0, 3)];\n            int topk     = KS[rng.next_int(0, 4)];\n            double noise = 0.12;\n\n            auto seq = build_cover(alpha, beta, topk, noise, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(2100LL, elapsed_ms() + 70));\n            if (elapsed_ms() < 2200 && rng.next_double() < 0.70) {\n                replace_candidatewise(seq, c, min(2250LL, elapsed_ms() + 30));\n            }\n            prune_waypoint_cost(seq);\n            update_best(seq);\n        }\n\n        vector<int> curSeq = bestSeq;\n        long long curCost = bestCost;\n\n        // Ruin & recreate with SA-like acceptance\n        const long long T_RR = 2480;\n        while (elapsed_ms() < T_RR) {\n            vector<int> base = (rng.next_double() < 0.60 ? bestSeq : curSeq);\n\n            auto seq = ruin_recreate(base, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(T_RR, elapsed_ms() + 80));\n\n            if (elapsed_ms() < T_RR - 35 && rng.next_double() < 0.75) {\n                replace_candidatewise(seq, c, min(T_RR, elapsed_ms() + 30));\n            }\n\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n\n            if (c < bestCost) {\n                bestCost = c;\n                bestSeq = seq;\n            }\n\n            double prog = min(1.0, elapsed_ms() / (double)T_RR);\n            double temp = 25.0 * (1.0 - prog) + 1.0;\n            long long delta = c - curCost;\n            if (delta <= 0 || rng.next_double() < exp(-(double)delta / temp)) {\n                curSeq = seq;\n                curCost = c;\n            }\n        }\n\n        // Final polish\n        {\n            auto seq = bestSeq;\n            long long c = bestCost;\n\n            while (elapsed_ms() < 2720) {\n                long long before = c;\n\n                local_search(seq, c, min(2760LL, elapsed_ms() + 60));\n                if (elapsed_ms() < 2780) {\n                    replace_candidatewise(seq, c, min(2810LL, elapsed_ms() + 35));\n                }\n                prune_waypoint_cost(seq);\n                c = cycle_cost(seq);\n\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestSeq = seq;\n                }\n                if (c >= before) break;\n            }\n        }\n\n        vector<int> finalSeq = bestSeq;\n\n        // Route-aware final pruning\n        if (elapsed_ms() < 2890 && finalSeq.size() > 1) {\n            auto tmp = finalSeq;\n            route_aware_prune_topk(tmp, 2890, 12);\n            if (coverage_full_route_skip(tmp, -1)) {\n                long long ct = cycle_cost(tmp);\n                long long cf = cycle_cost(finalSeq);\n                if (ct <= cf) finalSeq.swap(tmp);\n            }\n        }\n\n        string ans = build_answer(finalSeq);\n\n        // safety\n        if (!validate_ans(ans)) {\n            string alt = build_answer(bestSeq);\n            if (validate_ans(alt)) {\n                ans = alt;\n            } else {\n                ans = fallback_dfs_tour();\n            }\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\nusing namespace std;\nusing namespace atcoder;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n\n    int N, M, K, R;\n    vector<vector<int>> d;\n    vector<vector<int>> succ;\n    vector<int> indeg0, indegRem, outdeg;\n    vector<int> sumd;\n    vector<int> lp;          // dynamic remaining longest path (among unfinished tasks)\n    vector<int> descCnt;     // static descendant count\n    vector<int> taskState;   // 0:not started, 1:in progress, 2:done\n\n    vector<int> ready, readyPos, readySince;\n    int day = 1;\n    int stallDays = 0;\n\n    struct Member {\n        bool busy = false;\n        int task = -1;\n        int startDay = 0;\n        vector<int> s;\n        vector<int> histTask;\n        vector<int> histDur;\n        bool dirty = false;\n        int doneCount = 0;\n    };\n    vector<Member> members;\n\n    // ---- parameters ----\n    static constexpr int INIT_SKILL = 8;\n    static constexpr int SKILL_MAX = 80;\n    static constexpr int MAX_HIST = 120;\n\n    static constexpr int MAX_CAND = 180;\n    static constexpr int BASE_CAND = 110;\n    static constexpr int AGE_CAND = 40;\n\n    static constexpr int LP_W = 100;\n    static constexpr int DESC_W = 2;\n    static constexpr int UNLOCK_W = 70;\n    static constexpr int AGE_W = 6;\n\n    static constexpr double PRED_W = 40.0;\n    static constexpr double CRIT_MARGIN = 2.0;\n    static constexpr double CRIT_EXCESS_W = 220.0;\n    static constexpr double NEWBIE_CRIT_PEN = 120.0;\n\n    static constexpr double IDLE_UTILITY = -1800.0;\n    static constexpr long long COST_SHIFT = 1'000'000LL;\n\n    static inline double expected_time_from_w(int w) {\n        if (w <= 0) return 1.0;\n        if (w == 1) return 13.0 / 7.0;\n        if (w == 2) return 17.0 / 7.0;\n        if (w == 3) return 22.0 / 7.0;\n        return (double)w;\n    }\n\n    static inline long long utility_to_cost(double util) {\n        long long u10 = llround(util * 10.0);\n        long long c = COST_SHIFT - u10;\n        if (c < 0) c = 0;\n        return c;\n    }\n\n    double sample_loss(int w, int obs) const {\n        const double pred = expected_time_from_w(w);\n        const double e = pred - (double)obs;\n        const double ae = fabs(e);\n\n        // robust / noise-tolerant loss\n        double l;\n        if (ae <= 2.0) {\n            l = 0.25 * ae * ae;\n        } else {\n            const double z = ae - 2.0;\n            l = 1.0 + z * z;\n        }\n\n        // short tasks are less informative (especially obs=1 due clipping)\n        const double wt = (obs <= 1 ? 0.30 : (obs <= 3 ? 0.70 : 1.00));\n        return wt * l;\n    }\n\n    inline int calc_w(const vector<int>& s, int task) const {\n        int w = 0;\n        for (int k = 0; k < K; k++) {\n            if (d[task][k] > s[k]) w += d[task][k] - s[k];\n        }\n        return w;\n    }\n\n    inline double predict_time_exp(int member, int task) const {\n        int w = calc_w(members[member].s, task);\n        return expected_time_from_w(w);\n    }\n\n    void add_ready(int t, int availDay) {\n        if (t < 0 || t >= N) return;\n        if (taskState[t] != 0) return;\n        if (indegRem[t] != 0) return;\n        if (readyPos[t] != -1) return;\n        readyPos[t] = (int)ready.size();\n        ready.push_back(t);\n        readySince[t] = availDay;\n    }\n\n    void remove_ready(int t) {\n        int p = readyPos[t];\n        if (p == -1) return;\n        int last = ready.back();\n        ready[p] = last;\n        readyPos[last] = p;\n        ready.pop_back();\n        readyPos[t] = -1;\n        readySince[t] = -1;\n    }\n\n    void compute_static_descendants() {\n        descCnt.assign(N, 0);\n        if (N <= MAXN) {\n            vector<bitset<MAXN>> reach(N);\n            for (int i = N - 1; i >= 0; i--) {\n                for (int to : succ[i]) {\n                    reach[i] |= reach[to];\n                    reach[i].set(to);\n                }\n                descCnt[i] = (int)reach[i].count();\n            }\n        } else {\n            // fallback (shouldn't be used in official generator)\n            for (int i = 0; i < N; i++) descCnt[i] = outdeg[i];\n        }\n    }\n\n    void update_remaining_lp() {\n        if ((int)lp.size() != N) lp.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            if (taskState[i] == 2) {\n                lp[i] = 0;\n                continue;\n            }\n            int best = 1;\n            for (int to : succ[i]) {\n                if (taskState[to] != 2) best = max(best, lp[to] + 1);\n            }\n            lp[i] = best;\n        }\n    }\n\n    int task_base(int t) const {\n        int unlock = 0;\n        for (int ch : succ[t]) {\n            if (taskState[ch] == 0 && indegRem[ch] == 1) unlock++;\n        }\n        int age = 0;\n        if (readySince[t] >= 0) age = max(0, day - readySince[t]);\n\n        int base = 0;\n        base += LP_W * lp[t];\n        base += DESC_W * descCnt[t];\n        base += UNLOCK_W * unlock;\n        base += AGE_W * age;\n        base += outdeg[t]; // tiny tie-break\n        return base;\n    }\n\n    vector<int> make_candidates() const {\n        if ((int)ready.size() <= MAX_CAND) return ready;\n\n        vector<pair<int, int>> byBase; // (-base, t)\n        vector<pair<int, int>> byAge;  // (-age, t)\n        byBase.reserve(ready.size());\n        byAge.reserve(ready.size());\n\n        for (int t : ready) {\n            byBase.push_back({-task_base(t), t});\n            int age = max(0, day - readySince[t]);\n            byAge.push_back({-age, t});\n        }\n\n        sort(byBase.begin(), byBase.end());\n        sort(byAge.begin(), byAge.end());\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(MAX_CAND);\n\n        int t1 = min(BASE_CAND, (int)byBase.size());\n        for (int i = 0; i < t1; i++) {\n            int t = byBase[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        int t2 = min(AGE_CAND, (int)byAge.size());\n        for (int i = 0; i < t2 && (int)cand.size() < MAX_CAND; i++) {\n            int t = byAge[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        if ((int)cand.size() < MAX_CAND) {\n            vector<pair<int, int>> byEasy; // (sumd, t)\n            byEasy.reserve(ready.size());\n            for (int t : ready) {\n                if (!used[t]) byEasy.push_back({sumd[t], t});\n            }\n            sort(byEasy.begin(), byEasy.end());\n            for (auto &p : byEasy) {\n                if ((int)cand.size() >= MAX_CAND) break;\n                cand.push_back(p.second);\n            }\n        }\n        return cand;\n    }\n\n    void optimize_member(int j) {\n        Member &mb = members[j];\n        int total = (int)mb.histTask.size();\n        if (total == 0) {\n            mb.dirty = false;\n            return;\n        }\n\n        int st = max(0, total - MAX_HIST);\n        int h = total - st;\n\n        vector<int> tasks(h), obs(h), w(h);\n        for (int i = 0; i < h; i++) {\n            tasks[i] = mb.histTask[st + i];\n            obs[i] = mb.histDur[st + i];\n        }\n\n        for (int i = 0; i < h; i++) {\n            w[i] = calc_w(mb.s, tasks[i]);\n        }\n\n        const double reg = 0.30 / (h + 3.0); // stronger when data is scarce\n\n        double loss = 0.0;\n        for (int i = 0; i < h; i++) loss += sample_loss(w[i], obs[i]);\n        for (int k = 0; k < K; k++) {\n            double diff = (double)mb.s[k] - INIT_SKILL;\n            loss += reg * diff * diff;\n        }\n\n        static const int deltas_small[] = {-2, -1, 1, 2};\n        static const int deltas_large[] = {-8, -4, -2, -1, 1, 2, 4, 8};\n        const int *deltas = (h < 5 ? deltas_small : deltas_large);\n        int nd = (h < 5 ? 4 : 8);\n\n        int passes = (h < 8 ? 6 : (h < 20 ? 5 : 4));\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            bool improved = false;\n            if (pass & 1) reverse(order.begin(), order.end());\n\n            for (int idx = 0; idx < K; idx++) {\n                int k = order[idx];\n                int curS = mb.s[k];\n                double bestLoss = loss;\n                int bestS = curS;\n\n                for (int di = 0; di < nd; di++) {\n                    int ns = curS + deltas[di];\n                    if (ns < 0 || ns > SKILL_MAX || ns == curS) continue;\n\n                    double newLoss = loss;\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)ns - INIT_SKILL;\n                        newLoss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > ns ? dval - ns : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n\n                        newLoss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                    }\n\n                    if (newLoss + 1e-9 < bestLoss) {\n                        bestLoss = newLoss;\n                        bestS = ns;\n                    }\n                }\n\n                if (bestS != curS) {\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)bestS - INIT_SKILL;\n                        loss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > bestS ? dval - bestS : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n                        loss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                        w[i] = nw;\n                    }\n\n                    mb.s[k] = bestS;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        mb.dirty = false;\n    }\n\n    vector<pair<int, int>> decide_assignments(bool force) {\n        vector<pair<int, int>> ret;\n\n        vector<int> freeMembers;\n        freeMembers.reserve(M);\n        for (int j = 0; j < M; j++) {\n            if (!members[j].busy) freeMembers.push_back(j);\n        }\n        if (freeMembers.empty() || ready.empty()) return ret;\n\n        vector<int> cand = make_candidates();\n        int F = (int)freeMembers.size();\n        int T = (int)cand.size();\n        if (T == 0) return ret;\n\n        vector<int> base(T);\n        int maxReadyLp = 0, maxReadyDesc = 0;\n        for (int t : ready) {\n            maxReadyLp = max(maxReadyLp, lp[t]);\n            maxReadyDesc = max(maxReadyDesc, descCnt[t]);\n        }\n\n        vector<char> critical(T, 0);\n        for (int ti = 0; ti < T; ti++) {\n            int t = cand[ti];\n            base[ti] = task_base(t);\n            if (lp[t] >= maxReadyLp - 1) critical[ti] = 1;\n            if (descCnt[t] >= maxReadyDesc - 20) critical[ti] = 1;\n        }\n\n        vector<vector<double>> predAll(M, vector<double>(T));\n        vector<double> bestAllPred(T, 1e100);\n        for (int m = 0; m < M; m++) {\n            for (int ti = 0; ti < T; ti++) {\n                double p = predict_time_exp(m, cand[ti]);\n                predAll[m][ti] = p;\n                if (p < bestAllPred[ti]) bestAllPred[ti] = p;\n            }\n        }\n\n        int S = F + T;\n        int G = S + 1;\n        mcf_graph<int, long long> g(G + 1);\n\n        for (int fi = 0; fi < F; fi++) g.add_edge(S, fi, 1, 0);\n        for (int ti = 0; ti < T; ti++) g.add_edge(F + ti, G, 1, 0);\n\n        if (!force) {\n            long long idleCost = utility_to_cost(IDLE_UTILITY);\n            for (int fi = 0; fi < F; fi++) {\n                g.add_edge(fi, G, 1, idleCost);\n            }\n        }\n\n        vector<int> eid(F * T, -1);\n\n        for (int fi = 0; fi < F; fi++) {\n            int m = freeMembers[fi];\n            for (int ti = 0; ti < T; ti++) {\n                double pred = predAll[m][ti];\n                double util = (double)base[ti] - PRED_W * pred;\n\n                if (critical[ti]) {\n                    double excess = pred - bestAllPred[ti];\n                    if (excess > CRIT_MARGIN) {\n                        util -= CRIT_EXCESS_W * (excess - CRIT_MARGIN);\n                    }\n                    if (members[m].doneCount < 2) {\n                        util -= NEWBIE_CRIT_PEN;\n                    }\n                }\n\n                long long cost = utility_to_cost(util);\n                eid[fi * T + ti] = g.add_edge(fi, F + ti, 1, cost);\n            }\n        }\n\n        if (force) {\n            int L = min(T, max(1, F / 2)); // conservative forced progress\n            g.flow(S, G, L);\n        } else {\n            g.flow(S, G, F); // each free member: task or idle\n        }\n\n        for (int fi = 0; fi < F; fi++) {\n            for (int ti = 0; ti < T; ti++) {\n                auto e = g.get_edge(eid[fi * T + ti]);\n                if (e.flow > 0) {\n                    ret.push_back({freeMembers[fi], cand[ti]});\n                }\n            }\n        }\n\n        for (auto [m, t] : ret) {\n            members[m].busy = true;\n            members[m].task = t;\n            members[m].startDay = day;\n\n            taskState[t] = 1;\n            remove_ready(t);\n        }\n\n        return ret;\n    }\n\n    void read_initial() {\n        cin >> N >> M >> K >> R;\n\n        d.assign(N, vector<int>(K));\n        sumd.assign(N, 0);\n        for (int i = 0; i < N; i++) {\n            int s = 0;\n            for (int k = 0; k < K; k++) {\n                cin >> d[i][k];\n                s += d[i][k];\n            }\n            sumd[i] = s;\n        }\n\n        succ.assign(N, {});\n        indeg0.assign(N, 0);\n\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            succ[u].push_back(v);\n            indeg0[v]++;\n        }\n\n        outdeg.assign(N, 0);\n        for (int i = 0; i < N; i++) outdeg[i] = (int)succ[i].size();\n\n        compute_static_descendants();\n\n        indegRem = indeg0;\n        taskState.assign(N, 0);\n\n        ready.clear();\n        readyPos.assign(N, -1);\n        readySince.assign(N, -1);\n\n        day = 1;\n        for (int i = 0; i < N; i++) {\n            if (indegRem[i] == 0) add_ready(i, 1);\n        }\n\n        members.assign(M, Member());\n        for (int j = 0; j < M; j++) {\n            members[j].s.assign(K, INIT_SKILL);\n        }\n\n        lp.assign(N, 1);\n        update_remaining_lp();\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        read_initial();\n\n        while (true) {\n            update_remaining_lp();\n\n            int freeCntBefore = 0;\n            for (int j = 0; j < M; j++) if (!members[j].busy) freeCntBefore++;\n            bool hadReady = !ready.empty();\n\n            bool force = (stallDays >= 2);\n            auto assignments = decide_assignments(force);\n\n            if (hadReady && freeCntBefore > 0 && assignments.empty()) {\n                stallDays++;\n            } else if (!assignments.empty()) {\n                stallDays = 0;\n            } else if (!hadReady || freeCntBefore == 0) {\n                stallDays = 0;\n            }\n\n            cout << assignments.size();\n            for (auto [m, t] : assignments) {\n                cout << ' ' << (m + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int n;\n            if (!(cin >> n)) return;\n            if (n == -1) return;\n\n            vector<int> finished(n);\n            for (int i = 0; i < n; i++) {\n                cin >> finished[i];\n                --finished[i];\n            }\n\n            for (int m : finished) {\n                if (m < 0 || m >= M) continue;\n                Member &mb = members[m];\n                if (!mb.busy) continue;\n\n                int task = mb.task;\n                int duration = day - mb.startDay + 1;\n\n                mb.busy = false;\n                mb.task = -1;\n                mb.doneCount++;\n                mb.histTask.push_back(task);\n                mb.histDur.push_back(duration);\n                mb.dirty = true;\n\n                taskState[task] = 2;\n\n                for (int ch : succ[task]) {\n                    indegRem[ch]--;\n                    if (indegRem[ch] == 0 && taskState[ch] == 0) {\n                        add_ready(ch, day + 1);\n                    }\n                }\n            }\n\n            for (int m : finished) {\n                if (0 <= m && m < M && members[m].dirty) {\n                    optimize_member(m);\n                }\n            }\n\n            day++;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic uint16_t DISTMAT[2001][2001];\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t nextU32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(nextU32() % (uint32_t)n); }\n    double nextDouble() { return (nextU32() + 0.5) / 4294967296.0; }\n};\n\nclass Solver {\n    static constexpr int N = 1000;\n    static constexpr int M = 50;\n    static constexpr int DEP = 2000;\n    static constexpr int TOT = 2001;\n\n    struct Insertion {\n        int delta;\n        int i, j; // insert pickup at i, delivery at j (after pickup insertion)\n    };\n\n    struct Cand {\n        int delta;\n        int id;\n        Insertion ins;\n    };\n\n    struct State {\n        vector<int> route; // pickup [0..999], delivery [1000..1999]\n        vector<int> sel;   // selected order IDs [0..999], size 50\n        array<int, N> pos; // -1 if unselected\n        int len;\n        State() : len(INT_MAX) {\n            route.reserve(2 * M);\n            sel.reserve(M);\n            pos.fill(-1);\n        }\n    };\n\n    int a[N], b[N], c[N], d[N];\n    int nodeX[TOT], nodeY[TOT];\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n    double TL = 1.88;\n\n    vector<int> tmp1, tmp2, tmp3, ord;\n    vector<pair<int, int>> gains; // (removal gain, oid)\n\npublic:\n    Solver()\n        : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        tmp1.reserve(2 * M);\n        tmp2.reserve(2 * M);\n        tmp3.reserve(2 * M);\n        ord.reserve(M);\n        gains.reserve(M);\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    template <class T>\n    inline void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    inline int calcLen(const vector<int>& route) const {\n        int prev = DEP;\n        int len = 0;\n        for (int v : route) {\n            len += DISTMAT[prev][v];\n            prev = v;\n        }\n        len += DISTMAT[prev][DEP];\n        return len;\n    }\n\n    // O(n) best insertion for a pair (pickup oid, delivery oid+N)\n    Insertion bestInsertPair(const vector<int>& route, int oid) const {\n        const int p = oid;\n        const int q = oid + N;\n        const int n = (int)route.size();\n\n        int U[105], V[105], dQ[105];\n        int sufVal[107], sufIdx[107];\n\n        const uint16_t* rowP = DISTMAT[p];\n        const uint16_t* rowQ = DISTMAT[q];\n        const int pq = rowP[q];\n\n        for (int t = 0; t <= n; ++t) {\n            U[t] = (t == 0 ? DEP : route[t - 1]);\n            V[t] = (t == n ? DEP : route[t]);\n            dQ[t] = (int)DISTMAT[U[t]][q] + (int)rowQ[V[t]] - (int)DISTMAT[U[t]][V[t]];\n        }\n\n        const int INF = 1e9;\n        sufVal[n + 1] = INF;\n        sufIdx[n + 1] = -1;\n        for (int t = n; t >= 0; --t) {\n            if (dQ[t] <= sufVal[t + 1]) {\n                sufVal[t] = dQ[t];\n                sufIdx[t] = t;\n            } else {\n                sufVal[t] = sufVal[t + 1];\n                sufIdx[t] = sufIdx[t + 1];\n            }\n        }\n\n        Insertion best{INF, 0, 1};\n\n        for (int i = 0; i <= n; ++i) {\n            int A = U[i];\n            int B = V[i];\n\n            int baseP = (int)DISTMAT[A][p] + (int)rowP[B] - (int)DISTMAT[A][B];\n\n            // adjacent: A -> p -> q -> B\n            int bestExtra = pq + (int)rowQ[B] - (int)rowP[B];\n            int bestJ = i + 1;\n\n            // separated: insert q on an original edge t >= i+1\n            if (i + 1 <= n && sufVal[i + 1] < bestExtra) {\n                bestExtra = sufVal[i + 1];\n                bestJ = sufIdx[i + 1] + 1;\n            }\n\n            int delta = baseP + bestExtra;\n            if (delta < best.delta) best = {delta, i, bestJ};\n        }\n\n        return best;\n    }\n\n    inline void insertPair(vector<int>& route, const Insertion& ins, int oid) const {\n        route.insert(route.begin() + ins.i, oid);\n        route.insert(route.begin() + ins.j, oid + N);\n    }\n\n    inline void removeOrder(const vector<int>& route, int oid, vector<int>& out) const {\n        out.clear();\n        int p = oid, q = oid + N;\n        for (int v : route) {\n            if (v == p || v == q) continue;\n            out.push_back(v);\n        }\n    }\n\n    inline void applyReplace(State& s, int oldId, int newId, const vector<int>& routeWO, const Insertion& ins, int newLen) {\n        tmp2 = routeWO;\n        insertPair(tmp2, ins, newId);\n\n        int idx = s.pos[oldId];\n        s.pos[oldId] = -1;\n        s.pos[newId] = idx;\n        s.sel[idx] = newId;\n\n        s.route.swap(tmp2);\n        s.len = newLen;\n    }\n\n    inline void pushTopCand(vector<Cand>& top, const Cand& c, int lim) {\n        if ((int)top.size() < lim) {\n            top.push_back(c);\n            for (int i = (int)top.size() - 1; i > 0; --i) {\n                if (top[i].delta < top[i - 1].delta) swap(top[i], top[i - 1]);\n                else break;\n            }\n        } else if (c.delta < top.back().delta) {\n            top.back() = c;\n            for (int i = (int)top.size() - 1; i > 0; --i) {\n                if (top[i].delta < top[i - 1].delta) swap(top[i], top[i - 1]);\n                else break;\n            }\n        }\n    }\n\n    State buildGRASP(int rcl) {\n        if (rcl < 1) rcl = 1;\n        State s;\n        s.len = 0;\n\n        vector<Cand> top;\n        top.reserve(rcl + 1);\n\n        for (int step = 0; step < M; ++step) {\n            top.clear();\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTopCand(top, Cand{ins.delta, id, ins}, rcl);\n            }\n\n            int pick = ((int)top.size() == 1 ? 0 : rng.nextInt((int)top.size()));\n            const Cand& ch = top[pick];\n\n            insertPair(s.route, ch.ins, ch.id);\n            s.len += ch.delta;\n            s.pos[ch.id] = (int)s.sel.size();\n            s.sel.push_back(ch.id);\n        }\n\n        s.len = calcLen(s.route); // safety\n        return s;\n    }\n\n    bool relocateOrder(State& s, int oid) {\n        removeOrder(s.route, oid, tmp1);\n        int base = calcLen(tmp1);\n        Insertion ins = bestInsertPair(tmp1, oid);\n        int nlen = base + ins.delta;\n\n        if (nlen < s.len) {\n            tmp2 = tmp1;\n            insertPair(tmp2, ins, oid);\n            s.route.swap(tmp2);\n            s.len = nlen;\n            return true;\n        }\n        return false;\n    }\n\n    bool relocatePass(State& s, double deadline) {\n        ord = s.sel;\n        shuffleVec(ord);\n\n        bool improved = false;\n        for (int oid : ord) {\n            if (elapsed() >= deadline) break;\n            if (relocateOrder(s, oid)) improved = true;\n        }\n        return improved;\n    }\n\n    void computeRemovalGains(const State& s) {\n        gains.clear();\n        gains.reserve(M);\n        for (int oid : s.sel) {\n            removeOrder(s.route, oid, tmp3);\n            int l = calcLen(tmp3);\n            gains.emplace_back(s.len - l, oid);\n        }\n        sort(gains.begin(), gains.end(), [](const auto& L, const auto& R) {\n            return L.first > R.first;\n        });\n    }\n\n    int pickOldForSA(const State& s) {\n        struct OG { int gain, oid; };\n        array<OG, 8> top{};\n        int tsz = 0;\n\n        auto pushTop = [&](int gain, int oid) {\n            if (tsz < 8) {\n                top[tsz++] = {gain, oid};\n                for (int i = tsz - 1; i > 0; --i) {\n                    if (top[i].gain > top[i - 1].gain) swap(top[i], top[i - 1]);\n                    else break;\n                }\n            } else if (gain > top[tsz - 1].gain) {\n                top[tsz - 1] = {gain, oid};\n                for (int i = tsz - 1; i > 0; --i) {\n                    if (top[i].gain > top[i - 1].gain) swap(top[i], top[i - 1]);\n                    else break;\n                }\n            }\n        };\n\n        for (int oid : s.sel) {\n            removeOrder(s.route, oid, tmp3);\n            int l = calcLen(tmp3);\n            int g = s.len - l;\n            pushTop(g, oid);\n        }\n\n        if (tsz == 0) return s.sel[rng.nextInt(M)];\n\n        int r = rng.nextInt(100);\n        if (r < 50) return top[0].oid;\n        if (r < 80) return top[rng.nextInt(min(tsz, 3))].oid;\n        if (r < 95) return top[rng.nextInt(tsz)].oid;\n        return s.sel[rng.nextInt(M)];\n    }\n\n    bool tryReplaceSA(State& s, double temp) {\n        int oldId = pickOldForSA(s);\n\n        removeOrder(s.route, oldId, tmp1);\n        int base = calcLen(tmp1);\n\n        struct RCand {\n            int nlen;\n            int id;\n            Insertion ins;\n        };\n        array<RCand, 4> best{};\n        int bsz = 0;\n\n        auto pushBest = [&](const RCand& c) {\n            if (bsz < 4) {\n                best[bsz++] = c;\n                for (int i = bsz - 1; i > 0; --i) {\n                    if (best[i].nlen < best[i - 1].nlen) swap(best[i], best[i - 1]);\n                    else break;\n                }\n            } else if (c.nlen < best[bsz - 1].nlen) {\n                best[bsz - 1] = c;\n                for (int i = bsz - 1; i > 0; --i) {\n                    if (best[i].nlen < best[i - 1].nlen) swap(best[i], best[i - 1]);\n                    else break;\n                }\n            }\n        };\n\n        for (int id = 0; id < N; ++id) {\n            if (s.pos[id] != -1) continue;\n            Insertion ins = bestInsertPair(tmp1, id);\n            int nlen = base + ins.delta;\n            pushBest(RCand{nlen, id, ins});\n        }\n\n        if (bsz == 0) return false;\n\n        int pick;\n        int rr = rng.nextInt(100);\n        if (rr < 70) pick = 0;\n        else if (rr < 90) pick = rng.nextInt(min(bsz, 2));\n        else pick = rng.nextInt(bsz);\n\n        RCand cand = best[pick];\n        int diff = cand.nlen - s.len;\n\n        if (diff > 0) {\n            double prob = exp(-double(diff) / temp);\n            if (rng.nextDouble() >= prob) return false;\n        }\n\n        applyReplace(s, oldId, cand.id, tmp1, cand.ins, cand.nlen);\n        return true;\n    }\n\n    bool tryBestReplaceImprovement(State& s, int topOldLimit, double deadline) {\n        computeRemovalGains(s);\n        topOldLimit = min(topOldLimit, (int)gains.size());\n\n        for (int t = 0; t < topOldLimit; ++t) {\n            if (elapsed() >= deadline) return false;\n\n            int oldId = gains[t].second;\n            removeOrder(s.route, oldId, tmp1);\n            int base = calcLen(tmp1);\n\n            int bestLen = s.len;\n            int bestId = -1;\n            Insertion bestIns{INT_MAX, 0, 1};\n\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                Insertion ins = bestInsertPair(tmp1, id);\n                int nlen = base + ins.delta;\n                if (nlen < bestLen) {\n                    bestLen = nlen;\n                    bestId = id;\n                    bestIns = ins;\n                }\n            }\n\n            if (bestId != -1) {\n                applyReplace(s, oldId, bestId, tmp1, bestIns, bestLen);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void ruinRecreate(State& s, int k, int rcl, bool targeted) {\n        if (k <= 0) return;\n        rcl = max(1, rcl);\n\n        array<char, N> removed{};\n        removed.fill(0);\n\n        if (targeted) {\n            computeRemovalGains(s);\n            int topRange = min((int)gains.size(), k + 8);\n            int cnt = 0;\n            while (cnt < k) {\n                int oid = gains[rng.nextInt(topRange)].second;\n                if (removed[oid]) continue;\n                removed[oid] = 1;\n                ++cnt;\n            }\n        } else {\n            int cnt = 0;\n            while (cnt < k) {\n                int oid = s.sel[rng.nextInt((int)s.sel.size())];\n                if (removed[oid]) continue;\n                removed[oid] = 1;\n                ++cnt;\n            }\n        }\n\n        tmp1.clear();\n        tmp1.reserve((int)s.route.size() - 2 * k);\n        for (int v : s.route) {\n            int oid = (v < N ? v : v - N);\n            if (!removed[oid]) tmp1.push_back(v);\n        }\n        s.route.swap(tmp1);\n\n        vector<int> ns;\n        ns.reserve(M);\n        s.pos.fill(-1);\n        for (int oid : s.sel) {\n            if (!removed[oid]) {\n                s.pos[oid] = (int)ns.size();\n                ns.push_back(oid);\n            }\n        }\n        s.sel.swap(ns);\n        s.len = calcLen(s.route);\n\n        vector<Cand> top;\n        top.reserve(rcl + 1);\n\n        for (int step = 0; step < k; ++step) {\n            top.clear();\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                if (removed[id]) continue; // force set change\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTopCand(top, Cand{ins.delta, id, ins}, rcl);\n            }\n\n            if (top.empty()) {\n                for (int id = 0; id < N; ++id) {\n                    if (s.pos[id] == -1) {\n                        Insertion ins = bestInsertPair(s.route, id);\n                        top.push_back(Cand{ins.delta, id, ins});\n                        break;\n                    }\n                }\n            }\n\n            int pick = ((int)top.size() == 1 ? 0 : rng.nextInt((int)top.size()));\n            const Cand& ch = top[pick];\n\n            insertPair(s.route, ch.ins, ch.id);\n            s.len += ch.delta;\n            s.pos[ch.id] = (int)s.sel.size();\n            s.sel.push_back(ch.id);\n        }\n\n        s.len = calcLen(s.route); // safety\n    }\n\n    void finalImprove(State& s, double deadline) {\n        while (elapsed() < deadline) {\n            bool improved = false;\n\n            while (elapsed() < deadline) {\n                bool imp = relocatePass(s, deadline);\n                if (!imp) break;\n                improved = true;\n            }\n\n            if (elapsed() >= deadline) break;\n\n            bool rep = tryBestReplaceImprovement(s, 12, deadline);\n            if (rep) {\n                improved = true;\n                continue;\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    void output(const State& s) const {\n        cout << M;\n        for (int id : s.sel) cout << ' ' << (id + 1);\n        cout << '\\n';\n\n        int n = (int)s.route.size() + 2;\n        cout << n << ' ' << 400 << ' ' << 400;\n        for (int v : s.route) {\n            if (v < N) {\n                cout << ' ' << a[v] << ' ' << b[v];\n            } else {\n                int id = v - N;\n                cout << ' ' << c[id] << ' ' << d[id];\n            }\n        }\n        cout << ' ' << 400 << ' ' << 400 << '\\n';\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 0; i < N; ++i) {\n            if (!(cin >> a[i] >> b[i] >> c[i] >> d[i])) return;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            nodeX[i] = a[i];\n            nodeY[i] = b[i];\n            nodeX[i + N] = c[i];\n            nodeY[i + N] = d[i];\n        }\n        nodeX[DEP] = 400;\n        nodeY[DEP] = 400;\n\n        for (int i = 0; i < TOT; ++i) {\n            for (int j = 0; j < TOT; ++j) {\n                DISTMAT[i][j] = (uint16_t)(abs(nodeX[i] - nodeX[j]) + abs(nodeY[i] - nodeY[j]));\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n\n        // Multi-start initialization\n        State best;\n        best.len = INT_MAX;\n\n        vector<int> rclList = {1, 2, 3, 5, 8};\n        int ptr = 0;\n\n        double initEnd = min(0.30, TL * 0.20);\n        while (elapsed() < initEnd) {\n            int rcl = rclList[ptr % (int)rclList.size()];\n            ++ptr;\n\n            State s = buildGRASP(rcl);\n            double d = min(initEnd, elapsed() + 0.02);\n            relocatePass(s, d);\n\n            if (s.len < best.len) best = std::move(s);\n        }\n        if (best.len == INT_MAX) best = buildGRASP(2);\n\n        State cur = best;\n\n        // Main search\n        int iter = 0;\n        int noBest = 0;\n        double mainEnd = TL - 0.22;\n\n        while (elapsed() < mainEnd) {\n            ++iter;\n            double p = elapsed() / TL;\n            double temp = 36.0 * (1.0 - p) + 0.8;\n\n            bool moved = tryReplaceSA(cur, temp);\n\n            if (moved) {\n                if (rng.nextInt(100) < 80) {\n                    int oid = cur.sel[rng.nextInt(M)];\n                    relocateOrder(cur, oid);\n                }\n                if ((iter & 7) == 0 && rng.nextInt(100) < 40) {\n                    int oid = cur.sel[rng.nextInt(M)];\n                    relocateOrder(cur, oid);\n                }\n            } else {\n                if (rng.nextInt(100) < 25) {\n                    int oid = cur.sel[rng.nextInt(M)];\n                    relocateOrder(cur, oid);\n                }\n            }\n\n            if ((iter & 63) == 0) {\n                double d = min(mainEnd, elapsed() + 0.012);\n                relocatePass(cur, d);\n            }\n\n            if (cur.len < best.len) {\n                best = cur;\n                noBest = 0;\n            } else {\n                ++noBest;\n            }\n\n            if (noBest > 110 && elapsed() < mainEnd - 0.04) {\n                State cand = best;\n                int rr = rng.nextInt(100);\n                int k = (rr < 55 ? 2 : (rr < 85 ? 3 : 4));\n                bool targeted = (rng.nextInt(100) < 75);\n                int rcl = (k == 2 ? 4 : 3);\n\n                ruinRecreate(cand, k, rcl, targeted);\n\n                double d = min(mainEnd, elapsed() + 0.035);\n                while (elapsed() < d) {\n                    bool imp = relocatePass(cand, d);\n                    if (!imp) break;\n                }\n                if (elapsed() < d) {\n                    tryBestReplaceImprovement(cand, 6, d);\n                }\n\n                if (cand.len < cur.len || rng.nextInt(100) < 30) cur = cand;\n                if (cand.len < best.len) best = cand;\n\n                noBest = 0;\n            }\n\n            if ((iter & 255) == 0 && cur.len > best.len + 360) {\n                cur = best;\n            }\n        }\n\n        // Final intensification\n        State ans = best;\n        double finalEnd = TL - 0.001;\n\n        finalImprove(ans, finalEnd);\n\n        // Extra light perturb-and-polish\n        if (elapsed() < finalEnd - 0.06) {\n            State cand = ans;\n            ruinRecreate(cand, 2, 3, true);\n\n            double d = min(finalEnd, elapsed() + 0.05);\n            while (elapsed() < d) {\n                bool imp = relocatePass(cand, d);\n                if (!imp) break;\n            }\n            while (elapsed() < d) {\n                bool rep = tryBestReplaceImprovement(cand, 6, d);\n                if (!rep) break;\n            }\n\n            if (cand.len < ans.len) ans = cand;\n        }\n\n        output(ans);\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\n// Monte Carlo settings\nstatic constexpr int MC = 40;          // even\nstatic constexpr int HALF_MC = MC / 2; // antithetic pairs\nstatic constexpr int MIN_CHECK = 16;   // start confidence check after this many samples\nstatic constexpr int CHECK_INTERVAL = 4;\nstatic constexpr double CONF_Z = 2.0;  // confidence multiplier\n\nstatic_assert(MC % 2 == 0);\n\nstruct DSU {\n    uint16_t p[N];\n    uint16_t sz[N];\n    int comps;\n\n    DSU() { init(); }\n\n    inline void init() {\n        for (int i = 0; i < N; ++i) {\n            p[i] = (uint16_t)i;\n            sz[i] = 1;\n        }\n        comps = N;\n    }\n\n    inline int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n\n    inline bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = (uint16_t)a;\n        sz[a] = (uint16_t)(sz[a] + sz[b]);\n        --comps;\n        return true;\n    }\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    array<int, N> xs{}, ys{};\n    for (int i = 0; i < N; ++i) {\n        if (!(cin >> xs[i] >> ys[i])) return 0;\n    }\n\n    array<int, M> eu{}, ev{}, ed{};\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        eu[i] = u;\n        ev[i] = v;\n        long long dx = (long long)xs[u] - xs[v];\n        long long dy = (long long)ys[u] - ys[v];\n        ed[i] = (int)llround(sqrt((long double)dx * dx + (long double)dy * dy));\n    }\n\n    // Deterministic expected-weight order (weight = 2d)\n    vector<int> mean_order(M);\n    iota(mean_order.begin(), mean_order.end(), 0);\n    sort(mean_order.begin(), mean_order.end(), [&](int a, int b) {\n        int wa = 2 * ed[a];\n        int wb = 2 * ed[b];\n        if (wa != wb) return wa < wb;\n        return a < b;\n    });\n\n    // Scenario weights + orders\n    vector<array<uint16_t, M>> scen_w(MC), scen_ord(MC);\n\n    XorShift64 rng(0x123456789ABCDEFULL);\n\n    // Antithetic generation:\n    // scenario s and s+HALF_MC are paired (w' = 4d - w)\n    for (int i = 0; i < M; ++i) {\n        int d = ed[i];\n        for (int t = 0; t < HALF_MC; ++t) {\n            int w = rng.next_int(d, 3 * d);\n            scen_w[t][i] = (uint16_t)w;\n            scen_w[t + HALF_MC][i] = (uint16_t)(4 * d - w);\n        }\n    }\n\n    // Sort edges by weight in each scenario\n    for (int s = 0; s < MC; ++s) {\n        for (int i = 0; i < M; ++i) scen_ord[s][i] = (uint16_t)i;\n        auto &ord = scen_ord[s];\n        auto &w = scen_w[s];\n        sort(ord.begin(), ord.end(), [&](uint16_t a, uint16_t b) {\n            if (w[a] != w[b]) return w[a] < w[b];\n            return a < b;\n        });\n    }\n\n    // Future-only suffix DSU (quick can-reject positive check)\n    vector<DSU> suffix(M + 1);\n    suffix[M].init();\n    for (int i = M - 1; i >= 0; --i) {\n        suffix[i] = suffix[i + 1];\n        suffix[i].unite(eu[i], ev[i]);\n    }\n\n    DSU uf_selected;\n\n    for (int i = 0; i < M; ++i) {\n        int li;\n        if (!(cin >> li)) return 0;\n\n        int u = eu[i], v = ev[i];\n        int ans = 0;\n\n        // Cycle edges in selected forest are always rejected.\n        if (!uf_selected.same(u, v)) {\n            // Feasibility guard: can reject only if u-v remains connectable via selected + future.\n            bool can_reject = false;\n\n            if (suffix[i + 1].same(u, v)) {\n                can_reject = true;\n            } else {\n                DSU ufp = uf_selected;\n                int cu = ufp.find(u), cv = ufp.find(v);\n\n                for (int j = i + 1; j < M; ++j) {\n                    int a = eu[j], b = ev[j];\n                    int ra = ufp.find(a), rb = ufp.find(b);\n                    if (ra == rb) continue;\n\n                    bool touch_u = (ra == cu || rb == cu);\n                    bool touch_v = (ra == cv || rb == cv);\n\n                    if (ufp.sz[ra] < ufp.sz[rb]) swap(ra, rb);\n                    ufp.p[rb] = (uint16_t)ra;\n                    ufp.sz[ra] = (uint16_t)(ufp.sz[ra] + ufp.sz[rb]);\n\n                    if (touch_u) cu = ra;\n                    if (touch_v) cv = ra;\n\n                    if (cu == cv) {\n                        can_reject = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!can_reject) {\n                ans = 1; // mandatory\n            } else {\n                // Estimate gain = E[bottleneck - li] with adaptive confidence\n                long long sum = 0;\n                long long sumsq = 0;\n                int used = 0;\n                bool decided = false;\n\n                // pair order rotation\n                int start = (i * 13 + uf_selected.comps * 7) % HALF_MC;\n                const int stride = 7; // coprime with 20\n\n                for (int tt = 0; tt < HALF_MC; ++tt) {\n                    int p = (start + tt * stride) % HALF_MC;\n\n                    for (int rep = 0; rep < 2; ++rep) {\n                        int s = p + rep * HALF_MC;\n\n                        DSU uf = uf_selected;\n                        int cu = uf.find(u), cv = uf.find(v);\n\n                        const auto &ord = scen_ord[s];\n                        const auto &w = scen_w[s];\n\n                        int gain = -li; // fallback (should rarely happen if can_reject=true)\n\n                        for (int k = 0; k < M; ++k) {\n                            int eid = ord[k];\n                            if (eid <= i) continue;\n\n                            int a = eu[eid], b = ev[eid];\n                            int ra = uf.find(a), rb = uf.find(b);\n                            if (ra == rb) continue;\n\n                            bool touch_u = (ra == cu || rb == cu);\n                            bool touch_v = (ra == cv || rb == cv);\n\n                            if (uf.sz[ra] < uf.sz[rb]) swap(ra, rb);\n                            uf.p[rb] = (uint16_t)ra;\n                            uf.sz[ra] = (uint16_t)(uf.sz[ra] + uf.sz[rb]);\n\n                            if (touch_u) cu = ra;\n                            if (touch_v) cv = ra;\n\n                            if (cu == cv) {\n                                gain = (int)w[eid] - li;\n                                break;\n                            }\n                        }\n\n                        sum += gain;\n                        sumsq += 1LL * gain * gain;\n                        ++used;\n                    }\n\n                    if (used >= MIN_CHECK && used % CHECK_INTERVAL == 0) {\n                        double mean = (double)sum / used;\n                        double var = (double)sumsq / used - mean * mean;\n                        if (var < 0) var = 0;\n                        double se = sqrt(var / used);\n                        double margin = CONF_Z * se;\n\n                        if (mean > margin) {\n                            ans = 1;\n                            decided = true;\n                            break;\n                        }\n                        if (mean < -margin) {\n                            ans = 0;\n                            decided = true;\n                            break;\n                        }\n                    }\n                }\n\n                if (!decided) {\n                    // Near tie: deterministic expected-weight tie-break.\n                    if (llabs(sum) <= 2) {\n                        DSU uf = uf_selected;\n                        int cu = uf.find(u), cv = uf.find(v);\n                        int gdet = -li;\n\n                        for (int k = 0; k < M; ++k) {\n                            int eid = mean_order[k];\n                            if (eid <= i) continue;\n\n                            int a = eu[eid], b = ev[eid];\n                            int ra = uf.find(a), rb = uf.find(b);\n                            if (ra == rb) continue;\n\n                            bool touch_u = (ra == cu || rb == cu);\n                            bool touch_v = (ra == cv || rb == cv);\n\n                            if (uf.sz[ra] < uf.sz[rb]) swap(ra, rb);\n                            uf.p[rb] = (uint16_t)ra;\n                            uf.sz[ra] = (uint16_t)(uf.sz[ra] + uf.sz[rb]);\n\n                            if (touch_u) cu = ra;\n                            if (touch_v) cv = ra;\n\n                            if (cu == cv) {\n                                gdet = 2 * ed[eid] - li;\n                                break;\n                            }\n                        }\n\n                        if (gdet > 0) ans = 1;\n                        else if (gdet < 0) ans = 0;\n                        else ans = (sum > 0 ? 1 : 0); // exact tie -> reject\n                    } else {\n                        ans = (sum > 0 ? 1 : 0); // tie -> reject\n                    }\n                }\n            }\n        } else {\n            ans = 0;\n        }\n\n        if (ans == 1) uf_selected.unite(u, v);\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int r, c; };\nbool operator==(const Pos& a, const Pos& b){ return a.r == b.r && a.c == b.c; }\n\nstatic constexpr int BOARD = 30;\nstatic constexpr int BASE = 31;\nstatic constexpr int SZ = BASE * BASE;\nstatic constexpr long long INF64 = (1LL << 60);\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\ninline bool inBoard(int r, int c){ return 1 <= r && r <= BOARD && 1 <= c && c <= BOARD; }\ninline bool inBoard(const Pos& p){ return inBoard(p.r, p.c); }\ninline int pid(int r, int c){ return r * BASE + c; }\ninline int pid(const Pos& p){ return pid(p.r, p.c); }\nint manhattan(const Pos& a, const Pos& b){ return abs(a.r - b.r) + abs(a.c - b.c); }\n\nint dirFromUpper(char ch){\n    if(ch == 'U') return 0;\n    if(ch == 'D') return 1;\n    if(ch == 'L') return 2;\n    if(ch == 'R') return 3;\n    return -1;\n}\nint dirFromLower(char ch){\n    if(ch == 'u') return 0;\n    if(ch == 'd') return 1;\n    if(ch == 'l') return 2;\n    if(ch == 'r') return 3;\n    return -1;\n}\nchar lowerFromDelta(int dr, int dc){\n    if(dr == -1 && dc == 0) return 'u';\n    if(dr == 1 && dc == 0) return 'd';\n    if(dr == 0 && dc == -1) return 'l';\n    if(dr == 0 && dc == 1) return 'r';\n    return '.';\n}\nPos moved(const Pos& p, int d){ return Pos{p.r + DR[d], p.c + DC[d]}; }\n\nint petWeight(int t){\n    if(t == 1) return 1; // cow\n    if(t == 2) return 2; // pig\n    if(t == 3) return 3; // rabbit\n    if(t == 4) return 2; // dog\n    return 2;            // cat\n}\n\nstruct WallTask {\n    Pos target;\n    Pos standOut;\n    Pos standIn;\n    char buildOut;\n    char buildIn;\n};\n\nstruct RegionPlan {\n    int corner = 0; // 0:TL 1:TR 2:BL 3:BR\n    int s = 6;\n    vector<WallTask> tasks;\n    int gateIdx = 0;\n    Pos safeCell{1,1};\n    Pos decoyCell{30,30};\n\n    bool inRegion(const Pos& p) const {\n        if(corner == 0){\n            return (1 <= p.r && p.r <= s && 1 <= p.c && p.c <= s);\n        }else if(corner == 1){\n            int cL = 31 - s;\n            return (1 <= p.r && p.r <= s && cL <= p.c && p.c <= 30);\n        }else if(corner == 2){\n            int rT = 31 - s;\n            return (rT <= p.r && p.r <= 30 && 1 <= p.c && p.c <= s);\n        }else{\n            int rT = 31 - s;\n            int cL = 31 - s;\n            return (rT <= p.r && p.r <= 30 && cL <= p.c && p.c <= 30);\n        }\n    }\n};\n\nclass Solver {\npublic:\n    void run();\n\nprivate:\n    int N = 0, M = 0;\n    vector<Pos> pets;\n    vector<int> petType;\n    vector<Pos> humans;\n    bool passable[31][31]{};\n\n    RegionPlan plan;\n\n    enum Phase { BUILD, ENTER, CLOSE, DONE };\n    Phase phase = BUILD;\n\n    int gateCloser = -1;\n    int attemptCnt = 0;\n    int lastReplanTurn = -1000;\n    int lastBuiltCnt = 0;\n    int stallTurns = 0;\n    int closeStartTurn = -1;\n    int targetInside = 1;\n\n    // basics\n    void buildCounts(int humanCnt[31][31], int petCnt[31][31]) const;\n    bool canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const;\n\n    // path\n    void runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const;\n    void computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const;\n    char moveToward(int i, const Pos& target,\n                    const vector<array<int,SZ>>& dist,\n                    const vector<array<int,SZ>>& first) const;\n\n    // planning\n    RegionPlan generatePlan(int corner, int s) const;\n    void computeComponents(int compId[31][31], vector<int>& humCompCnt) const;\n    bool reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const;\n    long long evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                const int compId[31][31], const vector<int>& humCompCnt) const;\n    RegionPlan choosePlan(bool emergency, int avoidCorner) const;\n\n    // plan stats\n    int countInsideHumans(const RegionPlan& p) const;\n    int countInsidePets(const RegionPlan& p) const;\n    int builtNonGateWalls(const RegionPlan& p) const;\n    int remainingNonGateWalls(const RegionPlan& p) const;\n\n    // phase / replan\n    bool isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const;\n    int computeTargetInside(int turn, int insidePets, bool pressure) const;\n    void updatePhase(int turn, const int petCnt[31][31]);\n    bool shouldReplan(int turn, const int petCnt[31][31]) const;\n    bool replan(int turn);\n\n    // action generation\n    vector<char> decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]);\n\n    // simulation\n    void sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const;\n    void applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]);\n    void applyPetMoves(const vector<string>& pMoves);\n};\n\nvoid Solver::buildCounts(int humanCnt[31][31], int petCnt[31][31]) const {\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            humanCnt[r][c] = 0;\n            petCnt[r][c] = 0;\n        }\n    }\n    for(const auto& h: humans) humanCnt[h.r][h.c]++;\n    for(const auto& p: pets) petCnt[p.r][p.c]++;\n}\n\nbool Solver::canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    if(!inBoard(t)) return false;\n    if(humanCnt[t.r][t.c] > 0) return false;\n    if(petCnt[t.r][t.c] > 0) return false;\n    for(int d=0; d<4; d++){\n        int nr = t.r + DR[d], nc = t.c + DC[d];\n        if(!inBoard(nr, nc)) continue;\n        if(petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nvoid Solver::runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const {\n    dist.fill(-1);\n    first.fill(-1);\n    queue<Pos> q;\n    dist[pid(st)] = 0;\n    q.push(st);\n\n    while(!q.empty()){\n        Pos cur = q.front(); q.pop();\n        int cid = pid(cur);\n        for(int d=0; d<4; d++){\n            Pos nx{cur.r + DR[d], cur.c + DC[d]};\n            if(!inBoard(nx)) continue;\n            if(!passable[nx.r][nx.c]) continue;\n            int nid = pid(nx);\n            if(dist[nid] != -1) continue;\n            dist[nid] = dist[cid] + 1;\n            first[nid] = (cur == st ? d : first[cid]);\n            q.push(nx);\n        }\n    }\n}\n\nvoid Solver::computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const {\n    dist.resize(M);\n    first.resize(M);\n    for(int i=0; i<M; i++) runBFS(humans[i], dist[i], first[i]);\n}\n\nchar Solver::moveToward(int i, const Pos& target,\n                        const vector<array<int,SZ>>& dist,\n                        const vector<array<int,SZ>>& first) const {\n    if(!inBoard(target) || !passable[target.r][target.c]) return '.';\n    if(humans[i] == target) return '.';\n    int d = dist[i][pid(target)];\n    if(d <= 0) return '.';\n    int fd = first[i][pid(target)];\n    if(fd < 0) return '.';\n    return MOVE_CH[fd];\n}\n\nRegionPlan Solver::generatePlan(int corner, int s) const {\n    RegionPlan p;\n    p.corner = corner;\n    p.s = s;\n    p.tasks.clear();\n\n    auto addTask = [&](Pos target, Pos standOut, Pos standIn){\n        WallTask t;\n        t.target = target;\n        t.standOut = standOut;\n        t.standIn = standIn;\n        t.buildOut = lowerFromDelta(target.r - standOut.r, target.c - standOut.c);\n        t.buildIn = lowerFromDelta(target.r - standIn.r, target.c - standIn.c);\n        p.tasks.push_back(t);\n    };\n\n    Pos gate{-1,-1};\n\n    if(corner == 0){\n        for(int c=1; c<=s; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{s+1,1};\n        p.safeCell = Pos{1,1};\n        p.decoyCell = Pos{30,30};\n    }else if(corner == 1){\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{s+1,30};\n        p.safeCell = Pos{1,30};\n        p.decoyCell = Pos{30,1};\n    }else if(corner == 2){\n        int rT = 30 - s;\n        for(int c=1; c<=s; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{rT,1};\n        p.safeCell = Pos{30,1};\n        p.decoyCell = Pos{1,30};\n    }else{\n        int rT = 30 - s;\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{rT,30};\n        p.safeCell = Pos{30,30};\n        p.decoyCell = Pos{1,1};\n    }\n\n    p.gateIdx = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(p.tasks[i].target == gate){\n            p.gateIdx = i;\n            break;\n        }\n    }\n    return p;\n}\n\nvoid Solver::computeComponents(int compId[31][31], vector<int>& humCompCnt) const {\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) compId[r][c] = 0;\n\n    int cid = 0;\n    queue<Pos> q;\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            if(!passable[r][c] || compId[r][c] != 0) continue;\n            cid++;\n            compId[r][c] = cid;\n            q.push(Pos{r,c});\n            while(!q.empty()){\n                Pos cur = q.front(); q.pop();\n                for(int d=0; d<4; d++){\n                    int nr = cur.r + DR[d], nc = cur.c + DC[d];\n                    if(!inBoard(nr,nc) || !passable[nr][nc] || compId[nr][nc] != 0) continue;\n                    compId[nr][nc] = cid;\n                    q.push(Pos{nr,nc});\n                }\n            }\n        }\n    }\n\n    humCompCnt.assign(cid + 1, 0);\n    for(const auto& h: humans){\n        if(!passable[h.r][h.c]) continue;\n        int id = compId[h.r][h.c];\n        if(id >= 1 && id < (int)humCompCnt.size()) humCompCnt[id]++;\n    }\n}\n\nbool Solver::reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(!inBoard(p) || !passable[p.r][p.c]) return false;\n    int id = compId[p.r][p.c];\n    if(id <= 0 || id >= (int)humCompCnt.size()) return false;\n    return humCompCnt[id] > 0;\n}\n\nlong long Solver::evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                    const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(p.tasks.empty()) return INF64/2;\n    const WallTask& gate = p.tasks[p.gateIdx];\n\n    if(!inBoard(gate.target) || !passable[gate.target.r][gate.target.c]) return INF64/2;\n    if(!(reachableByHuman(gate.standIn, compId, humCompCnt) ||\n         reachableByHuman(gate.standOut, compId, humCompCnt))) return INF64/2;\n\n    int insidePets = 0, insidePetsW = 0;\n    int nearBoundary = 0, nearGate = 0;\n\n    for(int i=0; i<N; i++){\n        const Pos& pet = pets[i];\n        int w = petWeight(petType[i]);\n\n        if(p.inRegion(pet)){\n            insidePets++;\n            insidePetsW += w;\n        }\n\n        int md = 100;\n        for(const auto& t: p.tasks) md = min(md, manhattan(pet, t.target));\n        if(md <= 1) nearBoundary += 2*w;\n        else if(md == 2) nearBoundary += w;\n\n        if(manhattan(pet, gate.target) <= 2) nearGate += w;\n    }\n\n    int remaining = 0, impossible = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i];\n        if(!passable[t.target.r][t.target.c]) continue;\n        remaining++;\n        bool okOut = reachableByHuman(t.standOut, compId, humCompCnt);\n        bool okIn  = reachableByHuman(t.standIn, compId, humCompCnt);\n        if(!okOut && !okIn) impossible++;\n    }\n\n    int interiorWalls = 0;\n    if(p.corner == 0){\n        for(int r=1; r<=p.s; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 1){\n        int cL = 31 - p.s;\n        for(int r=1; r<=p.s; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 2){\n        int rT = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else{\n        int rT = 31 - p.s, cL = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }\n\n    long long humDist = 0;\n    for(const auto& h: humans) humDist += manhattan(h, gate.standOut);\n\n    long long score = 0;\n    score += 300000000LL * insidePets;\n    score +=  50000000LL * insidePetsW;\n    score +=    900000LL * nearGate;\n    score +=    250000LL * nearBoundary;\n    score +=  40000000LL * impossible;\n    score +=      4000LL * remaining;\n    score +=       120LL * humDist;\n    score +=    350000LL * interiorWalls;\n    score -= (emergency ? 1700LL : 3000LL) * p.s * p.s;\n\n    if(!passable[p.safeCell.r][p.safeCell.c]) score += 8000000LL;\n    if(avoidCorner >= 0 && p.corner == avoidCorner){\n        score += (emergency ? 300000LL : 1200000LL);\n    }\n    return score;\n}\n\nRegionPlan Solver::choosePlan(bool emergency, int avoidCorner) const {\n    int compId[31][31];\n    vector<int> humCompCnt;\n    computeComponents(compId, humCompCnt);\n\n    int sL = emergency ? 4 : 6;\n    int sR = emergency ? 7 : 10;\n\n    long long bestScore = INF64;\n    RegionPlan bestPlan;\n    bool found = false;\n\n    for(int corner=0; corner<4; corner++){\n        for(int s=sL; s<=sR; s++){\n            RegionPlan cand = generatePlan(corner, s);\n            long long sc = evaluateCandidate(cand, emergency, avoidCorner, compId, humCompCnt);\n            if(sc >= INF64/4) continue;\n            if(!found || sc < bestScore){\n                found = true;\n                bestScore = sc;\n                bestPlan = cand;\n            }\n        }\n    }\n\n    if(found) return bestPlan;\n    if(!plan.tasks.empty()) return plan;\n    return generatePlan(0, emergency ? 4 : 6);\n}\n\nint Solver::countInsideHumans(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& h: humans) if(p.inRegion(h)) cnt++;\n    return cnt;\n}\n\nint Solver::countInsidePets(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& x: pets) if(p.inRegion(x)) cnt++;\n    return cnt;\n}\n\nint Solver::builtNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int b = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(!passable[t.r][t.c]) b++;\n    }\n    return b;\n}\n\nint Solver::remainingNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int rem = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(passable[t.r][t.c]) rem++;\n    }\n    return rem;\n}\n\nbool Solver::isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const {\n    const Pos& g = p.tasks[p.gateIdx].target;\n    for(int r=max(1, g.r-2); r<=min(30, g.r+2); r++){\n        for(int c=max(1, g.c-2); c<=min(30, g.c+2); c++){\n            if(abs(r-g.r) + abs(c-g.c) > 2) continue;\n            if(petCnt[r][c] > 0) return true;\n        }\n    }\n    return false;\n}\n\nint Solver::computeTargetInside(int turn, int insidePets, bool pressure) const {\n    int t = max(1, M-1);\n    if(pressure) t = max(1, M-2);\n    if(insidePets >= 1) t = max(1, M-2);\n    if(turn >= 240) t = max(1, M-2);\n    if(turn >= 270) t = max(1, M-3);\n    if(turn >= 290) t = 1;\n    return min(t, M);\n}\n\nvoid Solver::updatePhase(int turn, const int petCnt[31][31]) {\n    if(phase == BUILD){\n        if(remainingNonGateWalls(plan) == 0){\n            phase = ENTER;\n            gateCloser = -1;\n            targetInside = max(1, M-1);\n        }\n    }\n\n    if(phase == ENTER){\n        int insideHum = countInsideHumans(plan);\n        int insidePets = countInsidePets(plan);\n        bool pressure = isGatePressured(plan, petCnt) || (insidePets > 0);\n        targetInside = computeTargetInside(turn, insidePets, pressure);\n\n        if(insideHum >= targetInside || (turn >= 289 && insideHum >= 1)){\n            phase = CLOSE;\n            closeStartTurn = turn;\n        }\n    }\n\n    if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(!passable[gt.r][gt.c]) phase = DONE;\n    }\n}\n\nbool Solver::shouldReplan(int turn, const int petCnt[31][31]) const {\n    if(phase == DONE) return false;\n    if(attemptCnt >= 2) return false;\n    if(turn - lastReplanTurn < 20) return false;\n\n    int rem = remainingNonGateWalls(plan);\n    int insidePets = countInsidePets(plan);\n    bool pressure = isGatePressured(plan, petCnt);\n\n    if(phase == BUILD){\n        if(rem > 0 && turn >= 190) return true;\n        if(rem > 0 && stallTurns >= 30 && turn <= 245) return true;\n        if(insidePets >= 2 && turn <= 175) return true;\n    }else if(phase == ENTER){\n        if(insidePets >= 2 && turn <= 220) return true;\n        if(turn >= 250 && countInsideHumans(plan) < max(1, M-2)) return true;\n    }else if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(passable[gt.r][gt.c] && closeStartTurn >= 0 &&\n           (turn - closeStartTurn) >= 40 && pressure && turn <= 245){\n            return true;\n        }\n    }\n    return false;\n}\n\nbool Solver::replan(int turn) {\n    bool emergency = (turn >= 140 || attemptCnt >= 1);\n    int avoid = plan.corner;\n    RegionPlan np = choosePlan(emergency, avoid);\n\n    if(np.corner == plan.corner && np.s == plan.s){\n        lastReplanTurn = turn; // cooldown\n        return false;\n    }\n\n    plan = np;\n    phase = BUILD;\n    gateCloser = -1;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n\n    attemptCnt++;\n    lastReplanTurn = turn;\n\n    if(remainingNonGateWalls(plan) == 0) phase = ENTER;\n    return true;\n}\n\nvector<char> Solver::decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n\n    vector<int> remaining;\n    for(int i=0; i<(int)plan.tasks.size(); i++){\n        if(i == plan.gateIdx) continue;\n        const Pos& t = plan.tasks[i].target;\n        if(passable[t.r][t.c]) remaining.push_back(i);\n    }\n    if(remaining.empty()) return act;\n\n    vector<char> isBuildable(plan.tasks.size(), 0);\n    vector<int> buildable;\n    for(int idx: remaining){\n        if(canBuildCell(plan.tasks[idx].target, humanCnt, petCnt)){\n            isBuildable[idx] = 1;\n            buildable.push_back(idx);\n        }\n    }\n\n    const vector<int>& cand = (!buildable.empty() ? buildable : remaining);\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    bool reserved[31][31]{};\n    vector<int> useCnt(plan.tasks.size(), 0);\n\n    // immediate build\n    for(int i=0; i<M; i++){\n        for(int idx: cand){\n            if(!isBuildable[idx]) continue;\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n\n            if(humans[i] == t.standOut){\n                act[i] = t.buildOut;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n            if(humans[i] == t.standIn){\n                act[i] = t.buildIn;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(act[i] != '.') continue;\n\n        int bestCost = 1e9;\n        int bestIdx = -1, bestMode = 0, bestD = -1;\n\n        for(int idx: cand){\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n            bool buildNow = isBuildable[idx];\n\n            for(int mode=0; mode<2; mode++){\n                Pos st = (mode == 0 ? t.standOut : t.standIn);\n                if(!inBoard(st) || !passable[st.r][st.c]) continue;\n                int d = dist[i][pid(st)];\n                if(d < 0) continue;\n                if(d == 0 && !buildNow) continue;\n\n                int cost = d*10 + useCnt[idx]*18 + (mode==1 ? 8 : 0) + (buildNow ? 0 : 30);\n                if(cost < bestCost){\n                    bestCost = cost;\n                    bestIdx = idx;\n                    bestMode = mode;\n                    bestD = d;\n                }\n            }\n        }\n\n        if(bestIdx == -1) continue;\n\n        useCnt[bestIdx]++;\n        const auto& t = plan.tasks[bestIdx];\n        bool buildNow = isBuildable[bestIdx];\n\n        if(bestD == 0 && buildNow && !reserved[t.target.r][t.target.c]){\n            act[i] = (bestMode == 0 ? t.buildOut : t.buildIn);\n            reserved[t.target.r][t.target.c] = true;\n        }else if(bestD > 0){\n            Pos st = (bestMode == 0 ? t.standOut : t.standIn);\n            int fd = first[i][pid(st)];\n            if(fd >= 0) act[i] = MOVE_CH[fd];\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)humanCnt;\n    (void)petCnt;\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        int da = dist[a][pid(gate.standIn)];\n        int db = dist[b][pid(gate.standIn)];\n        bool ra = (da >= 0), rb = (db >= 0);\n        if(ra != rb) return ra > rb;\n\n        bool ia = plan.inRegion(humans[a]);\n        bool ib = plan.inRegion(humans[b]);\n        if(ia != ib) return ia > ib;\n\n        int ka = ra ? da : 1000000;\n        int kb = rb ? db : 1000000;\n        if(ka != kb) return ka < kb;\n        return a < b;\n    });\n\n    vector<char> insideSet(M, 0);\n    int need = max(1, min(targetInside, M));\n    int got = 0;\n    for(int id: ord){\n        int d = dist[id][pid(gate.standIn)];\n        bool can = (d >= 0) || plan.inRegion(humans[id]);\n        if(!can) continue;\n        insideSet[id] = 1;\n        got++;\n        if(got >= need) break;\n    }\n\n    if(got == 0){\n        int fb = -1, best = 1e9;\n        for(int i=0; i<M; i++){\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; fb = i; }\n        }\n        if(fb == -1) fb = 0;\n        insideSet[fb] = 1;\n    }\n\n    gateCloser = -1;\n    int best = 1e9;\n    for(int i=0; i<M; i++){\n        if(!insideSet[i]) continue;\n        int d = dist[i][pid(gate.standIn)];\n        if(d >= 0 && d < best){ best = d; gateCloser = i; }\n    }\n    if(gateCloser == -1){\n        best = 1e9;\n        for(int i=0; i<M; i++){\n            if(!insideSet[i]) continue;\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; gateCloser = i; }\n        }\n    }\n    if(gateCloser == -1){\n        for(int i=0; i<M; i++) if(insideSet[i]) { gateCloser = i; break; }\n        if(gateCloser == -1) gateCloser = 0;\n    }\n\n    for(int i=0; i<M; i++){\n        if(insideSet[i]){\n            Pos tgt;\n            if(i == gateCloser){\n                tgt = gate.standIn;\n                if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n            }else{\n                if(plan.inRegion(humans[i])) tgt = plan.safeCell;\n                else{\n                    tgt = gate.standIn;\n                    if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n                }\n            }\n            act[i] = moveToward(i, tgt, dist, first);\n        }else{\n            act[i] = moveToward(i, plan.decoyCell, dist, first);\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    int builder = -1;\n    int buildSide = 0; // 0=in 1=out\n    int bestCost = 1e9;\n\n    for(int i=0; i<M; i++){\n        for(int side=0; side<2; side++){\n            Pos st = (side == 0 ? gate.standIn : gate.standOut);\n            if(!inBoard(st) || !passable[st.r][st.c]) continue;\n            int d = dist[i][pid(st)];\n            if(d < 0) continue;\n\n            int cost = d*10 + (side==1 ? 4 : 0);\n            if(gateCloser >= 0 && i != gateCloser) cost += 2;\n            if(!plan.inRegion(humans[i])) cost += 1;\n            if(d == 0 && canBuildCell(gate.target, humanCnt, petCnt)) cost -= 1000;\n\n            if(cost < bestCost){\n                bestCost = cost;\n                builder = i;\n                buildSide = side;\n            }\n        }\n    }\n\n    if(builder != -1){\n        Pos st = (buildSide == 0 ? gate.standIn : gate.standOut);\n        if(humans[builder] == st){\n            if(canBuildCell(gate.target, humanCnt, petCnt)){\n                act[builder] = (buildSide == 0 ? gate.buildIn : gate.buildOut);\n            }\n        }else{\n            act[builder] = moveToward(builder, st, dist, first);\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(i == builder) continue;\n        Pos tgt = plan.inRegion(humans[i]) ? plan.safeCell : plan.decoyCell;\n        act[i] = moveToward(i, tgt, dist, first);\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)turn;\n    if(phase == DONE) return vector<char>(M, '.');\n    if(phase == BUILD) return decideBuildActions(humanCnt, petCnt);\n    if(phase == ENTER) return decideEnterActions(humanCnt, petCnt);\n    return decideCloseActions(humanCnt, petCnt);\n}\n\nvoid Solver::sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    bool buildNow[31][31]{};\n\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }else{\n            act[i] = '.';\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to) || !passable[to.r][to.c] || buildNow[to.r][to.c]){\n            act[i] = '.';\n        }\n    }\n}\n\nvoid Solver::applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) {\n    bool passBefore[31][31];\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passBefore[r][c] = passable[r][c];\n\n    bool buildNow[31][31]{};\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }\n    }\n\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) if(buildNow[r][c]) passable[r][c] = false;\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to)) continue;\n        if(!passBefore[to.r][to.c]) continue;\n        if(buildNow[to.r][to.c]) continue;\n        humans[i] = to;\n    }\n}\n\nvoid Solver::applyPetMoves(const vector<string>& pMoves) {\n    for(int i=0; i<N; i++){\n        if(pMoves[i] == \".\") continue;\n        for(char ch: pMoves[i]){\n            int d = dirFromUpper(ch);\n            if(d < 0) continue;\n            pets[i].r += DR[d];\n            pets[i].c += DC[d];\n        }\n    }\n}\n\nvoid Solver::run() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if(!(cin >> N)) return;\n    pets.resize(N);\n    petType.resize(N);\n    for(int i=0; i<N; i++) cin >> pets[i].r >> pets[i].c >> petType[i];\n    cin >> M;\n    humans.resize(M);\n    for(int i=0; i<M; i++) cin >> humans[i].r >> humans[i].c;\n\n    for(int r=0; r<=BOARD; r++) for(int c=0; c<=BOARD; c++) passable[r][c] = false;\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passable[r][c] = true;\n\n    plan = choosePlan(false, -1);\n\n    phase = BUILD;\n    gateCloser = -1;\n    attemptCnt = 0;\n    lastReplanTurn = -1000;\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n\n    for(int turn=0; turn<300; turn++){\n        int humanCnt[31][31], petCnt[31][31];\n        buildCounts(humanCnt, petCnt);\n\n        if(phase == BUILD){\n            int b = builtNonGateWalls(plan);\n            if(b > lastBuiltCnt){\n                lastBuiltCnt = b;\n                stallTurns = 0;\n            }else{\n                stallTurns++;\n            }\n        }else{\n            stallTurns = 0;\n        }\n\n        updatePhase(turn, petCnt);\n\n        if(shouldReplan(turn, petCnt)){\n            bool changed = replan(turn);\n            if(changed) updatePhase(turn, petCnt);\n        }\n\n        vector<char> actions = decideActions(turn, humanCnt, petCnt);\n        sanitizeActions(actions, humanCnt, petCnt);\n\n        string out;\n        out.reserve(M);\n        for(char ch: actions) out.push_back(ch);\n        cout << out << '\\n';\n        cout.flush();\n\n        applyActions(actions, humanCnt, petCnt);\n\n        vector<string> pMoves(N);\n        for(int i=0; i<N; i++){\n            if(!(cin >> pMoves[i])) return;\n        }\n        applyPetMoves(pMoves);\n    }\n}\n\nint main(){\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    void reseed(uint64_t seed) { x = seed ? seed : 88172645463325252ull; }\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\nclass Solver {\n    static constexpr int H = 20;\n    static constexpr int W = 20;\n    static constexpr int N = 400;\n    static constexpr int L = 200;\n\n    int si, sj, ti, tj;\n    int start, target;\n    double p, q;\n    string h[H], v[H - 1];\n\n    int to_raw[N][4];\n    int to_eval[N][4];\n    double isTar[N];\n\n    vector<array<double, N>> fw, bw, ub;\n    array<double, L + 1> pref{};\n\n    vector<uint8_t> seq, bestSeq;\n    double curScore = -1e100, bestScore = -1e100;\n\n    vector<pair<double, vector<uint8_t>>> elite;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver() : fw(L + 1), bw(L + 1), ub(L + 1), seq(L), bestSeq(L) {}\n\n    void solve() {\n        readInput();\n        buildTransitions();\n        precomputeUB();\n\n        st = chrono::steady_clock::now();\n\n        vector<vector<uint8_t>> cands;\n        buildCandidates(cands);\n\n        elite.clear();\n        bestScore = -1e100;\n\n        for (auto &c : cands) {\n            seq = c;\n            curScore = recompute();\n            addElite(seq, curScore);\n        }\n\n        const double TL = 1.93;\n\n        // Initial refinement on top seeds\n        {\n            int use = min<int>(4, elite.size());\n            for (int i = 0; i < use && now() < 0.95; i++) {\n                seq = elite[i].second;\n                curScore = recompute();\n                updateBest();\n                double dl = min(TL, now() + 0.13);\n                localSearch(dl, 1);\n                if (now() < dl && rng.nextInt(100) < 50) {\n                    int w = 8 + rng.nextInt(8);\n                    int l = rng.nextInt(L - w + 1);\n                    beamPatch(l, w, 30, dl);\n                }\n                addElite(seq, curScore);\n            }\n        }\n\n        // Iterated local search\n        while (now() < TL - 0.08) {\n            int m = min<int>(6, elite.size());\n            int pick = 0;\n            int r = rng.nextInt(100);\n            if (m >= 2) {\n                if (r < 55) pick = 0;\n                else if (r < 85) pick = rng.nextInt(min(3, m));\n                else pick = rng.nextInt(m);\n            }\n\n            seq = elite[pick].second;\n            curScore = recompute();\n            updateBest();\n\n            int op = rng.nextInt(100);\n            if (op < 45) {\n                mutateCurrent();\n                curScore = recompute();\n                updateBest();\n            } else if (op < 75) {\n                int cut = rng.nextInt(L - 2);\n                regrowSuffixFromCut(cut, 0.12);\n                curScore = recompute();\n                updateBest();\n            } else {\n                bool ok = false;\n                for (int z = 0; z < 2 && now() < TL - 0.08; z++) {\n                    int w = 8 + rng.nextInt(9);\n                    int l = rng.nextInt(L - w + 1);\n                    int B = 24 + rng.nextInt(16);\n                    if (beamPatch(l, w, B, TL - 0.05)) {\n                        ok = true;\n                        break;\n                    }\n                }\n                if (!ok) {\n                    mutateCurrent();\n                    curScore = recompute();\n                    updateBest();\n                }\n            }\n\n            double dl = min(TL - 0.03, now() + 0.05);\n            localSearch(dl, 1);\n\n            if (now() < TL - 0.03 && rng.nextInt(100) < 35) {\n                int w = 7 + rng.nextInt(10);\n                int l = rng.nextInt(L - w + 1);\n                beamPatch(l, w, 30, TL - 0.02);\n            }\n\n            addElite(seq, curScore);\n        }\n\n        // Final polish from best\n        seq = bestSeq;\n        curScore = recompute();\n        updateBest();\n\n        while (now() < TL) {\n            bool imp = false;\n            imp |= singleSweep(TL);\n            if (now() < TL) imp |= pairSweep(TL);\n\n            if (!imp) {\n                bool pImp = false;\n                for (int z = 0; z < 3 && now() < TL; z++) {\n                    int w = 7 + rng.nextInt(10);\n                    int l = rng.nextInt(L - w + 1);\n                    if (beamPatch(l, w, 36, TL)) {\n                        pImp = true;\n                        break;\n                    }\n                }\n                if (!pImp) break;\n            }\n        }\n\n        const char mp[4] = {'U', 'D', 'L', 'R'};\n        string ans(L, 'U');\n        for (int i = 0; i < L; i++) ans[i] = mp[bestSeq[i]];\n        cout << ans << '\\n';\n    }\n\nprivate:\n    inline int id(int i, int j) const { return i * W + j; }\n\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void readInput() {\n        cin >> si >> sj >> ti >> tj >> p;\n        for (int i = 0; i < H; i++) cin >> h[i];\n        for (int i = 0; i < H - 1; i++) cin >> v[i];\n\n        start = id(si, sj);\n        target = id(ti, tj);\n        q = 1.0 - p;\n\n        uint64_t seed = 1469598103934665603ull;\n        auto mix = [&](uint64_t x) {\n            seed ^= x + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n        };\n        mix(si); mix(sj); mix(ti); mix(tj);\n        mix((uint64_t)llround(p * 1000.0));\n        for (int i = 0; i < H; i++) for (char c : h[i]) mix((uint64_t)c);\n        for (int i = 0; i < H - 1; i++) for (char c : v[i]) mix((uint64_t)c);\n        rng.reseed(seed);\n    }\n\n    void buildTransitions() {\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                int s = id(i, j);\n\n                // U\n                if (i == 0 || v[i - 1][j] == '1') to_raw[s][0] = s;\n                else to_raw[s][0] = id(i - 1, j);\n\n                // D\n                if (i == H - 1 || v[i][j] == '1') to_raw[s][1] = s;\n                else to_raw[s][1] = id(i + 1, j);\n\n                // L\n                if (j == 0 || h[i][j - 1] == '1') to_raw[s][2] = s;\n                else to_raw[s][2] = id(i, j - 1);\n\n                // R\n                if (j == W - 1 || h[i][j] == '1') to_raw[s][3] = s;\n                else to_raw[s][3] = id(i, j + 1);\n            }\n        }\n\n        for (int s = 0; s < N; s++) {\n            for (int a = 0; a < 4; a++) to_eval[s][a] = to_raw[s][a];\n            isTar[s] = (s == target ? 1.0 : 0.0);\n        }\n        // target absorbing\n        for (int a = 0; a < 4; a++) to_eval[target][a] = target;\n    }\n\n    inline void stepDist(const array<double, N>& cur, int a, array<double, N>& nxt) const {\n        nxt.fill(0.0);\n        for (int s = 0; s < N; s++) {\n            double pr = cur[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            if (n == s) {\n                nxt[s] += pr;\n            } else {\n                double mv = pr * q;\n                nxt[s] += pr - mv;\n                nxt[n] += mv;\n            }\n        }\n    }\n\n    inline double dotDouble(const array<double, N>& x, const array<double, N>& y) const {\n        double r = 0.0;\n        for (int s = 0; s < N; s++) r += x[s] * y[s];\n        return r;\n    }\n\n    inline double dotFloatDouble(const array<float, N>& x, const array<double, N>& y) const {\n        double r = 0.0;\n        for (int s = 0; s < N; s++) r += (double)x[s] * y[s];\n        return r;\n    }\n\n    void precomputeUB() {\n        ub[0].fill(0.0);\n        for (int rem = 1; rem <= L; rem++) {\n            int coef = (rem == 1 ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                double rs = isTar[s] * coef;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double cand;\n                    if (n == s) {\n                        cand = rs + ub[rem - 1][s];\n                    } else {\n                        double rn = isTar[n] * coef;\n                        cand = p * (rs + ub[rem - 1][s]) + q * (rn + ub[rem - 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                ub[rem][s] = best;\n            }\n        }\n    }\n\n    int bestActionUB1(const array<double, N>& dist, int t) const {\n        int rem = L - t;\n        int coef = (t + 1 == L ? 201 : 1);\n        const auto &U = ub[rem - 1];\n\n        int bestA = 0;\n        double bestV = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n            for (int s = 0; s < N; s++) {\n                double pr = dist[s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                double rs = isTar[s] * coef;\n                if (n == s) {\n                    val += pr * (rs + U[s]);\n                } else {\n                    double rn = isTar[n] * coef;\n                    val += pr * (p * (rs + U[s]) + q * (rn + U[n]));\n                }\n            }\n            if (val > bestV) {\n                bestV = val;\n                bestA = a;\n            }\n        }\n        return bestA;\n    }\n\n    int bestActionUB2(const array<double, N>& dist, int t) const {\n        int rem = L - t;\n        if (rem <= 1) return bestActionUB1(dist, t);\n\n        int c1 = (t + 1 == L ? 201 : 1);\n        int c2 = (t + 2 == L ? 201 : 1);\n        const auto &U = ub[rem - 2];\n\n        array<array<double, N>, 4> d1;\n        array<double, 4> v1{};\n        array<double, N> d2;\n\n        for (int a = 0; a < 4; a++) {\n            stepDist(dist, a, d1[a]);\n            v1[a] = c1 * d1[a][target];\n        }\n\n        int bestA = 0;\n        double bestV = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                stepDist(d1[a], b, d2);\n                double val = v1[a] + c2 * d2[target] + dotDouble(d2, U);\n                if (val > bestV) {\n                    bestV = val;\n                    bestA = a;\n                }\n            }\n        }\n        return bestA;\n    }\n\n    vector<int> shortestPath() {\n        vector<int> dist(N, -1), par(N, -1), pdir(N, -1);\n        queue<int> qu;\n        dist[start] = 0;\n        qu.push(start);\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            if (s == target) break;\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (dist[n] != -1) continue;\n                dist[n] = dist[s] + 1;\n                par[n] = s;\n                pdir[n] = a;\n                qu.push(n);\n            }\n        }\n\n        vector<int> path;\n        if (dist[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> weightedPath(double penUL, double noise) {\n        const double INF = 1e100;\n        vector<double> dist(N, INF);\n        vector<int> par(N, -1), pdir(N, -1);\n\n        array<array<double, 4>, N> rnd{};\n        for (int s = 0; s < N; s++) for (int a = 0; a < 4; a++) rnd[s][a] = rng.nextDouble();\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!pq.empty()) {\n            auto [cd, s] = pq.top();\n            pq.pop();\n            if (cd > dist[s] + 1e-15) continue;\n            if (s == target) break;\n\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                double w = 1.0 + ((a == 0 || a == 2) ? penUL : 0.0) + noise * rnd[s][a];\n                double nd = cd + w;\n                if (nd < dist[n]) {\n                    dist[n] = nd;\n                    par[n] = s;\n                    pdir[n] = a;\n                    pq.push({nd, n});\n                }\n            }\n        }\n\n        vector<int> path;\n        if (par[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> distToTarget() {\n        const int INF = 1e9;\n        vector<int> d(N, INF);\n        queue<int> qu;\n        d[target] = 0;\n        qu.push(target);\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            for (int a = 0; a < 4; a++) {\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (d[n] > d[s] + 1) {\n                    d[n] = d[s] + 1;\n                    qu.push(n);\n                }\n            }\n        }\n        return d;\n    }\n\n    vector<uint8_t> seedFromPath(const vector<int>& path, int rep, bool useUB2, double epsRand) {\n        vector<uint8_t> out;\n        out.reserve(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int dir : path) {\n            for (int k = 0; k < rep && (int)out.size() < L; k++) {\n                out.push_back((uint8_t)dir);\n                stepDist(cur, dir, nxt);\n                cur = nxt;\n            }\n            if ((int)out.size() >= L) break;\n        }\n\n        while ((int)out.size() < L) {\n            int t = (int)out.size();\n            int a = useUB2 ? bestActionUB2(cur, t) : bestActionUB1(cur, t);\n            if (epsRand > 0.0 && rng.nextDouble() < epsRand) a = rng.nextInt(4);\n            out.push_back((uint8_t)a);\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n\n        return out;\n    }\n\n    vector<uint8_t> greedyUBSeed(bool useUB2) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int a = useUB2 ? bestActionUB2(cur, t) : bestActionUB1(cur, t);\n            out[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n        return out;\n    }\n\n    vector<uint8_t> greedyStaticSeed(const vector<double>& val) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int bestA = 0;\n            double bestV = -1e100;\n\n            for (int a = 0; a < 4; a++) {\n                double v = 0.0;\n                for (int s = 0; s < N; s++) {\n                    double pr = cur[s];\n                    if (pr == 0.0) continue;\n                    int n = to_eval[s][a];\n                    if (n == s) v += pr * val[s];\n                    else v += pr * (p * val[s] + q * val[n]);\n                }\n                if (v > bestV) {\n                    bestV = v;\n                    bestA = a;\n                }\n            }\n\n            out[t] = (uint8_t)bestA;\n            stepDist(cur, bestA, nxt);\n            cur = nxt;\n        }\n\n        return out;\n    }\n\n    vector<uint8_t> globalBeamSeed(int B, double noise) {\n        struct Node {\n            array<float, N> dist;\n            double score;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double score;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> beam(1), nxt;\n        beam[0].dist.fill(0.0f);\n        beam[0].dist[start] = 1.0f;\n        beam[0].score = 0.0;\n        beam[0].key = ub[L][start];\n\n        vector<vector<pair<int, uint8_t>>> trace(L + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 8);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            return a.key > b.key;\n        };\n\n        for (int d = 0; d < L; d++) {\n            int coef = (d + 1 == L ? 201 : 1);\n            int rem = L - (d + 1); // remaining after this step\n            cand.clear();\n\n            for (int i = 0; i < (int)beam.size(); i++) {\n                const auto &nd = beam[i];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = i;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    for (int s = 0; s < N; s++) {\n                        float pr = nd.dist[s];\n                        if (pr == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += pr;\n                            if (s == target) inc += (double)pr;\n                        } else {\n                            float ps = (float)(pr * p);\n                            float pn = (float)(pr * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                        }\n                    }\n\n                    ch.score = nd.score + coef * inc;\n                    ch.key = ch.score + dotFloatDouble(ch.dist, ub[rem]);\n                    if (noise > 0.0) ch.key += noise * (rng.nextDouble() - 0.5);\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            nxt.resize(cand.size());\n            trace[d + 1].resize(cand.size());\n            for (int i = 0; i < (int)cand.size(); i++) {\n                nxt[i].dist = std::move(cand[i].dist);\n                nxt[i].score = cand[i].score;\n                nxt[i].key = cand[i].key;\n                trace[d + 1][i] = {cand[i].par, cand[i].act};\n            }\n            beam.swap(nxt);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)beam.size(); i++) {\n            if (beam[i].score > beam[bestIdx].score) bestIdx = i;\n        }\n\n        vector<uint8_t> out(L);\n        int idx = bestIdx;\n        for (int d = L; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            out[d - 1] = act;\n            idx = par;\n        }\n        return out;\n    }\n\n    void buildCandidates(vector<vector<uint8_t>>& cands) {\n        auto sp = shortestPath();\n        int rep0 = (int)llround(1.3 / max(1e-9, q));\n        rep0 = max(1, min(6, rep0));\n\n        vector<int> reps = {1, max(1, rep0 - 1), rep0, min(7, rep0 + 1), min(8, rep0 + 2)};\n        sort(reps.begin(), reps.end());\n        reps.erase(unique(reps.begin(), reps.end()), reps.end());\n\n        if (!sp.empty()) {\n            for (int rep : reps) cands.push_back(seedFromPath(sp, rep, false, 0.0));\n            cands.push_back(seedFromPath(sp, rep0, true, 0.0));\n            cands.push_back(seedFromPath(sp, min(8, rep0 + 1), true, 0.05));\n        }\n\n        vector<pair<double, double>> params = {\n            {0.0, 0.0},\n            {0.4, 0.0},\n            {0.8, 0.0},\n            {0.2, 0.25},\n            {0.6, 0.25}\n        };\n        for (auto [pen, noise] : params) {\n            auto pth = weightedPath(pen, noise);\n            if (pth.empty()) continue;\n            cands.push_back(seedFromPath(pth, rep0, false, 0.0));\n            cands.push_back(seedFromPath(pth, min(8, rep0 + 1), true, 0.02));\n        }\n\n        cands.push_back(greedyUBSeed(false));\n        cands.push_back(greedyUBSeed(true));\n\n        auto d = distToTarget();\n        vector<double> val(N);\n        for (int s = 0; s < N; s++) val[s] = -1.0 * d[s];\n        cands.push_back(greedyStaticSeed(val));\n\n        int Bmain = 120 + (p > 0.35 ? 20 : 0) + (p > 0.45 ? 10 : 0);\n        cands.push_back(globalBeamSeed(Bmain, 0.0));\n        if (now() < 0.70) cands.push_back(globalBeamSeed(70, 0.02));\n\n        // fallback patterns\n        vector<uint8_t> pat(L);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 1 : 3); // D...R...\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 3 : 1); // R...D...\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = ((i & 1) ? 3 : 1);   // D,R,D,R\n        cands.push_back(pat);\n\n        // random fallback\n        vector<uint8_t> rnd(L);\n        for (int i = 0; i < L; i++) rnd[i] = (uint8_t)rng.nextInt(4);\n        cands.push_back(rnd);\n    }\n\n    double recompute() {\n        fw[0].fill(0.0);\n        fw[0][start] = 1.0;\n        pref[0] = 0.0;\n\n        for (int t = 0; t < L; t++) {\n            fw[t + 1].fill(0.0);\n            int a = seq[t];\n            for (int s = 0; s < N; s++) {\n                double pr = fw[t][s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                if (n == s) {\n                    fw[t + 1][s] += pr;\n                } else {\n                    double mv = pr * q;\n                    fw[t + 1][s] += pr - mv;\n                    fw[t + 1][n] += mv;\n                }\n            }\n            int coef = (t + 1 == L ? 201 : 1);\n            pref[t + 1] = pref[t] + coef * fw[t + 1][target];\n        }\n\n        bw[L].fill(0.0);\n        for (int t = L - 1; t >= 0; t--) {\n            int a = seq[t];\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                int n = to_eval[s][a];\n                double rs = isTar[s] * coef;\n                if (n == s) {\n                    bw[t][s] = rs + bw[t + 1][s];\n                } else {\n                    double rn = isTar[n] * coef;\n                    bw[t][s] = p * (rs + bw[t + 1][s]) + q * (rn + bw[t + 1][n]);\n                }\n            }\n        }\n\n        return pref[L];\n    }\n\n    inline void updateBest() {\n        if (curScore > bestScore) {\n            bestScore = curScore;\n            bestSeq = seq;\n        }\n    }\n\n    void addElite(const vector<uint8_t>& s, double sc) {\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestSeq = s;\n        }\n\n        for (auto &e : elite) {\n            if (e.second == s) {\n                if (sc > e.first) e.first = sc;\n                sort(elite.begin(), elite.end(),\n                     [](const auto& a, const auto& b) { return a.first > b.first; });\n                return;\n            }\n        }\n\n        elite.push_back({sc, s});\n        sort(elite.begin(), elite.end(),\n             [](const auto& a, const auto& b) { return a.first > b.first; });\n        if ((int)elite.size() > 8) elite.resize(8);\n    }\n\n    double evalSingle(int pos, int a) const {\n        double total = pref[pos];\n        int coef = (pos + 1 == L ? 201 : 1);\n\n        const auto &dist = fw[pos];\n        const auto &suf = bw[pos + 1];\n\n        for (int s = 0; s < N; s++) {\n            double pr = dist[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            double rs = isTar[s] * coef;\n            double v;\n            if (n == s) {\n                v = rs + suf[s];\n            } else {\n                double rn = isTar[n] * coef;\n                v = p * (rs + suf[s]) + q * (rn + suf[n]);\n            }\n            total += pr * v;\n        }\n        return total;\n    }\n\n    bool singleSweep(double deadline) {\n        bool improved = false;\n        array<int, L> ord;\n        iota(ord.begin(), ord.end(), 0);\n        for (int i = L - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        for (int ii = 0; ii < L; ii++) {\n            if ((ii & 15) == 0 && now() >= deadline) break;\n            int pos = ord[ii];\n\n            int curA = seq[pos];\n            int bestA = curA;\n            double bestV = curScore;\n\n            for (int a = 0; a < 4; a++) {\n                if (a == curA) continue;\n                double sc = evalSingle(pos, a);\n                if (sc > bestV + 1e-12) {\n                    bestV = sc;\n                    bestA = a;\n                }\n            }\n\n            if (bestA != curA) {\n                seq[pos] = (uint8_t)bestA;\n                curScore = recompute();\n                updateBest();\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    bool pairSweep(double deadline) {\n        bool improved = false;\n        array<int, L - 1> ord;\n        iota(ord.begin(), ord.end(), 0);\n        for (int i = L - 2; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        array<array<double, N>, 4> d1;\n        array<double, 4> base1{};\n        array<double, N> d2;\n\n        for (int ii = 0; ii < L - 1; ii++) {\n            if ((ii & 7) == 0 && now() >= deadline) break;\n            int pos = ord[ii];\n\n            int curA = seq[pos], curB = seq[pos + 1];\n            int bestA = curA, bestB = curB;\n            double bestV = curScore;\n\n            const auto &dist0 = fw[pos];\n            const auto &suf = bw[pos + 2];\n            int c1 = (pos + 1 == L ? 201 : 1);\n            int c2 = (pos + 2 == L ? 201 : 1);\n\n            for (int a = 0; a < 4; a++) {\n                stepDist(dist0, a, d1[a]);\n                base1[a] = pref[pos] + c1 * d1[a][target];\n            }\n\n            for (int a = 0; a < 4; a++) {\n                for (int b = 0; b < 4; b++) {\n                    stepDist(d1[a], b, d2);\n                    double sc = base1[a] + c2 * d2[target];\n                    double tail = 0.0;\n                    for (int s = 0; s < N; s++) tail += d2[s] * suf[s];\n                    sc += tail;\n\n                    if (sc > bestV + 1e-12) {\n                        bestV = sc;\n                        bestA = a;\n                        bestB = b;\n                    }\n                }\n            }\n\n            if (bestA != curA || bestB != curB) {\n                seq[pos] = (uint8_t)bestA;\n                seq[pos + 1] = (uint8_t)bestB;\n                curScore = recompute();\n                updateBest();\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    bool localSearch(double deadline, int rounds) {\n        bool any = false;\n        for (int r = 0; r < rounds && now() < deadline; r++) {\n            bool imp = false;\n            imp |= singleSweep(deadline);\n            if (now() < deadline) imp |= pairSweep(deadline);\n            any |= imp;\n            if (!imp) break;\n        }\n        return any;\n    }\n\n    void regrowSuffixFromCut(int cut, double epsRand) {\n        array<double, N> cur = fw[cut], nxt;\n        for (int t = cut; t < L; t++) {\n            int a = bestActionUB2(cur, t);\n            if (epsRand > 0.0 && rng.nextDouble() < epsRand) a = rng.nextInt(4);\n            seq[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n    }\n\n    void mutateCurrent() {\n        int type = rng.nextInt(100);\n\n        if (type < 45) {\n            int m = 1 + rng.nextInt(5);\n            for (int k = 0; k < m; k++) {\n                int pos = rng.nextInt(L);\n                seq[pos] = (uint8_t)rng.nextInt(4);\n            }\n        } else if (type < 75) {\n            int len = 6 + rng.nextInt(24);\n            len = min(len, L);\n            int l = rng.nextInt(L - len + 1);\n            for (int i = 0; i < len; i++) seq[l + i] = (uint8_t)rng.nextInt(4);\n        } else {\n            int cut = rng.nextInt(L - 2);\n            regrowSuffixFromCut(cut, 0.15);\n        }\n    }\n\n    bool beamPatch(int l, int w, int B, double deadline) {\n        if (now() >= deadline) return false;\n        int r = l + w - 1;\n\n        // Adaptive upper bound for this window + fixed suffix\n        vector<array<double, N>> Hh(w + 1);\n        Hh[w] = bw[r + 1];\n        for (int i = w - 1; i >= 0; i--) {\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                double rs = isTar[s] * coef;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double cand;\n                    if (n == s) {\n                        cand = rs + Hh[i + 1][s];\n                    } else {\n                        double rn = isTar[n] * coef;\n                        cand = p * (rs + Hh[i + 1][s]) + q * (rn + Hh[i + 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                Hh[i][s] = best;\n            }\n        }\n\n        struct Node {\n            array<float, N> dist;\n            double local;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double local;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> cur(1), nxt;\n        cur[0].dist.fill(0.0f);\n        for (int s = 0; s < N; s++) cur[0].dist[s] = (float)fw[l][s];\n        cur[0].local = 0.0;\n        cur[0].key = dotFloatDouble(cur[0].dist, Hh[0]);\n\n        vector<vector<pair<int, uint8_t>>> trace(w + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 8);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            return a.key > b.key;\n        };\n\n        for (int i = 0; i < w; i++) {\n            if ((i & 1) == 0 && now() >= deadline) return false;\n\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n\n            cand.clear();\n            for (int bi = 0; bi < (int)cur.size(); bi++) {\n                const auto &nd = cur[bi];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = bi;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    for (int s = 0; s < N; s++) {\n                        float pr = nd.dist[s];\n                        if (pr == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += pr;\n                            if (s == target) inc += (double)pr;\n                        } else {\n                            float ps = (float)(pr * p);\n                            float pn = (float)(pr * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                        }\n                    }\n\n                    ch.local = nd.local + coef * inc;\n                    ch.key = ch.local + dotFloatDouble(ch.dist, Hh[i + 1]);\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if (cand.empty()) return false;\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            nxt.resize(cand.size());\n            trace[i + 1].resize(cand.size());\n            for (int j = 0; j < (int)cand.size(); j++) {\n                nxt[j].dist = std::move(cand[j].dist);\n                nxt[j].local = cand[j].local;\n                nxt[j].key = cand[j].key;\n                trace[i + 1][j] = {cand[j].par, cand[j].act};\n            }\n            cur.swap(nxt);\n        }\n\n        const auto &tail = bw[r + 1];\n        int bestIdx = 0;\n        double bestVal = -1e100;\n        for (int i = 0; i < (int)cur.size(); i++) {\n            double val = cur[i].local + dotFloatDouble(cur[i].dist, tail);\n            if (val > bestVal) {\n                bestVal = val;\n                bestIdx = i;\n            }\n        }\n\n        vector<uint8_t> acts(w);\n        int idx = bestIdx;\n        for (int d = w; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            acts[d - 1] = act;\n            idx = par;\n        }\n\n        // Exact score of patched segment\n        array<double, N> dist = fw[l], nxtd;\n        double seg = 0.0;\n        for (int i = 0; i < w; i++) {\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n            stepDist(dist, acts[i], nxtd);\n            seg += coef * nxtd[target];\n            dist = nxtd;\n        }\n        double tailVal = dotDouble(dist, tail);\n        double newScore = pref[l] + seg + tailVal;\n\n        if (newScore > curScore + 1e-12) {\n            for (int i = 0; i < w; i++) seq[l + i] = acts[i];\n            curScore = recompute();\n            updateBest();\n            return true;\n        }\n        return false;\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}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int C = N * N;\nstatic constexpr int S = C * 4;\n\nint 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\nuint8_t SIDE[8] = {\n    (1u << 0) | (1u << 1), // 0\n    (1u << 0) | (1u << 3), // 1\n    (1u << 2) | (1u << 3), // 2\n    (1u << 1) | (1u << 2), // 3\n    0b1111,                // 4\n    0b1111,                // 5\n    (1u << 0) | (1u << 2), // 6\n    (1u << 1) | (1u << 3), // 7\n};\n\nint ROT1[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nint ROT[8][4];\nint NEI[C][4];\nint OPP[4] = {2, 3, 0, 1};\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463393265ull) {\n        x = seed ^ 0x9e3779b97f4a7c15ULL;\n        if (x == 0) x = 88172645463393265ull;\n        for (int i = 0; i < 8; i++) next_u64();\n    }\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t next_u32() { return static_cast<uint32_t>(next_u64()); }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Eval {\n    int l1 = 0, l2 = 0, l3 = 0, l4 = 0;\n    int loopCnt = 0;\n    int sumLoop = 0;\n    int matched = 0;\n    long long contest = 0;\n};\n\ninline bool better_best(const Eval& a, const Eval& b) {\n    if (a.contest != b.contest) return a.contest > b.contest;\n    if (a.l1 != b.l1) return a.l1 > b.l1;\n    if (a.l2 != b.l2) return a.l2 > b.l2;\n    if (a.l3 != b.l3) return a.l3 > b.l3;\n    if (a.sumLoop != b.sumLoop) return a.sumLoop > b.sumLoop;\n    return a.matched > b.matched;\n}\n\ninline double objective(const Eval& e, double p) {\n    double core;\n    if (e.loopCnt >= 2) {\n        core = (double)e.l1 * (double)e.l2; // contest score\n    } else {\n        core = -3000.0 + 25.0 * e.l1 + 8.0 * e.sumLoop + 120.0 * e.loopCnt;\n    }\n    double early = 3.5 * e.sumLoop + 1.2 * e.l1 + 1.0 * e.l2 + 0.6 * e.l3 + 0.05 * e.matched;\n    double w = 0.2 + 0.8 * p; // p=1 -> pure core\n    return (1.0 - w) * early + w * core;\n}\n\ninline double elapsed_sec(const chrono::steady_clock::time_point& st) {\n    return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n}\n\nstruct Evaluator {\n    int nxt[S];\n    int partner[S];\n    int vis[S];\n    int posi[S];\n    int stk[S];\n    uint8_t done[S];\n    uint8_t canon[S];\n\n    Eval eval(const array<uint8_t, C>& board) {\n        uint8_t mask[C];\n        for (int c = 0; c < C; c++) mask[c] = SIDE[board[c]];\n\n        int matched = 0;\n        for (int i = 0; i < N; i++) {\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                int c = base + j;\n                uint8_t m = mask[c];\n                if (j + 1 < N) {\n                    if ((m & (1 << 2)) && (mask[c + 1] & (1 << 0))) matched++;\n                }\n                if (i + 1 < N) {\n                    if ((m & (1 << 3)) && (mask[c + N] & (1 << 1))) matched++;\n                }\n            }\n        }\n\n        for (int c = 0; c < C; c++) {\n            int t = board[c];\n            int c4 = c << 2;\n            for (int d = 0; d < 4; d++) {\n                int s = c4 | d;\n                int d2 = TO[t][d];\n                if (d2 < 0) {\n                    nxt[s] = -1;\n                    partner[s] = -1;\n                    continue;\n                }\n                partner[s] = c4 | d2;\n                int nc = NEI[c][d2];\n                if (nc < 0) {\n                    nxt[s] = -1;\n                    continue;\n                }\n                if (mask[nc] & (1 << OPP[d2])) nxt[s] = (nc << 2) | OPP[d2];\n                else nxt[s] = -1;\n            }\n        }\n\n        memset(done, 0, sizeof(done));\n        memset(vis, 0, sizeof(vis));\n        memset(canon, 0, sizeof(canon));\n\n        int iter = 1;\n        int loopCnt = 0;\n        int sumLoop = 0;\n        int t0 = 0, t1 = 0, t2 = 0, t3 = 0;\n\n        auto push_len = [&](int len) {\n            if (len > t0) {\n                t3 = t2; t2 = t1; t1 = t0; t0 = len;\n            } else if (len > t1) {\n                t3 = t2; t2 = t1; t1 = len;\n            } else if (len > t2) {\n                t3 = t2; t2 = len;\n            } else if (len > t3) {\n                t3 = len;\n            }\n        };\n\n        for (int s0 = 0; s0 < S; s0++) {\n            if (done[s0]) continue;\n\n            int cur = s0;\n            int top = 0;\n            while (cur != -1 && !done[cur] && vis[cur] != iter) {\n                vis[cur] = iter;\n                posi[cur] = top;\n                stk[top++] = cur;\n                cur = nxt[cur];\n            }\n\n            if (cur != -1 && !done[cur] && vis[cur] == iter) {\n                int st = posi[cur];\n                int len = top - st;\n                int can = INT_MAX;\n                for (int k = st; k < top; k++) {\n                    int v = stk[k];\n                    int p = partner[v];\n                    int m = (v < p ? v : p);\n                    if (m < can) can = m;\n                }\n                if (!canon[can]) {\n                    canon[can] = 1;\n                    loopCnt++;\n                    sumLoop += len;\n                    push_len(len);\n                }\n            }\n\n            for (int k = 0; k < top; k++) done[stk[k]] = 1;\n            iter++;\n        }\n\n        Eval e;\n        e.l1 = t0;\n        e.l2 = t1;\n        e.l3 = t2;\n        e.l4 = t3;\n        e.loopCnt = loopCnt;\n        e.sumLoop = sumLoop;\n        e.matched = matched;\n        e.contest = (loopCnt >= 2 ? 1LL * t0 * t1 : 0LL);\n        return e;\n    }\n};\n\ninline int cell_badness(int c, const array<uint8_t, C>& board) {\n    uint8_t m = SIDE[board[c]];\n    int bad = 0;\n    for (int d = 0; d < 4; d++) {\n        int nc = NEI[c][d];\n        int b1 = (m >> d) & 1;\n        if (nc < 0) {\n            if (b1) bad += 2;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 != b2) bad += 1;\n        }\n    }\n    return bad;\n}\n\ninline int local_potential(int c, uint8_t cand, const array<uint8_t, C>& board) {\n    int score = 0;\n    uint8_t m = SIDE[cand];\n\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) score -= 6;\n            continue;\n        }\n        int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n        if (b1 && b2) score += 4;\n        else if (b1 ^ b2) score -= 3;\n    }\n\n    for (int d = 0; d < 4; d++) {\n        int d2 = TO[cand][d];\n        if (d2 < 0) continue;\n        int nc = NEI[c][d2];\n        if (nc >= 0 && (SIDE[board[nc]] & (1 << OPP[d2]))) score += 1;\n        else score -= 1;\n    }\n    return score;\n}\n\nvoid improve_connectivity(\n    array<uint8_t, C>& board,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng,\n    int passes\n) {\n    array<int, C> ord;\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int p = 0; p < passes; p++) {\n        for (int i = C - 1; i > 0; i--) {\n            int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n            swap(ord[i], ord[j]);\n        }\n        for (int id = 0; id < C; id++) {\n            int c = ord[id];\n            int bestScore = INT_MIN;\n            uint8_t bestState = board[c];\n            for (int k = 0; k < possCnt[c]; k++) {\n                uint8_t cand = poss[c][k];\n                int sc = local_potential(c, cand, board);\n                if (sc > bestScore || (sc == bestScore && (rng.next_u32() & 1))) {\n                    bestScore = sc;\n                    bestState = cand;\n                }\n            }\n            board[c] = bestState;\n        }\n    }\n}\n\nvoid pair_hillclimb(\n    array<uint8_t, C>& board,\n    Eval& curEval,\n    const vector<int>& cells,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int passes,\n    const chrono::steady_clock::time_point& start,\n    double deadline_sec\n) {\n    if (cells.empty()) return;\n    vector<int> ord = cells;\n    double curObj = objective(curEval, p);\n\n    for (int pass = 0; pass < passes; pass++) {\n        for (int i = (int)ord.size() - 1; i > 0; i--) {\n            int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n            swap(ord[i], ord[j]);\n        }\n        for (int idx = 0; idx < (int)ord.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec(start) >= deadline_sec) return;\n            int c = ord[idx];\n            if (possCnt[c] != 2) continue;\n            uint8_t old = board[c];\n            uint8_t nw = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n            board[c] = nw;\n            Eval ne = evaluator.eval(board);\n            double o = objective(ne, p);\n            if (o >= curObj) {\n                curEval = ne;\n                curObj = o;\n            } else {\n                board[c] = old;\n            }\n        }\n    }\n}\n\nvoid exact_subset_descent(\n    array<uint8_t, C>& board,\n    Eval& curEval,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int maxCells,\n    const chrono::steady_clock::time_point& start,\n    double deadline_sec\n) {\n    if (maxCells <= 0) return;\n    if (maxCells > C) maxCells = C;\n\n    array<int, C> ord;\n    iota(ord.begin(), ord.end(), 0);\n    for (int i = C - 1; i > 0; i--) {\n        int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n        swap(ord[i], ord[j]);\n    }\n\n    double curObj = objective(curEval, p);\n\n    for (int ii = 0; ii < maxCells; ii++) {\n        if ((ii & 15) == 0 && elapsed_sec(start) >= deadline_sec) return;\n\n        int c = ord[ii];\n        uint8_t old = board[c];\n\n        uint8_t bestState = old;\n        Eval bestEval = curEval;\n        double bestObj = curObj;\n\n        for (int k = 0; k < possCnt[c]; k++) {\n            uint8_t cand = poss[c][k];\n            if (cand == old) continue;\n            board[c] = cand;\n            Eval ne = evaluator.eval(board);\n            double o = objective(ne, p);\n            if (o > bestObj + 1e-12) {\n                bestObj = o;\n                bestState = cand;\n                bestEval = ne;\n            }\n        }\n\n        board[c] = bestState;\n        if (bestState != old) {\n            curEval = bestEval;\n            curObj = bestObj;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int t = 0; t < 8; t++) {\n        ROT[t][0] = t;\n        for (int k = 1; k < 4; k++) ROT[t][k] = ROT1[ROT[t][k - 1]];\n    }\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = i * N + j;\n            NEI[c][0] = (j > 0 ? c - 1 : -1);\n            NEI[c][1] = (i > 0 ? c - N : -1);\n            NEI[c][2] = (j + 1 < N ? c + 1 : -1);\n            NEI[c][3] = (i + 1 < N ? c + N : -1);\n        }\n    }\n\n    array<uint8_t, C> orig{};\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) orig[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    seed ^= (uint64_t)(uintptr_t)&seed;\n    RNG rng(seed);\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.94;\n    const double SA_END = TL - 0.12;\n\n    array<array<uint8_t, 4>, C> poss{};\n    array<uint8_t, C> possCnt{};\n    vector<int> twoStateCells;\n    vector<int> doubleCells;\n\n    for (int c = 0; c < C; c++) {\n        int t = orig[c];\n        if (t <= 3) {\n            possCnt[c] = 4;\n            for (int k = 0; k < 4; k++) poss[c][k] = (uint8_t)ROT[t][k];\n        } else if (t <= 5) {\n            possCnt[c] = 2;\n            poss[c][0] = 4;\n            poss[c][1] = 5;\n            twoStateCells.push_back(c);\n            doubleCells.push_back(c);\n        } else {\n            possCnt[c] = 2;\n            poss[c][0] = 6;\n            poss[c][1] = 7;\n            twoStateCells.push_back(c);\n        }\n    }\n\n    auto random_other = [&](int c, uint8_t old, array<uint8_t, C>& st) {\n        if (possCnt[c] == 2) {\n            st[c] = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n        } else {\n            uint8_t nw = old;\n            do nw = poss[c][rng.next_u32() & 3];\n            while (nw == old);\n            st[c] = nw;\n        }\n    };\n\n    Evaluator evaluator;\n\n    array<uint8_t, C> bestState = orig;\n    Eval bestEval = evaluator.eval(bestState);\n\n    const int KSEED = 5;\n    vector<array<uint8_t, C>> seedStates;\n    vector<Eval> seedEvals;\n    vector<double> seedKeys;\n    auto add_seed = [&](const array<uint8_t, C>& st, const Eval& ev, double key) {\n        if ((int)seedStates.size() < KSEED) {\n            seedStates.push_back(st);\n            seedEvals.push_back(ev);\n            seedKeys.push_back(key);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < KSEED; i++) {\n            if (seedKeys[i] < seedKeys[wi]) wi = i;\n        }\n        if (key > seedKeys[wi]) {\n            seedStates[wi] = st;\n            seedEvals[wi] = ev;\n            seedKeys[wi] = key;\n        }\n    };\n\n    add_seed(bestState, bestEval, objective(bestEval, 0.2));\n\n    // Initialization\n    const double initDeadline = 0.34;\n    int trial = 0;\n    while (elapsed_sec(start) < initDeadline && trial < 14) {\n        array<uint8_t, C> cand;\n\n        if (trial == 0) {\n            cand = orig;\n        } else if (trial % 3 == 0) {\n            cand = bestState;\n            int flips = 25 + (int)(rng.next_u32() % 45);\n            for (int f = 0; f < flips; f++) {\n                int c = (int)(rng.next_u32() % C);\n                random_other(c, cand[c], cand);\n            }\n        } else {\n            for (int c = 0; c < C; c++) {\n                if (possCnt[c] == 4) cand[c] = poss[c][rng.next_u32() & 3];\n                else cand[c] = poss[c][rng.next_u32() & 1];\n            }\n        }\n\n        int passes = (trial == 0 ? 8 : 5 + (trial % 3));\n        improve_connectivity(cand, poss, possCnt, rng, passes);\n\n        Eval e = evaluator.eval(cand);\n\n        if (trial < 6 && elapsed_sec(start) < initDeadline - 0.01) {\n            pair_hillclimb(cand, e, twoStateCells, poss, possCnt, evaluator, rng, 0.18, 1, start, initDeadline);\n        }\n        if (trial < 4 && elapsed_sec(start) < initDeadline - 0.005) {\n            exact_subset_descent(cand, e, poss, possCnt, evaluator, rng, 0.20, 140, start, initDeadline);\n        }\n\n        if (better_best(e, bestEval)) {\n            bestEval = e;\n            bestState = cand;\n        }\n\n        add_seed(cand, e, objective(e, 0.22));\n        trial++;\n    }\n\n    if (seedStates.empty()) {\n        seedStates.push_back(bestState);\n        seedEvals.push_back(bestEval);\n        seedKeys.push_back(objective(bestEval, 0.2));\n    }\n\n    int startIdx = 0;\n    for (int i = 1; i < (int)seedStates.size(); i++) {\n        if (seedKeys[i] > seedKeys[startIdx]) startIdx = i;\n    }\n\n    array<uint8_t, C> curState = seedStates[startIdx];\n    Eval curEval = seedEvals[startIdx];\n    if (better_best(curEval, bestEval)) {\n        bestEval = curEval;\n        bestState = curState;\n    }\n\n    // Small pre-SA intensification\n    if (elapsed_sec(start) < 0.55) {\n        double d = min(SA_END, elapsed_sec(start) + 0.05);\n        pair_hillclimb(curState, curEval, twoStateCells, poss, possCnt, evaluator, rng, 0.25, 1, start, d);\n        exact_subset_descent(curState, curEval, poss, possCnt, evaluator, rng, 0.25, 220, start, d);\n        if (better_best(curEval, bestEval)) {\n            bestEval = curEval;\n            bestState = curState;\n            add_seed(bestState, bestEval, objective(bestEval, 0.5));\n        }\n    }\n\n    // SA\n    long long iter = 0;\n    long long lastBestIter = 0;\n    long long lastRestartIter = 0;\n    long long lastIntenseIter = 0;\n\n    const double T0 = 160.0;\n    const double T1 = 0.03;\n    double progress = min(1.0, elapsed_sec(start) / TL);\n    double temp = T0 * pow(T1 / T0, progress);\n\n    auto pick_cell = [&]() -> int {\n        uint32_t r = rng.next_u32() % 100;\n        if (r < 18 && !doubleCells.empty()) {\n            return doubleCells[rng.next_u32() % doubleCells.size()];\n        }\n        if (r < 65) {\n            int best = (int)(rng.next_u32() % C);\n            int bestB = -1;\n            for (int t = 0; t < 5; t++) {\n                int c = (int)(rng.next_u32() % C);\n                int b = cell_badness(c, curState);\n                if (b > bestB) {\n                    bestB = b;\n                    best = c;\n                }\n            }\n            return best;\n        }\n        return (int)(rng.next_u32() % C);\n    };\n\n    while (true) {\n        if ((iter & 127LL) == 0) {\n            double now = elapsed_sec(start);\n            if (now >= SA_END) break;\n            progress = now / TL;\n            if (progress > 1.0) progress = 1.0;\n            temp = T0 * pow(T1 / T0, progress);\n\n            if (iter - lastBestIter > 7000 && iter - lastIntenseIter > 5000 && progress < 0.90) {\n                double d = min(SA_END, now + 0.025);\n                exact_subset_descent(curState, curEval, poss, possCnt, evaluator, rng, max(0.28, progress), 90, start, d);\n                if (better_best(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    lastBestIter = iter;\n                    add_seed(bestState, bestEval, objective(bestEval, 0.7));\n                }\n                lastIntenseIter = iter;\n            }\n\n            if (iter - lastBestIter > 15000 && iter - lastRestartIter > 6000) {\n                if (!seedStates.empty() && (rng.next_u32() % 100) < 50) {\n                    int si = (int)(rng.next_u32() % seedStates.size());\n                    curState = seedStates[si];\n                    curEval = seedEvals[si];\n                } else {\n                    curState = bestState;\n                    curEval = bestEval;\n                }\n                int flips = 24 + (int)(rng.next_u32() % 38);\n                for (int f = 0; f < flips; f++) {\n                    int c = (int)(rng.next_u32() % C);\n                    random_other(c, curState[c], curState);\n                }\n                improve_connectivity(curState, poss, possCnt, rng, 1);\n                curEval = evaluator.eval(curState);\n                lastRestartIter = iter;\n            }\n        }\n\n        double curObj = objective(curEval, progress);\n\n        int changedCount = 0;\n        int changedIdx[16];\n        uint8_t oldVal[16];\n\n        int mt = (int)(rng.next_u32() % 100);\n\n        if (mt < 40 && !doubleCells.empty()) {\n            int c = doubleCells[rng.next_u32() % doubleCells.size()];\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changedCount = 1;\n            curState[c] = (curState[c] == 4 ? 5 : 4);\n        } else if (mt < 78) {\n            int c = pick_cell();\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changedCount = 1;\n            random_other(c, curState[c], curState);\n        } else if (mt < 90) {\n            int c1 = pick_cell();\n            int c2 = (int)(rng.next_u32() % C);\n            while (c2 == c1) c2 = (int)(rng.next_u32() % C);\n\n            changedIdx[0] = c1; oldVal[0] = curState[c1];\n            changedIdx[1] = c2; oldVal[1] = curState[c2];\n            changedCount = 2;\n\n            random_other(c1, curState[c1], curState);\n            random_other(c2, curState[c2], curState);\n        } else if (mt < 97) {\n            int i = (int)(rng.next_u32() % (N - 1));\n            int j = (int)(rng.next_u32() % (N - 1));\n            int delta = (rng.next_u32() & 1) ? 1 : 3;\n            int c0 = i * N + j;\n            int cells[4] = {c0, c0 + 1, c0 + N, c0 + N + 1};\n            for (int k = 0; k < 4; k++) {\n                changedIdx[k] = cells[k];\n                oldVal[k] = curState[cells[k]];\n            }\n            changedCount = 4;\n            for (int k = 0; k < 4; k++) curState[cells[k]] = (uint8_t)ROT[curState[cells[k]]][delta];\n        } else {\n            int i = (int)(rng.next_u32() % (N - 2));\n            int j = (int)(rng.next_u32() % (N - 2));\n            changedCount = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    int c = (i + di) * N + (j + dj);\n                    changedIdx[changedCount] = c;\n                    oldVal[changedCount] = curState[c];\n                    changedCount++;\n                    if (possCnt[c] == 4) curState[c] = poss[c][rng.next_u32() & 3];\n                    else curState[c] = poss[c][rng.next_u32() & 1];\n                }\n            }\n        }\n\n        Eval ne = evaluator.eval(curState);\n        double newObj = objective(ne, progress);\n        double diff = newObj - curObj;\n\n        bool accept = false;\n        if (diff >= 0) accept = true;\n        else if (rng.next_double() < exp(diff / temp)) accept = true;\n\n        if (accept) {\n            curEval = ne;\n            if (better_best(curEval, bestEval)) {\n                bestEval = curEval;\n                bestState = curState;\n                lastBestIter = iter;\n                add_seed(bestState, bestEval, objective(bestEval, 0.85));\n            }\n        } else {\n            for (int k = 0; k < changedCount; k++) curState[changedIdx[k]] = oldVal[k];\n        }\n\n        iter++;\n    }\n\n    // Final polish\n    array<uint8_t, C> polState = bestState;\n    Eval polEval = bestEval;\n\n    double finalP = 0.97;\n    double now = elapsed_sec(start);\n    double finalDeadline = TL - 0.003;\n\n    if (now < finalDeadline) {\n        double d1 = min(finalDeadline, now + 0.04);\n        pair_hillclimb(polState, polEval, twoStateCells, poss, possCnt, evaluator, rng, finalP, 1, start, d1);\n        exact_subset_descent(polState, polEval, poss, possCnt, evaluator, rng, finalP, C, start, finalDeadline);\n        if (better_best(polEval, bestEval)) {\n            bestEval = polEval;\n            bestState = polState;\n        }\n    }\n\n    string ans(C, '0');\n    for (int c = 0; c < C; c++) {\n        int o = orig[c];\n        int f = bestState[c];\n        int rot = 0;\n        for (; rot < 4; rot++) {\n            if (ROT[o][rot] == f) break;\n        }\n        if (rot == 4) rot = 0;\n        ans[c] = char('0' + rot);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N_global, T_global, NN_global, FULLV;\nint NEI[100][4];\nuint64_t zobrist[100][16];\n\nconst int OPP[4] = {1, 0, 3, 2};\nconst char OPCH[4] = {'U', 'D', 'L', 'R'};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n};\n\nstatic inline uint64_t splitmix64(uint64_t &x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstruct AdjEdge {\n    uint8_t u, v;\n    uint8_t mu, mv;\n};\nvector<AdjEdge> g_edges;\n\nusing Board = array<uint8_t, 100>;\n\ninline int uf_find(int x, int parent[]) {\n    while (parent[x] != x) {\n        parent[x] = parent[parent[x]];\n        x = parent[x];\n    }\n    return x;\n}\n\nstruct EvalInfo {\n    int S = 0;         // largest acyclic connected component\n    int cmax = 0;      // largest connected component\n    int cmaxEx = 0;    // cycle excess of largest connected component\n    int totalEx = 0;   // sum of cycle excesses\n    int totalEdges = 0;\n\n    int pot4 = 0;      // max(v - 4*ex)\n    int pot7 = 0;      // max(v - 7*ex)\n    int near1 = 0;     // max component size with ex <= 1\n    int treeSum = 0;   // sum of vertices in tree-components\n};\n\nEvalInfo evaluate_state(const Board &b) {\n    int parent[100];\n    int sz[100];\n    int ed[100];\n\n    for (int i = 0; i < NN_global; i++) {\n        if (b[i] != 0) {\n            parent[i] = i;\n            sz[i] = 1;\n            ed[i] = 0;\n        } else {\n            parent[i] = -1;\n        }\n    }\n\n    for (const auto &e : g_edges) {\n        uint8_t a = b[e.u];\n        uint8_t c = b[e.v];\n        if (a != 0 && c != 0 && (a & e.mu) && (c & e.mv)) {\n            int ra = uf_find((int)e.u, parent);\n            int rb = uf_find((int)e.v, parent);\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\n    EvalInfo out;\n    bool first = true;\n    for (int i = 0; i < NN_global; i++) {\n        if (parent[i] == i) {\n            int v = sz[i];\n            int e = ed[i];\n            int ex = e - (v - 1);\n\n            if (ex == 0) {\n                out.S = max(out.S, v);\n                out.treeSum += v;\n            }\n            if (ex <= 1) out.near1 = max(out.near1, v);\n\n            out.pot4 = max(out.pot4, v - 4 * ex);\n            out.pot7 = max(out.pot7, v - 7 * ex);\n\n            out.totalEx += ex;\n            out.totalEdges += e;\n\n            if (first || v > out.cmax || (v == out.cmax && ex < out.cmaxEx)) {\n                out.cmax = v;\n                out.cmaxEx = ex;\n                first = false;\n            }\n        }\n    }\n\n    if (out.pot4 < 0) out.pot4 = 0;\n    if (out.pot7 < 0) out.pot7 = 0;\n    return out;\n}\n\ninline long long calc_key(const EvalInfo &e, int depth, int mode) {\n    int r = (T_global > 0 ? depth * 1000 / T_global : 1000);\n    int edgeGap = abs(e.totalEdges - (FULLV - 1));\n\n    if (mode == 0) {\n        // connect-first -> tree\n        if (r < 300) {\n            return 4200000LL * e.cmax\n                 + 2600000LL * e.pot4\n                 +  900000LL * e.S\n                 +  400000LL * e.near1\n                 +  120000LL * e.treeSum\n                 - 1100000LL * e.cmaxEx\n                 -   45000LL * e.totalEx\n                 -   13000LL * edgeGap;\n        } else if (r < 700) {\n            return 3000000LL * e.cmax\n                 + 3000000LL * e.pot4\n                 + 2200000LL * e.S\n                 +  800000LL * e.near1\n                 +  200000LL * e.treeSum\n                 - 1700000LL * e.cmaxEx\n                 -   70000LL * e.totalEx\n                 -   19000LL * edgeGap;\n        } else {\n            return 5300000LL * e.S\n                 + 2500000LL * e.pot4\n                 + 1200000LL * e.near1\n                 +  800000LL * e.cmax\n                 +  300000LL * e.treeSum\n                 - 2200000LL * e.cmaxEx\n                 -  100000LL * e.totalEx\n                 -   24000LL * edgeGap;\n        }\n    } else if (mode == 1) {\n        // balanced\n        if (r < 250) {\n            return 3800000LL * e.cmax\n                 + 2400000LL * e.pot4\n                 + 1500000LL * e.S\n                 +  600000LL * e.near1\n                 +  100000LL * e.treeSum\n                 - 1300000LL * e.cmaxEx\n                 -   50000LL * e.totalEx\n                 -   15000LL * edgeGap;\n        } else if (r < 700) {\n            return 4000000LL * e.pot4\n                 + 3900000LL * e.S\n                 + 1600000LL * e.cmax\n                 + 1100000LL * e.near1\n                 +  300000LL * e.treeSum\n                 - 2000000LL * e.cmaxEx\n                 -   85000LL * e.totalEx\n                 -   22000LL * edgeGap;\n        } else {\n            return 6800000LL * e.S\n                 + 2000000LL * e.near1\n                 + 1800000LL * e.pot7\n                 +  700000LL * e.cmax\n                 +  400000LL * e.treeSum\n                 - 2400000LL * e.cmaxEx\n                 -  120000LL * e.totalEx\n                 -   26000LL * edgeGap;\n        }\n    } else {\n        // cycle-break / tree finishing\n        if (r < 500) {\n            return 7500000LL * e.S\n                 + 3200000LL * e.near1\n                 + 2400000LL * e.pot7\n                 +  800000LL * e.treeSum\n                 +  500000LL * e.cmax\n                 - 2800000LL * e.cmaxEx\n                 -  160000LL * e.totalEx\n                 -   22000LL * edgeGap;\n        } else {\n            return 9200000LL * e.S\n                 + 3800000LL * e.near1\n                 + 2800000LL * e.pot7\n                 + 1000000LL * e.treeSum\n                 +  400000LL * e.cmax\n                 - 3200000LL * e.cmaxEx\n                 -  210000LL * e.totalEx\n                 -   28000LL * edgeGap;\n        }\n    }\n}\n\nuint64_t compute_hash(const Board &b) {\n    uint64_t h = 0;\n    for (int i = 0; i < NN_global; i++) h ^= zobrist[i][b[i]];\n    return h;\n}\n\nstruct SearchResult {\n    string path;\n    Board board{};\n    int blank = 0;\n    int lastDir = 4; // 0..3, 4=none\n    int S = 0;\n    int cmax = 0;\n    int cEx = 0;\n    long long key = LLONG_MIN;\n};\n\nbool better_result(const SearchResult &a, const SearchResult &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    if (a.cmax != b.cmax) return a.cmax > b.cmax;\n    if (a.cEx != b.cEx) return a.cEx < b.cEx;\n    return a.path.size() < b.path.size();\n}\n\ninline bool better_tuple(int S, int cmax, int cEx, int len, const SearchResult &best) {\n    if (S != best.S) return S > best.S;\n    if (S == FULLV && len != (int)best.path.size()) return len < (int)best.path.size();\n    if (cmax != best.cmax) return cmax > best.cmax;\n    if (cEx != best.cEx) return cEx < best.cEx;\n    return len < (int)best.path.size();\n}\n\nstruct Node {\n    Board b{};\n    uint8_t blank = 0;\n    uint16_t depth = 0;\n    int parent = -1;\n    uint8_t lastDir = 4;\n    char mv = '?';\n    uint64_t hash = 0;\n\n    int S = 0, cmax = 0, cEx = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN;\n};\n\nSearchResult run_beam(\n    const SearchResult &start,\n    int width,\n    int mode,\n    int depthLimit,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng\n) {\n    SearchResult res = start;\n    int startDepth = (int)start.path.size();\n    if (startDepth >= depthLimit || width <= 0) return res;\n\n    vector<Node> nodes;\n    size_t est = (size_t)(depthLimit - startDepth + 1) * (size_t)width * 2ULL + 2048ULL;\n    if (est > 2200000ULL) est = 2200000ULL;\n    nodes.reserve(est);\n\n    Node root;\n    root.b = start.board;\n    root.blank = (uint8_t)start.blank;\n    root.depth = (uint16_t)startDepth;\n    root.parent = -1;\n    root.lastDir = (uint8_t)start.lastDir;\n    root.mv = '?';\n    root.hash = compute_hash(root.b);\n    {\n        EvalInfo e0 = evaluate_state(root.b);\n        root.S = e0.S;\n        root.cmax = e0.cmax;\n        root.cEx = e0.cmaxEx;\n        root.key = calc_key(e0, startDepth, mode);\n        root.pri = root.key;\n    }\n    nodes.push_back(root);\n\n    auto state_key = [](uint64_t h, uint8_t lastDir) -> uint64_t {\n        return h ^ (0x9e3779b97f4a7c15ULL * (uint64_t)(lastDir + 1));\n    };\n\n    unordered_map<uint64_t, uint16_t> seenDepth;\n    seenDepth.max_load_factor(0.7f);\n    seenDepth.reserve((size_t)(est * 13 / 10 + 16));\n    seenDepth[state_key(root.hash, root.lastDir)] = root.depth;\n\n    int bestId = 0;\n\n    auto better_node = [&](int a, int b) -> bool {\n        const Node &x = nodes[a];\n        const Node &y = nodes[b];\n        if (x.S != y.S) return x.S > y.S;\n        if (x.S == FULLV && x.depth != y.depth) return x.depth < y.depth;\n        if (x.cmax != y.cmax) return x.cmax > y.cmax;\n        if (x.cEx != y.cEx) return x.cEx < y.cEx;\n        if (x.key != y.key) return x.key > y.key;\n        return x.depth < y.depth;\n    };\n\n    vector<int> beam, cand;\n    beam.reserve(width + 8);\n    cand.reserve(width * 4 + 64);\n    beam.push_back(0);\n\n    for (int dep = startDepth; dep < depthLimit; dep++) {\n        if ((dep & 3) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        cand.clear();\n        bool timeout = false;\n\n        for (int bi = 0; bi < (int)beam.size(); bi++) {\n            if ((bi & 31) == 0 && chrono::steady_clock::now() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int id = beam[bi];\n\n            // Copy out current data: prevents dangling-reference UB after push_back\n            uint8_t curBlank = nodes[id].blank;\n            uint8_t curLast = nodes[id].lastDir;\n            uint16_t curDepth = nodes[id].depth;\n            uint64_t curHash = nodes[id].hash;\n            Board curBoard = nodes[id].b;\n\n            for (int d = 0; d < 4; d++) {\n                if (curLast < 4 && d == OPP[curLast]) continue;\n                int nb = NEI[curBlank][d];\n                if (nb < 0) continue;\n\n                Node child;\n                child.b = curBoard;\n\n                uint8_t tile = child.b[nb];\n                child.b[curBlank] = tile;\n                child.b[nb] = 0;\n\n                child.blank = (uint8_t)nb;\n                child.depth = (uint16_t)(curDepth + 1);\n                child.parent = id;\n                child.lastDir = (uint8_t)d;\n                child.mv = OPCH[d];\n\n                child.hash = curHash\n                           ^ zobrist[curBlank][0]\n                           ^ zobrist[curBlank][tile]\n                           ^ zobrist[nb][tile]\n                           ^ zobrist[nb][0];\n\n                uint64_t sk = state_key(child.hash, child.lastDir);\n                auto it = seenDepth.find(sk);\n                if (it != seenDepth.end() && it->second <= child.depth) continue;\n                seenDepth[sk] = child.depth;\n\n                EvalInfo ec = evaluate_state(child.b);\n                child.S = ec.S;\n                child.cmax = ec.cmax;\n                child.cEx = ec.cmaxEx;\n                child.key = calc_key(ec, child.depth, mode);\n                child.pri = child.key * 2048LL + (long long)(rng.next() & 2047ULL);\n\n                nodes.push_back(std::move(child));\n                int nid = (int)nodes.size() - 1;\n                cand.push_back(nid);\n\n                if (better_node(nid, bestId)) bestId = nid;\n            }\n        }\n\n        if (timeout || cand.empty()) break;\n\n        auto cmpPri = [&](int a, int b) {\n            const Node &x = nodes[a];\n            const Node &y = nodes[b];\n            if (x.pri != y.pri) return x.pri > y.pri;\n            if (x.S != y.S) return x.S > y.S;\n            if (x.cmax != y.cmax) return x.cmax > y.cmax;\n            if (x.cEx != y.cEx) return x.cEx < y.cEx;\n            if (x.key != y.key) return x.key > y.key;\n            return a < b;\n        };\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), cmpPri);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), cmpPri);\n        beam.swap(cand);\n\n        if (nodes[bestId].S == FULLV) break;\n    }\n\n    string suffix;\n    for (int cur = bestId; nodes[cur].parent != -1; cur = nodes[cur].parent) {\n        suffix.push_back(nodes[cur].mv);\n    }\n    reverse(suffix.begin(), suffix.end());\n\n    res.path = start.path + suffix;\n    res.board = nodes[bestId].b;\n    res.blank = nodes[bestId].blank;\n    res.lastDir = nodes[bestId].lastDir;\n    res.S = nodes[bestId].S;\n    res.cmax = nodes[bestId].cmax;\n    res.cEx = nodes[bestId].cEx;\n    res.key = nodes[bestId].key;\n    return res;\n}\n\nSearchResult guided_walk(\n    const SearchResult &start,\n    int mode,\n    int greedPermille,\n    bool look2,\n    int depthLimit,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng\n) {\n    SearchResult best = start;\n    int startDepth = (int)start.path.size();\n    if (startDepth >= depthLimit) return best;\n\n    Board board = start.board;\n    int blank = start.blank;\n    int lastDir = start.lastDir;\n    string path = start.path;\n\n    uint64_t hash = compute_hash(board);\n    EvalInfo cur = evaluate_state(board);\n    long long curKey = calc_key(cur, startDepth, mode);\n\n    best.S = cur.S;\n    best.cmax = cur.cmax;\n    best.cEx = cur.cmaxEx;\n    best.key = curKey;\n    best.board = board;\n    best.blank = blank;\n    best.lastDir = lastDir;\n    best.path = path;\n\n    deque<uint64_t> recent;\n    recent.push_back(hash);\n    const int RECENT_WINDOW = 16;\n    const long long LOOP_PENALTY = 18000000LL;\n\n    struct Cand {\n        int d = 0;\n        int nb = 0;\n        Board b{};\n        uint64_t h = 0;\n        EvalInfo e;\n        long long key = LLONG_MIN;\n        long long val = LLONG_MIN;\n    };\n\n    for (int step = startDepth; step < depthLimit; step++) {\n        if ((step & 15) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        Cand cs[4];\n        int m = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n            int nb = NEI[blank][d];\n            if (nb < 0) continue;\n\n            Cand c;\n            c.d = d;\n            c.nb = nb;\n            c.b = board;\n\n            uint8_t tile = c.b[nb];\n            c.b[blank] = tile;\n            c.b[nb] = 0;\n\n            c.h = hash\n                ^ zobrist[blank][0]\n                ^ zobrist[blank][tile]\n                ^ zobrist[nb][tile]\n                ^ zobrist[nb][0];\n\n            c.e = evaluate_state(c.b);\n            c.key = calc_key(c.e, step + 1, mode);\n\n            for (uint64_t h0 : recent) {\n                if (h0 == c.h) {\n                    c.key -= LOOP_PENALTY;\n                    break;\n                }\n            }\n\n            c.val = c.key;\n\n            if (look2 && step + 1 < depthLimit) {\n                long long best2 = LLONG_MIN / 4;\n                for (int d2 = 0; d2 < 4; d2++) {\n                    if (d2 == OPP[d]) continue;\n                    int nb2 = NEI[nb][d2];\n                    if (nb2 < 0) continue;\n\n                    Board b2 = c.b;\n                    uint8_t t2 = b2[nb2];\n                    b2[nb] = t2;\n                    b2[nb2] = 0;\n\n                    EvalInfo e2 = evaluate_state(b2);\n                    long long k2 = calc_key(e2, step + 2, mode);\n                    if (k2 > best2) best2 = k2;\n                }\n                if (best2 > LLONG_MIN / 8) c.val = c.key * 4 + best2;\n            }\n\n            cs[m++] = std::move(c);\n        }\n\n        if (m == 0) break;\n\n        sort(cs, cs + m, [](const Cand &a, const Cand &b) {\n            if (a.val != b.val) return a.val > b.val;\n            return a.key > b.key;\n        });\n\n        int pick = 0;\n        uint64_t rr = rng.next() % 1000ULL;\n        if (m >= 2 && rr > (uint64_t)greedPermille) {\n            pick = (m == 2) ? 1 : (1 + (int)(rng.next() % (uint64_t)(m - 1)));\n        }\n\n        const Cand &ch = cs[pick];\n\n        board = ch.b;\n        blank = ch.nb;\n        lastDir = ch.d;\n        hash = ch.h;\n        cur = ch.e;\n        curKey = ch.key;\n        path.push_back(OPCH[ch.d]);\n\n        if (better_tuple(cur.S, cur.cmax, cur.cmaxEx, (int)path.size(), best)) {\n            best.path = path;\n            best.board = board;\n            best.blank = blank;\n            best.lastDir = lastDir;\n            best.S = cur.S;\n            best.cmax = cur.cmax;\n            best.cEx = cur.cmaxEx;\n            best.key = curKey;\n            if (best.S == FULLV) break;\n        }\n\n        recent.push_back(hash);\n        if ((int)recent.size() > RECENT_WINDOW) recent.pop_front();\n    }\n\n    return best;\n}\n\nSearchResult random_perturb(\n    const SearchResult &start,\n    int steps,\n    int mode,\n    int greedPermille,\n    XorShift64 &rng\n) {\n    SearchResult cur = start;\n    int startDepth = (int)start.path.size();\n    if (startDepth >= T_global || steps <= 0) return cur;\n\n    Board board = start.board;\n    int blank = start.blank;\n    int lastDir = start.lastDir;\n    string path = start.path;\n\n    int lim = min(T_global, startDepth + steps);\n\n    struct Cand {\n        int d = 0;\n        int nb = 0;\n        Board b{};\n        EvalInfo e;\n        long long key = LLONG_MIN;\n    };\n\n    for (int step = startDepth; step < lim; step++) {\n        Cand cs[4];\n        int m = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n            int nb = NEI[blank][d];\n            if (nb < 0) continue;\n\n            Cand c;\n            c.d = d;\n            c.nb = nb;\n            c.b = board;\n\n            uint8_t tile = c.b[nb];\n            c.b[blank] = tile;\n            c.b[nb] = 0;\n\n            c.e = evaluate_state(c.b);\n            c.key = calc_key(c.e, step + 1, mode);\n            cs[m++] = std::move(c);\n        }\n\n        if (m == 0) break;\n\n        sort(cs, cs + m, [](const Cand &a, const Cand &b) {\n            if (a.key != b.key) return a.key > b.key;\n            return a.d < b.d;\n        });\n\n        int pick = 0;\n        uint64_t rr = rng.next() % 1000ULL;\n        if (m >= 2 && rr > (uint64_t)greedPermille) {\n            pick = (m == 2) ? 1 : (int)(rng.next() % (uint64_t)m);\n        }\n\n        board = cs[pick].b;\n        blank = cs[pick].nb;\n        lastDir = cs[pick].d;\n        path.push_back(OPCH[cs[pick].d]);\n    }\n\n    EvalInfo ef = evaluate_state(board);\n    cur.path = std::move(path);\n    cur.board = board;\n    cur.blank = blank;\n    cur.lastDir = lastDir;\n    cur.S = ef.S;\n    cur.cmax = ef.cmax;\n    cur.cEx = ef.cmaxEx;\n    cur.key = calc_key(ef, (int)cur.path.size(), mode);\n    return cur;\n}\n\nint hex_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    return 10 + (c - 'A');\n}\n\nint dir_from_char(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\n// Safety post-process: output best legal prefix under true objective\nstring best_legal_prefix(const string &path, const Board &init, int initBlank) {\n    Board b = init;\n    int blank = initBlank;\n\n    string cur, best;\n    cur.reserve(min((int)path.size(), T_global));\n    best.reserve(min((int)path.size(), T_global));\n\n    EvalInfo e0 = evaluate_state(b);\n    int bestS = e0.S;\n    int bestLen = (bestS == FULLV ? 0 : INT_MAX);\n\n    auto isBetter = [&](int S, int len, int bS, int bLen) -> bool {\n        if (S != bS) return S > bS;\n        if (S == FULLV) return len < bLen;\n        return false;\n    };\n\n    for (char c : path) {\n        if ((int)cur.size() >= T_global) break;\n        int d = dir_from_char(c);\n        if (d < 0) break;\n\n        int nb = NEI[blank][d];\n        if (nb < 0) break; // illegal => truncate\n\n        uint8_t tile = b[nb];\n        b[blank] = tile;\n        b[nb] = 0;\n        blank = nb;\n        cur.push_back(c);\n\n        EvalInfo ei = evaluate_state(b);\n        int S = ei.S;\n        int len = (int)cur.size();\n\n        if (isBetter(S, len, bestS, bestLen)) {\n            bestS = S;\n            bestLen = len;\n            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_global >> T_global;\n    NN_global = N_global * N_global;\n    FULLV = NN_global - 1;\n\n    Board init{};\n    int blank = -1;\n\n    for (int i = 0; i < N_global; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N_global; j++) {\n            int v = hex_to_int(s[j]);\n            init[i * N_global + j] = (uint8_t)v;\n            if (v == 0) blank = i * N_global + j;\n        }\n    }\n\n    for (int p = 0; p < NN_global; p++) {\n        int r = p / N_global;\n        int c = p % N_global;\n        NEI[p][0] = (r > 0) ? (p - N_global) : -1;            // U\n        NEI[p][1] = (r + 1 < N_global) ? (p + N_global) : -1; // D\n        NEI[p][2] = (c > 0) ? (p - 1) : -1;                   // L\n        NEI[p][3] = (c + 1 < N_global) ? (p + 1) : -1;        // R\n    }\n\n    g_edges.clear();\n    g_edges.reserve(2 * N_global * (N_global - 1));\n    for (int i = 0; i < N_global; i++) {\n        for (int j = 0; j < N_global; j++) {\n            int id = i * N_global + j;\n            if (j + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + 1), 4, 1});\n            if (i + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + N_global), 8, 2});\n        }\n    }\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n    for (int i = 0; i < NN_global; i++) {\n        seed ^= (uint64_t)init[i] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n\n    uint64_t zseed = seed ^ 0xdeadbeefcafebabeULL;\n    for (int i = 0; i < 100; i++) {\n        for (int v = 0; v < 16; v++) {\n            zobrist[i][v] = splitmix64(zseed);\n        }\n    }\n\n    XorShift64 rng(seed ^ 0x517cc1b727220a95ULL);\n\n    EvalInfo e0 = evaluate_state(init);\n    SearchResult initRes;\n    initRes.path = \"\";\n    initRes.board = init;\n    initRes.blank = blank;\n    initRes.lastDir = 4;\n    initRes.S = e0.S;\n    initRes.cmax = e0.cmax;\n    initRes.cEx = e0.cmaxEx;\n    initRes.key = calc_key(e0, 0, 0);\n\n    SearchResult best = initRes;\n    int depthLimit = T_global;\n\n    struct PoolEntry {\n        uint64_t hk;\n        SearchResult r;\n    };\n    vector<PoolEntry> pool;\n    pool.reserve(12);\n\n    auto add_pool = [&](const SearchResult &r) {\n        uint64_t hk = compute_hash(r.board) ^ (0x9e3779b97f4a7c15ULL * (uint64_t)(r.lastDir + 1));\n        for (auto &e : pool) {\n            if (e.hk == hk) {\n                if (better_result(r, e.r)) e.r = r;\n                return;\n            }\n        }\n        pool.push_back(PoolEntry{hk, r});\n        sort(pool.begin(), pool.end(), [](const PoolEntry &a, const PoolEntry &b) {\n            return better_result(a.r, b.r);\n        });\n        if ((int)pool.size() > 10) pool.resize(10);\n    };\n\n    auto consider = [&](const SearchResult &r) {\n        if (better_result(r, best)) best = r;\n        add_pool(r);\n        if (best.S == FULLV) {\n            depthLimit = min(depthLimit, (int)best.path.size() - 1);\n            if (depthLimit < 0) depthLimit = 0;\n        }\n    };\n\n    auto pick_start = [&](bool exploratory) -> const SearchResult& {\n        if (pool.empty()) return initRes;\n        if (!exploratory) return pool[0].r;\n\n        uint64_t rv = rng.next() % 100ULL;\n        if (rv < 50ULL) return pool[0].r;\n\n        int lim = min((int)pool.size(), 5);\n        if (lim <= 1) return pool[0].r;\n        int idx = 1 + (int)(rng.next() % (uint64_t)(lim - 1));\n        return pool[idx].r;\n    };\n\n    add_pool(initRes);\n\n    auto t0 = chrono::steady_clock::now();\n    const int TIME_LIMIT_MS = 2730;\n    auto globalDeadline = t0 + chrono::milliseconds(TIME_LIMIT_MS);\n\n    auto d1 = t0 + chrono::milliseconds(TIME_LIMIT_MS * 34 / 100);\n    auto d2 = t0 + chrono::milliseconds(TIME_LIMIT_MS * 57 / 100);\n    auto d3 = t0 + chrono::milliseconds(TIME_LIMIT_MS * 71 / 100);\n    auto d4 = t0 + chrono::milliseconds(TIME_LIMIT_MS * 86 / 100);\n    if (d1 > globalDeadline) d1 = globalDeadline;\n    if (d2 > globalDeadline) d2 = globalDeadline;\n    if (d3 > globalDeadline) d3 = globalDeadline;\n    if (d4 > globalDeadline) d4 = globalDeadline;\n\n    int wBase = clamp(1150000 / max(1, 2 * T_global), 110, 700);\n    int wMain = wBase;\n    int wMid = max(80, wBase * 3 / 4);\n    int wSmall = max(60, wBase / 2);\n\n    if (chrono::steady_clock::now() < d1 && depthLimit > 0) {\n        SearchResult r1 = run_beam(initRes, wMain, 0, depthLimit, d1, rng);\n        consider(r1);\n    }\n\n    if (chrono::steady_clock::now() < d2 && depthLimit > 0) {\n        SearchResult r2 = run_beam(initRes, wMid, 1, depthLimit, d2, rng);\n        consider(r2);\n    }\n\n    if (chrono::steady_clock::now() < d3 && depthLimit > 0) {\n        const SearchResult &base = pick_start(false);\n        SearchResult r3 = run_beam(base, wMid, 2, depthLimit, d3, rng);\n        consider(r3);\n    }\n\n    int divIter = 0;\n    while (chrono::steady_clock::now() < d4 && depthLimit > 0) {\n        const SearchResult *basePtr = &initRes;\n        if (!pool.empty() && (rng.next() % 100ULL >= 55ULL)) {\n            basePtr = &pick_start(true);\n        }\n\n        int b1 = max(18, T_global / 10);\n        int b2 = max(10, T_global / 12);\n        int steps = b1 + (int)(rng.next() % (uint64_t)b2);\n        int mode = (int)(rng.next() % 2ULL);\n        int greed = 700 + (int)(rng.next() % 220ULL);\n\n        SearchResult st = random_perturb(*basePtr, steps, mode, greed, rng);\n        consider(st);\n\n        if (chrono::steady_clock::now() >= d4 || depthLimit <= 0) break;\n\n        auto slotEnd = min(chrono::steady_clock::now() + chrono::milliseconds(70), d4);\n        SearchResult rb = run_beam(st, wSmall, 2, depthLimit, slotEnd, rng);\n        consider(rb);\n\n        divIter++;\n        if (N_global <= 7 && divIter >= 8) break;\n    }\n\n    int iter = 0;\n    while (chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n        if (best.S == FULLV) {\n            auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(55), globalDeadline);\n            SearchResult rr = run_beam(initRes, wSmall, 2, depthLimit, dl, rng);\n            consider(rr);\n            continue;\n        }\n\n        const SearchResult *stPtr = &initRes;\n        if (!pool.empty() && (rng.next() % 100ULL >= 25ULL)) {\n            stPtr = &pick_start(true);\n        }\n\n        int mode = iter % 3;\n        int greed;\n        switch (iter % 5) {\n            case 0: greed = 760; break;\n            case 1: greed = 820; break;\n            case 2: greed = 870; break;\n            case 3: greed = 920; break;\n            default: greed = 850; break;\n        }\n        bool look2 = (iter % 4 == 0 || iter % 7 == 3);\n\n        auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(look2 ? 60 : 42), globalDeadline);\n        SearchResult g = guided_walk(*stPtr, mode, greed, look2, depthLimit, dl, rng);\n        consider(g);\n\n        if (iter % 4 == 2 && chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n            auto dlb = min(chrono::steady_clock::now() + chrono::milliseconds(40), globalDeadline);\n            SearchResult b = run_beam(g, wSmall, 2, depthLimit, dlb, rng);\n            consider(b);\n        }\n\n        if (iter % 6 == 5 && chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n            const SearchResult &pb = pick_start(true);\n            int steps = max(12, T_global / 14);\n            SearchResult rp = random_perturb(pb, steps, 1, 760, rng);\n            consider(rp);\n        }\n\n        iter++;\n    }\n\n    string out = best_legal_prefix(best.path, init, blank);\n    if ((int)out.size() > T_global) out.resize(T_global);\n    cout << out << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct Line {\n    long long x1, y1, x2, y2;\n    long long dx, dy;\n};\n\nstruct EvalKey {\n    int F = 0;\n    int def2 = 0;\n    int active = 0;\n    int waste = 0;\n    long long over = 0;\n};\n\nstatic inline bool betterKey(const EvalKey& a, const EvalKey& b) {\n    if (a.F != b.F) return a.F > b.F;\n    if (a.def2 != b.def2) return a.def2 < b.def2;\n    if (a.active != b.active) return a.active > b.active;\n    if (a.waste != b.waste) return a.waste < b.waste;\n    return a.over < b.over;\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) {\n        x = seed ? seed : 88172645463325252ull;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct State {\n    vector<vector<int>> pieces;\n    vector<int> pieceSize;\n    vector<int> pieceOf;     // -1 deleted\n    vector<int> active;\n    array<int, 11> h{};\n    int F = 0;\n    int def2 = 0;\n    int waste = 0;\n    long long over = 0;\n    vector<Line> lines;\n};\n\nstruct RunResult {\n    vector<Line> lines;\n    EvalKey key;\n};\n\nclass Solver {\n    static constexpr double PI = 3.1415926535897932384626433832795;\n    static constexpr long long BIG = (1LL << 62);\n\n    int N, K;\n    array<int, 11> a{};\n    vector<Point> pts;\n    int totalA = 0;\n    vector<long long> pen;\n\n    chrono::steady_clock::time_point t0;\n    const double TL = 2.82;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline long long orient(const Line& ln, const Point& p) const {\n        return ln.dx * ((long long)p.y - ln.y1) - ln.dy * ((long long)p.x - ln.x1);\n    }\n\n    inline int calcF(const array<int, 11>& h) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], h[d]);\n        return s;\n    }\n\n    inline int calcDef2(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int sat = min(a[d], h[d]);\n            int def = a[d] - sat;\n            v += def * def;\n        }\n        return v;\n    }\n\n    inline int calcWaste(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int ex = max(0, h[d] - a[d]);\n            v += ex * ex;\n        }\n        return v;\n    }\n\n    inline EvalKey stateKey(const State& st) const {\n        return EvalKey{st.F, st.def2, (int)st.active.size(), st.waste, st.over};\n    }\n\n    inline void addPart(array<int, 11>& h, long long& over, int t, int delta) const {\n        if (t <= 0) return;\n        if (t <= 10) h[t] += delta;\n        over += (long long)delta * pen[t];\n    }\n\n    inline void addPieceState(array<int, 11>& h, long long& over, int s, int l, int delta) const {\n        if (l <= 0 || l >= s) {\n            addPart(h, over, s, delta);\n        } else {\n            addPart(h, over, l, delta);\n            addPart(h, over, s - l, delta);\n        }\n    }\n\n    inline double normTheta(double th) const {\n        while (th < 0) th += PI;\n        while (th >= PI) th -= PI;\n        return th;\n    }\n\n    Line makeLineFromNormal(double nx, double ny, double c) const {\n        const double S = 8.8e8;\n        double dx = -ny, dy = nx;\n        double cx = nx * c, cy = ny * c;\n\n        long long x1 = llround(cx + dx * S);\n        long long y1 = llround(cy + dy * S);\n        long long x2 = llround(cx - dx * S);\n        long long y2 = llround(cy - dy * S);\n\n        if (x1 == x2 && y1 == y2) x2++;\n\n        Line ln;\n        ln.x1 = x1; ln.y1 = y1;\n        ln.x2 = x2; ln.y2 = y2;\n        ln.dx = ln.x2 - ln.x1;\n        ln.dy = ln.y2 - ln.y1;\n        if (ln.dx == 0 && ln.dy == 0) {\n            ln.x2++;\n            ln.dx = 1;\n        }\n        return ln;\n    }\n\n    Line makeLine(double theta, double c) const {\n        return makeLineFromNormal(cos(theta), sin(theta), c);\n    }\n\n    Line randomGlobalLine(XorShift64& rng) const {\n        double theta = rng.nextDouble() * PI;\n        double c = (rng.nextDouble() * 2.0 - 1.0) * 9200.0;\n        return makeLine(theta, c);\n    }\n\n    EvalKey evalLine(const State& st, const Line& ln, vector<int>& L, vector<int>& R) const {\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) {\n            L[i] = 0;\n            R[i] = 0;\n        }\n\n        for (int idx : st.active) {\n            int pid = st.pieceOf[idx];\n            long long v = orient(ln, pts[idx]);\n            if (v > 0) L[pid]++;\n            else if (v < 0) R[pid]++;\n        }\n\n        array<int, 11> h2 = st.h;\n        long long over2 = st.over;\n        int removed = 0;\n\n        for (int pid = 0; pid < P; pid++) {\n            int s = st.pieceSize[pid];\n            int l = L[pid];\n            int r = R[pid];\n\n            if (l == s || r == s) continue;\n\n            removed += s - l - r;\n            over2 -= pen[s];\n            if (l > 0) over2 += pen[l];\n            if (r > 0) over2 += pen[r];\n\n            if (1 <= s && s <= 10) h2[s]--;\n            if (1 <= l && l <= 10) h2[l]++;\n            if (1 <= r && r <= 10) h2[r]++;\n        }\n\n        EvalKey key;\n        key.F = calcF(h2);\n        key.def2 = calcDef2(h2);\n        key.active = (int)st.active.size() - removed;\n        key.waste = calcWaste(h2);\n        key.over = over2;\n        return key;\n    }\n\n    void rebuildMetrics(State& st) const {\n        st.h.fill(0);\n        st.over = 0;\n        for (int s : st.pieceSize) {\n            if (1 <= s && s <= 10) st.h[s]++;\n            st.over += pen[s];\n        }\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n    }\n\n    void applyLine(State& st, const Line& ln) const {\n        vector<vector<int>> newPieces;\n        vector<int> newSizes;\n        vector<int> newActive;\n\n        newPieces.reserve(st.pieces.size() * 2 + 2);\n        newSizes.reserve(st.pieces.size() * 2 + 2);\n        newActive.reserve(st.active.size());\n\n        fill(st.pieceOf.begin(), st.pieceOf.end(), -1);\n\n        for (const auto& pc : st.pieces) {\n            vector<int> left, right;\n            left.reserve(pc.size());\n            right.reserve(pc.size());\n\n            for (int idx : pc) {\n                long long v = orient(ln, pts[idx]);\n                if (v > 0) left.push_back(idx);\n                else if (v < 0) right.push_back(idx);\n            }\n\n            if (!left.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : left) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)left.size());\n                newPieces.push_back(move(left));\n            }\n            if (!right.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : right) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)right.size());\n                newPieces.push_back(move(right));\n            }\n        }\n\n        st.pieces.swap(newPieces);\n        st.pieceSize.swap(newSizes);\n        st.active.swap(newActive);\n        st.lines.push_back(ln);\n        rebuildMetrics(st);\n    }\n\n    bool bestCutForTheta(const State& st, double theta, double& bestC, EvalKey& pred,\n                         vector<pair<double, int>>& ord, vector<int>& cntLeft) const {\n        int M = (int)st.active.size();\n        if (M < 2) return false;\n\n        double nx = cos(theta), ny = sin(theta);\n        ord.resize(M);\n        for (int i = 0; i < M; i++) {\n            int idx = st.active[i];\n            ord[i] = {nx * pts[idx].x + ny * pts[idx].y, idx};\n        }\n        sort(ord.begin(), ord.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) cntLeft[i] = 0;\n\n        array<int, 11> hcur = st.h;\n        long long overcur = st.over;\n\n        bool found = false;\n        EvalKey bestLocal{};\n        double cLocal = 0.0;\n\n        const double EPS = 1e-12;\n        int i = 0;\n        while (i < M) {\n            int j = i + 1;\n            while (j < M && fabs(ord[j].first - ord[i].first) <= EPS) j++;\n\n            for (int k = i; k < j; k++) {\n                int idx = ord[k].second;\n                int pid = st.pieceOf[idx];\n                int s = st.pieceSize[pid];\n                int oldL = cntLeft[pid];\n                int newL = oldL + 1;\n\n                addPieceState(hcur, overcur, s, oldL, -1);\n                addPieceState(hcur, overcur, s, newL, +1);\n                cntLeft[pid] = newL;\n            }\n\n            if (j < M) {\n                double lv = ord[j - 1].first;\n                double rv = ord[j].first;\n                if (rv - lv > EPS) {\n                    EvalKey key;\n                    key.F = calcF(hcur);\n                    key.def2 = calcDef2(hcur);\n                    key.active = M;\n                    key.waste = calcWaste(hcur);\n                    key.over = overcur;\n                    if (!found || betterKey(key, bestLocal)) {\n                        found = true;\n                        bestLocal = key;\n                        cLocal = (lv + rv) * 0.5;\n                    }\n                }\n            }\n            i = j;\n        }\n\n        if (!found) return false;\n        bestC = cLocal;\n        pred = bestLocal;\n        return true;\n    }\n\n    pair<Line, EvalKey> realizeThetaC(const State& st, double theta, double c,\n                                      vector<int>& L, vector<int>& R) const {\n        Line bestLn = makeLine(theta, c);\n        EvalKey bestEv = evalLine(st, bestLn, L, R);\n\n        int curAct = (int)st.active.size();\n        if (bestEv.active == curAct) return {bestLn, bestEv};\n\n        static const double off[6] = {1e-4, -1e-4, 5e-4, -5e-4, 2e-3, -2e-3};\n        for (double d : off) {\n            Line ln = makeLine(theta, c + d);\n            EvalKey ev = evalLine(st, ln, L, R);\n            if (betterKey(ev, bestEv)) {\n                bestEv = ev;\n                bestLn = ln;\n            }\n        }\n        return {bestLn, bestEv};\n    }\n\n    int pickPieceRandom(const State& st, XorShift64& rng, int minSize) const {\n        if (st.active.empty()) return -1;\n        int S = (int)st.active.size();\n        for (int t = 0; t < 30; t++) {\n            int idx = st.active[rng.nextInt(0, S - 1)];\n            int pid = st.pieceOf[idx];\n            if (st.pieceSize[pid] >= minSize) return pid;\n        }\n        int best = -1, bestSize = 0;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s >= minSize && s > bestSize) {\n                bestSize = s;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int chooseTargetPiece(const State& st) const {\n        int best = -1;\n        long long bestScore = -1;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s < 2) continue;\n\n            long long score;\n            if (s > 10) {\n                score = 1000000LL + 1000LL * s;\n            } else {\n                int overSup = max(0, st.h[s] - a[s]);\n                score = (long long)overSup * 10000LL + s;\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int pickDeficitSize(const State& st, XorShift64& rng) const {\n        int w[11];\n        int sumW = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - st.h[d]);\n            int wt = 1 + def * def * 3;\n            w[d] = wt;\n            sumW += wt;\n        }\n        int r = rng.nextInt(1, sumW);\n        for (int d = 1; d <= 10; d++) {\n            if (r <= w[d]) return d;\n            r -= w[d];\n        }\n        return 1;\n    }\n\n    bool calcPCA(const State& st, int pid, double& th1, double& th2) const {\n        const auto& pc = st.pieces[pid];\n        int s = (int)pc.size();\n        if (s < 2) return false;\n\n        long double mx = 0, my = 0;\n        for (int idx : pc) {\n            mx += pts[idx].x;\n            my += pts[idx].y;\n        }\n        mx /= s;\n        my /= s;\n\n        long double cxx = 0, cyy = 0, cxy = 0;\n        for (int idx : pc) {\n            long double dx = pts[idx].x - mx;\n            long double dy = pts[idx].y - my;\n            cxx += dx * dx;\n            cyy += dy * dy;\n            cxy += dx * dy;\n        }\n        if ((double)(cxx + cyy) < 1e-9) return false;\n\n        double ang = 0.5 * atan2((double)(2 * cxy), (double)(cxx - cyy));\n        th1 = normTheta(ang);\n        th2 = normTheta(ang + PI * 0.5);\n        return true;\n    }\n\n    Line lineByQuantile(const State& st, int pid, double theta, int t, vector<double>& buf) const {\n        const auto& vec = st.pieces[pid];\n        int s = (int)vec.size();\n        t = max(1, min(s - 1, t));\n\n        double nx = cos(theta), ny = sin(theta);\n        buf.clear();\n        buf.reserve(s);\n        for (int idx : vec) {\n            buf.push_back(nx * pts[idx].x + ny * pts[idx].y);\n        }\n\n        sort(buf.begin(), buf.end());\n        double l = buf[t - 1], r = buf[t];\n        double c = (l + r) * 0.5;\n        if (fabs(r - l) < 1e-12) c += 1e-6;\n        return makeLine(theta, c);\n    }\n\n    RunResult runOne(uint64_t seed, int runId, double runEnd) {\n        XorShift64 rng(seed);\n\n        State st;\n        st.pieceOf.assign(N, 0);\n        st.pieces.assign(1, {});\n        st.pieces[0].resize(N);\n        iota(st.pieces[0].begin(), st.pieces[0].end(), 0);\n        st.pieceSize.assign(1, N);\n        st.active = st.pieces[0];\n        st.h.fill(0);\n        if (1 <= N && N <= 10) st.h[N] = 1;\n        st.over = pen[N];\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n\n        int oriBase;\n        if (N >= 4500) oriBase = 8;\n        else if (N >= 3000) oriBase = 10;\n        else if (N >= 1800) oriBase = 12;\n        else oriBase = 14;\n\n        int qBase = (N >= 3500 ? 3 : 4);\n        int noImpLimit = (runId == 0 ? 13 : 10);\n        if (runId == 0) oriBase += 2;\n        if (runId >= 3) oriBase = max(6, oriBase - 2);\n\n        vector<int> L(max(1, N), 0), R(max(1, N), 0), cntLeft(max(1, N), 0);\n        vector<pair<double, int>> ord;\n        ord.reserve(max(1, N));\n        vector<double> projBuf;\n        projBuf.reserve(max(1, N));\n\n        int noImprove = 0;\n        double runBudget = runEnd - elapsed();\n\n        for (int iter = 0; iter < K * 3 && (int)st.lines.size() < K; iter++) {\n            if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n            if (st.active.empty()) break;\n            if (st.F >= totalA) break;\n\n            int step = (int)st.lines.size();\n            EvalKey cur = stateKey(st);\n\n            int targetPid = chooseTargetPiece(st);\n            bool hasPCA = false;\n            double pca1 = 0.0, pca2 = 0.0;\n            if (targetPid >= 0) hasPCA = calcPCA(st, targetPid, pca1, pca2);\n\n            double remRun = runEnd - elapsed();\n            int oriCnt = oriBase;\n            if (step < 6) oriCnt += 2;\n            if (noImprove >= 3) oriCnt += 3;\n            if (runBudget < 0.35 || remRun < 0.22) oriCnt = max(4, oriCnt - 4);\n            if (remRun < 0.12) oriCnt = max(3, oriCnt / 2);\n\n            int qCnt = qBase;\n            if (noImprove >= 3) qCnt += 1;\n            if (runBudget < 0.35 || remRun < 0.22) qCnt = max(1, qCnt - 2);\n            if (remRun < 0.12) qCnt = 1;\n\n            vector<double> thetas;\n            thetas.reserve(oriCnt + 10);\n\n            auto addTheta = [&](double th) {\n                thetas.push_back(normTheta(th));\n            };\n\n            if (hasPCA) {\n                addTheta(pca1);\n                addTheta(pca2);\n                addTheta(pca1 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n                addTheta(pca2 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n            }\n\n            int prevUse = min((int)st.lines.size(), 2);\n            for (int i = 0; i < prevUse; i++) {\n                const Line& pl = st.lines[(int)st.lines.size() - 1 - i];\n                double th = atan2((double)pl.dx, (double)(-pl.dy));\n                addTheta(th + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n                addTheta(th + PI * 0.5 + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n            }\n\n            while ((int)thetas.size() < oriCnt) {\n                addTheta(rng.nextDouble() * PI);\n            }\n            if ((int)thetas.size() > 24) thetas.resize(24);\n\n            EvalKey bestEv{-1, INT_MAX, -1, INT_MAX, BIG};\n            Line bestLn{};\n            bool found = false;\n\n            for (double th : thetas) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                double c = 0.0;\n                EvalKey pred;\n                if (!bestCutForTheta(st, th, c, pred, ord, cntLeft)) continue;\n                auto [ln, ev] = realizeThetaC(st, th, c, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int qi = 0; qi < qCnt; qi++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n\n                int pid = -1;\n                if (targetPid >= 0 && st.pieceSize[targetPid] >= 2 && rng.nextDouble() < 0.65) {\n                    pid = targetPid;\n                } else {\n                    pid = pickPieceRandom(st, rng, 2);\n                }\n                if (pid < 0) continue;\n\n                int s = st.pieceSize[pid];\n                if (s <= 1) continue;\n\n                int d = pickDeficitSize(st, rng);\n                vector<int> candT;\n                if (1 <= d && d < s) candT.push_back(d);\n                if (1 <= s - d && s - d < s) candT.push_back(s - d);\n\n                int mid = s / 2;\n                if (1 <= mid && mid < s) candT.push_back(mid);\n\n                int w = max(1, s / 6);\n                int tr = mid + rng.nextInt(-w, w);\n                tr = max(1, min(s - 1, tr));\n                candT.push_back(tr);\n\n                int t = candT[rng.nextInt(0, (int)candT.size() - 1)];\n\n                double th;\n                if (hasPCA && rng.nextDouble() < 0.55) {\n                    th = (rng.nextDouble() < 0.5 ? pca1 : pca2)\n                       + (rng.nextDouble() * 2.0 - 1.0) * 0.28;\n                } else {\n                    th = rng.nextDouble() * PI;\n                }\n                th = normTheta(th);\n\n                Line ln = lineByQuantile(st, pid, th, t, projBuf);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                Line ln = randomGlobalLine(rng);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            if (!found) break;\n\n            bool accept = betterKey(bestEv, cur);\n            if (!accept && noImprove >= 5) {\n                if (bestEv.F == cur.F &&\n                    bestEv.active == cur.active &&\n                    bestEv.def2 <= cur.def2 + 1 &&\n                    (bestEv.waste < cur.waste || bestEv.over < cur.over)) {\n                    accept = true;\n                }\n            }\n\n            if (accept) {\n                applyLine(st, bestLn);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= noImpLimit) break;\n            }\n        }\n\n        RunResult rr;\n        rr.lines = move(st.lines);\n        rr.key = stateKey(st);\n        return rr;\n    }\n\npublic:\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> K;\n        a.fill(0);\n        totalA = 0;\n        for (int d = 1; d <= 10; d++) {\n            cin >> a[d];\n            totalA += a[d];\n        }\n\n        pts.resize(N);\n        for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n        pen.assign(N + 1, 0);\n        for (int s = 0; s <= N; s++) {\n            if (s > 10) {\n                long long t = s - 10;\n                pen[s] = t * t;\n            }\n        }\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        uint64_t seedBase = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            v += 0x9e3779b97f4a7c15ULL;\n            v = (v ^ (v >> 30)) * 0xbf58476d1ce4e5b9ULL;\n            v = (v ^ (v >> 27)) * 0x94d049bb133111ebULL;\n            v ^= (v >> 31);\n            seedBase ^= v + 0x9e3779b97f4a7c15ULL + (seedBase << 6) + (seedBase >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)K);\n        for (int d = 1; d <= 10; d++) mix((uint64_t)a[d]);\n        for (const auto& p : pts) {\n            uint64_t v = ((uint64_t)(p.x + 20000) << 20) ^ (uint64_t)(p.y + 20000);\n            mix(v);\n        }\n\n        EvalKey bestKey{-1, INT_MAX, -1, INT_MAX, BIG};\n        vector<Line> bestLines;\n\n        int runId = 0;\n        while (true) {\n            double rem = TL - elapsed();\n            if (rem < 0.08) break;\n\n            double factor = (runId == 0 ? 0.58 : (runId < 3 ? 0.62 : 0.70));\n            double budget = rem * factor;\n            budget = max(0.14, budget);\n            budget = min(budget, rem - 0.03);\n            if (budget <= 0.02) break;\n\n            double runEnd = elapsed() + budget;\n            uint64_t seed = seedBase + 0x9e3779b97f4a7c15ULL * (uint64_t)(runId + 1);\n\n            RunResult rr = runOne(seed, runId, runEnd);\n            if (bestLines.empty() || betterKey(rr.key, bestKey)) {\n                bestKey = rr.key;\n                bestLines = move(rr.lines);\n            }\n\n            runId++;\n            if (bestKey.F >= totalA) break;\n        }\n\n        if (bestLines.empty()) {\n            cout << 0 << '\\n';\n            return;\n        }\n\n        cout << bestLines.size() << '\\n';\n        for (const auto& ln : bestLines) {\n            cout << ln.x1 << ' ' << ln.y1 << ' ' << ln.x2 << ' ' << ln.y2 << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(next() % (uint64_t)n); } // n > 0\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nclass Solver {\n    using Clock = chrono::steady_clock;\n\n    static constexpr int MAXN = 61;\n    static constexpr int MAXD = 121;\n    static constexpr double NEG_INF = -1e100;\n\n    struct Point {\n        int x, y;\n    };\n    struct Move {\n        int x1, y1, x2, y2, x3, y3, x4, y4;\n    };\n    struct Candidate {\n        Move mv;\n        double val; // effective score\n        int w;\n        int L;\n    };\n    struct Core {\n        array<uint64_t, MAXN> row{}, col{}, usedH{}, usedV{};\n        array<uint64_t, MAXD> diagPos{}, diagNeg{}, usedPos{}, usedNeg{};\n        long long sumW = 0;\n        int dotCount = 0;\n    };\n    struct HeuParam {\n        // base score: w - m*(a*L + b*L^2) + m*g*conn\n        double a0, a1;\n        double b0, b1;\n        double g0, g1;\n        double m0, m1;\n\n        bool stochastic;\n        int pickK;\n        int keep;\n    };\n    struct RunConfig {\n        HeuParam h;\n        bool lookahead;\n        int laSteps;\n        int laBranch;\n        double laCoef;\n    };\n    struct RunResult {\n        long long sumW;\n        vector<Move> ops;\n    };\n    struct EliteEntry {\n        long long sumW;\n        RunConfig cfg;\n    };\n\n    int N = 0, M = 0;\n    int off = 0;\n    int diagCnt = 0;\n    double density = 0.0;\n\n    vector<pair<int, int>> initDots;\n    int W[MAXN][MAXN]{};\n    vector<pair<int, int>> cellsByWeight;\n    uint64_t rangeMask[MAXN + 1][MAXN + 1]{};\n\n    static inline constexpr array<int, 8> pairU = {0, 1, 2, 3, 4, 5, 6, 7};\n    static inline constexpr array<int, 8> pairV = {1, 2, 3, 0, 5, 6, 7, 4};\n\n    static inline int ctz64(uint64_t v) { return __builtin_ctzll(v); }\n    static inline int msb64(uint64_t v) { return 63 - __builtin_clzll(v); }\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    double randRange(XorShift64 &rng, double lo, double hi) const {\n        return lo + (hi - lo) * rng.nextDouble();\n    }\n\n    // approx normal-ish, mean 0, std ~0.707\n    double normalish(XorShift64 &rng) const {\n        double z = 0.0;\n        for (int i = 0; i < 6; i++) z += rng.nextDouble();\n        return z - 3.0;\n    }\n\n    void buildTables() {\n        off = N - 1;\n        diagCnt = 2 * N - 1;\n\n        int c = (N - 1) / 2;\n        cellsByWeight.clear();\n        cellsByWeight.reserve(N * N);\n\n        for (int y = 0; y < N; y++) {\n            for (int x = 0; x < N; x++) {\n                int dx = x - c;\n                int dy = y - c;\n                W[y][x] = dx * dx + dy * dy + 1;\n                cellsByWeight.emplace_back(x, y);\n            }\n        }\n\n        sort(cellsByWeight.begin(), cellsByWeight.end(), [&](const auto &a, const auto &b) {\n            int wa = W[a.second][a.first];\n            int wb = W[b.second][b.first];\n            if (wa != wb) return wa > wb;\n            if (a.second != b.second) return a.second < b.second;\n            return a.first < b.first;\n        });\n\n        for (int l = 0; l <= N; l++) for (int r = 0; r <= N; r++) rangeMask[l][r] = 0;\n        for (int l = 0; l <= N; l++) {\n            uint64_t m = 0;\n            for (int r = l + 1; r <= N; r++) {\n                m |= (1ULL << (r - 1)); // [l, r)\n                rangeMask[l][r] = m;\n            }\n        }\n    }\n\n    inline bool hasDot(const Core &st, int x, int y) const {\n        return ((st.row[y] >> x) & 1ULL) != 0;\n    }\n\n    inline void addDot(Core &st, int x, int y) const {\n        uint64_t bx = 1ULL << x;\n        st.row[y] |= bx;\n        st.col[x] |= (1ULL << y);\n        st.diagPos[x - y + off] |= bx; // keyed by x-bit\n        st.diagNeg[x + y] |= bx;       // keyed by x-bit\n        st.dotCount++;\n    }\n\n    Point nearestDot(const Core &st, int x, int y, int dir) const {\n        uint64_t m = 0;\n        switch (dir) {\n            case 0: // E\n                m = st.row[y] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                return {ctz64(m), y};\n            case 1: // N\n                m = st.col[x] & (~0ULL << (y + 1));\n                if (!m) return {-1, -1};\n                return {x, ctz64(m)};\n            case 2: // W\n                m = st.row[y] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                return {msb64(m), y};\n            case 3: // S\n                m = st.col[x] & ((1ULL << y) - 1);\n                if (!m) return {-1, -1};\n                return {x, msb64(m)};\n            case 4: { // NE\n                int d = x - y + off;\n                m = st.diagPos[d] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                int k = d - off;\n                return {nx, nx - k};\n            }\n            case 5: { // NW\n                int s = x + y;\n                m = st.diagNeg[s] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                return {nx, s - nx};\n            }\n            case 6: { // SW\n                int d = x - y + off;\n                m = st.diagPos[d] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                int k = d - off;\n                return {nx, nx - k};\n            }\n            default: { // 7: SE\n                int s = x + y;\n                m = st.diagNeg[s] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                return {nx, s - nx};\n            }\n        }\n    }\n\n    inline bool edgeFree(const Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) {\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            return (st.usedV[x] & rangeMask[l][r]) == 0;\n        }\n        if (y1 == y2) {\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedH[y] & rangeMask[l][r]) == 0;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedPos[d] & rangeMask[l][r]) == 0;\n        }\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        return (st.usedNeg[s] & rangeMask[l][r]) == 0;\n    }\n\n    inline void useEdge(Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) {\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            st.usedV[x] |= rangeMask[l][r];\n            return;\n        }\n        if (y1 == y2) {\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedH[y] |= rangeMask[l][r];\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedPos[d] |= rangeMask[l][r];\n            return;\n        }\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        st.usedNeg[s] |= rangeMask[l][r];\n    }\n\n    inline void applyMove(Core &st, const Move &mv) const {\n        useEdge(st, mv.x1, mv.y1, mv.x2, mv.y2);\n        useEdge(st, mv.x2, mv.y2, mv.x3, mv.y3);\n        useEdge(st, mv.x3, mv.y3, mv.x4, mv.y4);\n        useEdge(st, mv.x4, mv.y4, mv.x1, mv.y1);\n        addDot(st, mv.x1, mv.y1);\n        st.sumW += W[mv.y1][mv.x1];\n    }\n\n    Core makeBaseState() const {\n        Core st;\n        for (auto [x, y] : initDots) {\n            if (!hasDot(st, x, y)) {\n                addDot(st, x, y);\n                st.sumW += W[y][x];\n            }\n        }\n        return st;\n    }\n\n    inline void evalCoeffs(const HeuParam &h, double progress, double &a, double &b, double &g, double &m) const {\n        a = h.a0 + (h.a1 - h.a0) * progress;\n        b = h.b0 + (h.b1 - h.b0) * progress;\n        g = h.g0 + (h.g1 - h.g0) * progress;\n        m = h.m0 + (h.m1 - h.m0) * progress;\n\n        if (a < 0.0) a = 0.0;\n        if (b < 0.0) b = 0.0;\n        if (g < 0.0) g = 0.0;\n        m = clampD(m, 0.0, 1.5);\n    }\n\n    inline bool betterCand(const Candidate &A, const Candidate &B) const {\n        if (A.val > B.val + 1e-9) return true;\n        if (A.val + 1e-9 < B.val) return false;\n        if (A.w != B.w) return A.w > B.w;\n        return A.L < B.L;\n    }\n\n    void findTopCandidates(const Core &st, double a, double b, double g, double m, int keep,\n                           vector<Candidate> &out) const {\n        out.clear();\n        if (keep <= 0) return;\n        if ((int)out.capacity() < keep + 1) out.reserve(keep + 1);\n\n        array<Point, 8> near{};\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n\n            if ((int)out.size() == keep) {\n                double ub = (double)w - m * (a * 2.0 + b * 4.0) + m * g * 8.0;\n                if (ub + 1e-9 < out.back().val) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n            if (conn < 2) continue;\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du];\n                Point p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                // rule2 (remaining two sides)\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                // rule3 (segment overlap)\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double val = (double)w - m * (a * (double)L + b * (double)L * (double)L) + m * g * (double)conn;\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                int pos = 0;\n                while (pos < (int)out.size() && !betterCand(cand, out[pos])) pos++;\n                if (pos >= keep) continue;\n\n                out.insert(out.begin() + pos, cand);\n                if ((int)out.size() > keep) out.pop_back();\n            }\n        }\n    }\n\n    double findBestValue(const Core &st, double a, double b, double g, double m) const {\n        bool found = false;\n        double best = NEG_INF;\n\n        array<Point, 8> near{};\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n\n            if (found) {\n                double ub = (double)w - m * (a * 2.0 + b * 4.0) + m * g * 8.0;\n                if (ub + 1e-9 < best) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n            if (conn < 2) continue;\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du];\n                Point p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double val = (double)w - m * (a * (double)L + b * (double)L * (double)L) + m * g * (double)conn;\n                if (!found || val > best) {\n                    found = true;\n                    best = val;\n                }\n            }\n        }\n\n        return found ? best : NEG_INF;\n    }\n\n    int pickRankedIndex(int k, XorShift64 &rng) const {\n        if (k <= 1) return 0;\n        int total = k * (k + 1) / 2;\n        int r = rng.nextInt(total);\n        for (int i = 0; i < k; i++) {\n            int wt = k - i;\n            if (r < wt) return i;\n            r -= wt;\n        }\n        return k - 1;\n    }\n\n    bool selectMove(const Core &st, const RunConfig &cfg, int moveCnt, int baseDotCount, int totalAddable,\n                    XorShift64 &rng, Clock::time_point deadline, Move &out, vector<Candidate> &cands) const {\n        double progress = (double)(st.dotCount - baseDotCount) / (double)max(1, totalAddable);\n\n        double a, b, g, m;\n        evalCoeffs(cfg.h, progress, a, b, g, m);\n\n        bool laPossible = cfg.lookahead && (moveCnt < cfg.laSteps);\n\n        int keep = cfg.h.keep;\n        if (!cfg.h.stochastic && !laPossible) keep = 1;\n        keep = max(keep, max(1, cfg.h.pickK));\n        if (laPossible) keep = max(keep, max(2, cfg.laBranch));\n        if (Clock::now() + chrono::milliseconds(2) >= deadline) keep = min(keep, 10);\n\n        findTopCandidates(st, a, b, g, m, keep, cands);\n        if (cands.empty()) return false;\n\n        int idx = 0;\n\n        bool doLA = laPossible && ((int)cands.size() >= 2);\n        if (doLA) {\n            if (Clock::now() + chrono::milliseconds(3) >= deadline) doLA = false;\n            if ((int)cands.size() >= 2 && cands[0].val - cands[1].val > 95.0) doLA = false;\n        }\n\n        if (doLA) {\n            int B = min(cfg.laBranch, (int)cands.size());\n            vector<pair<double, int>> comb;\n            comb.reserve(B);\n\n            for (int i = 0; i < B; i++) {\n                if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n                Core tmp = st;\n                applyMove(tmp, cands[i].mv);\n\n                double p2 = (double)(tmp.dotCount - baseDotCount) / (double)max(1, totalAddable);\n                double a2, b2, g2, m2;\n                evalCoeffs(cfg.h, p2, a2, b2, g2, m2);\n\n                double nxt = findBestValue(tmp, a2, b2, g2, m2);\n                if (nxt < -1e90) nxt = 0.0;\n\n                double score = cands[i].val + cfg.laCoef * nxt;\n                comb.emplace_back(score, i);\n            }\n\n            if (!comb.empty()) {\n                sort(comb.begin(), comb.end(), [&](const auto &A, const auto &B) {\n                    return A.first > B.first;\n                });\n\n                if (cfg.h.stochastic) {\n                    int k = min(cfg.h.pickK, (int)comb.size());\n                    int r = pickRankedIndex(max(1, k), rng);\n                    idx = comb[r].second;\n                } else {\n                    idx = comb[0].second;\n                }\n            } else {\n                doLA = false;\n            }\n        }\n\n        if (!doLA) {\n            if (cfg.h.stochastic) {\n                int k = min(cfg.h.pickK, (int)cands.size());\n                idx = pickRankedIndex(max(1, k), rng);\n            } else {\n                idx = 0;\n            }\n        }\n\n        out = cands[idx].mv;\n        return true;\n    }\n\n    RunResult runOne(const Core &base, const RunConfig &cfg, XorShift64 &rng, Clock::time_point deadline) const {\n        Core st = base;\n        vector<Move> ops;\n        ops.reserve(max(0, N * N - base.dotCount));\n\n        vector<Candidate> cands;\n        cands.reserve(48);\n\n        int baseDotCount = base.dotCount;\n        int totalAddable = max(1, N * N - baseDotCount);\n\n        int moveCnt = 0;\n        while (true) {\n            if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n            Move mv;\n            if (!selectMove(st, cfg, moveCnt, baseDotCount, totalAddable, rng, deadline, mv, cands)) break;\n\n            applyMove(st, mv);\n            ops.push_back(mv);\n            moveCnt++;\n        }\n\n        return {st.sumW, move(ops)};\n    }\n\n    void normalizeConfig(RunConfig &cfg, int remainMs) const {\n        cfg.h.a0 = clampD(cfg.h.a0, 0.0, 8.0);\n        cfg.h.a1 = clampD(cfg.h.a1, 0.0, 4.0);\n        cfg.h.b0 = clampD(cfg.h.b0, 0.0, 0.08);\n        cfg.h.b1 = clampD(cfg.h.b1, 0.0, 0.05);\n        cfg.h.g0 = clampD(cfg.h.g0, 0.0, 4.0);\n        cfg.h.g1 = clampD(cfg.h.g1, 0.0, 3.0);\n        cfg.h.m0 = clampD(cfg.h.m0, 0.0, 1.5);\n        cfg.h.m1 = clampD(cfg.h.m1, 0.0, 1.5);\n\n        cfg.h.pickK = std::clamp(cfg.h.pickK, 1, 10);\n        cfg.h.keep = std::clamp(cfg.h.keep, 1, 32);\n        if (!cfg.h.stochastic) cfg.h.pickK = 1;\n\n        if (remainMs < 800) cfg.lookahead = false;\n\n        if (cfg.lookahead) {\n            cfg.laSteps = std::clamp(cfg.laSteps, 20, 220);\n            cfg.laBranch = std::clamp(cfg.laBranch, 2, 6);\n            cfg.laCoef = clampD(cfg.laCoef, 0.35, 1.20);\n            cfg.h.keep = max(cfg.h.keep, cfg.laBranch);\n        } else {\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laCoef = 0.0;\n        }\n\n        cfg.h.keep = max(cfg.h.keep, cfg.h.pickK);\n\n        if (remainMs < 500) {\n            cfg.lookahead = false;\n            cfg.h.keep = min(cfg.h.keep, 14);\n            cfg.h.pickK = min(cfg.h.pickK, 5);\n        }\n        if (remainMs < 300) {\n            cfg.h.keep = min(cfg.h.keep, 10);\n            cfg.h.pickK = min(cfg.h.pickK, 3);\n        }\n    }\n\n    RunConfig randomGlobalConfig(XorShift64 &rng, int remainMs) const {\n        RunConfig cfg{};\n\n        double densF = 1.0;\n        if (density < 0.040) densF = 1.15;\n        else if (density > 0.065) densF = 0.90;\n\n        cfg.h.a0 = randRange(rng, 0.0, 5.6 * densF);\n        cfg.h.a1 = randRange(rng, 0.0, 2.3);\n        cfg.h.b0 = randRange(rng, 0.0, 0.040 * densF);\n        cfg.h.b1 = randRange(rng, 0.0, 0.022);\n        cfg.h.g0 = randRange(rng, 0.0, 2.2);\n        cfg.h.g1 = randRange(rng, 0.0, 1.3);\n        cfg.h.m0 = randRange(rng, 0.45, 1.12);\n        cfg.h.m1 = randRange(rng, 0.35, 1.05);\n\n        if (rng.nextInt(5) == 0) swap(cfg.h.a0, cfg.h.a1);\n        if (rng.nextInt(6) == 0) swap(cfg.h.b0, cfg.h.b1);\n        if (rng.nextInt(5) == 0) swap(cfg.h.g0, cfg.h.g1);\n        if (rng.nextInt(7) == 0) swap(cfg.h.m0, cfg.h.m1);\n\n        cfg.h.stochastic = (rng.nextInt(100) < 88);\n        cfg.h.pickK = 2 + rng.nextInt(7);  // 2..8\n        cfg.h.keep = 8 + rng.nextInt(17);  // 8..24\n\n        if (!cfg.h.stochastic) {\n            cfg.h.pickK = 1;\n            cfg.h.keep = 1 + rng.nextInt(8);\n        }\n\n        bool allowLA = (remainMs > 900 && rng.nextInt(100) < 18);\n        if (allowLA) {\n            cfg.lookahead = true;\n            cfg.laSteps = 40 + rng.nextInt(95); // 40..134\n            cfg.laBranch = 3 + rng.nextInt(3);  // 3..5\n            cfg.laCoef = randRange(rng, 0.55, 0.98);\n        } else {\n            cfg.lookahead = false;\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laCoef = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    RunConfig mutateConfig(const RunConfig &base, XorShift64 &rng, int remainMs) const {\n        RunConfig cfg = base;\n\n        auto madd = [&](double v, double sigma, double lo, double hi) {\n            v += normalish(rng) * sigma;\n            return clampD(v, lo, hi);\n        };\n\n        cfg.h.a0 = madd(cfg.h.a0, 0.80, 0.0, 8.0);\n        cfg.h.a1 = madd(cfg.h.a1, 0.45, 0.0, 4.0);\n        cfg.h.b0 = madd(cfg.h.b0, 0.007, 0.0, 0.08);\n        cfg.h.b1 = madd(cfg.h.b1, 0.004, 0.0, 0.05);\n        cfg.h.g0 = madd(cfg.h.g0, 0.35, 0.0, 4.0);\n        cfg.h.g1 = madd(cfg.h.g1, 0.25, 0.0, 3.0);\n        cfg.h.m0 = madd(cfg.h.m0, 0.10, 0.0, 1.5);\n        cfg.h.m1 = madd(cfg.h.m1, 0.10, 0.0, 1.5);\n\n        if (rng.nextInt(100) < 8) cfg.h.stochastic = !cfg.h.stochastic;\n        cfg.h.pickK = std::clamp(cfg.h.pickK + (rng.nextInt(5) - 2), 1, 10);\n        cfg.h.keep = std::clamp(cfg.h.keep + (rng.nextInt(11) - 5), 1, 32);\n\n        if (remainMs < 800) {\n            cfg.lookahead = false;\n        } else {\n            if (rng.nextInt(100) < 10) cfg.lookahead = !cfg.lookahead;\n            if (!cfg.lookahead && remainMs > 1300 && rng.nextInt(100) < 18) cfg.lookahead = true;\n        }\n\n        if (cfg.lookahead) {\n            if (cfg.laSteps == 0) cfg.laSteps = 70;\n            if (cfg.laBranch == 0) cfg.laBranch = 4;\n            if (cfg.laCoef == 0.0) cfg.laCoef = 0.75;\n\n            cfg.laSteps = std::clamp(cfg.laSteps + (rng.nextInt(61) - 30), 20, 220);\n            cfg.laBranch = std::clamp(cfg.laBranch + (rng.nextInt(3) - 1), 2, 6);\n            cfg.laCoef = clampD(cfg.laCoef + normalish(rng) * 0.08, 0.35, 1.20);\n        } else {\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laCoef = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    void addElite(vector<EliteEntry> &elite, long long sumW, const RunConfig &cfg) const {\n        EliteEntry e{sumW, cfg};\n        int pos = 0;\n        while (pos < (int)elite.size() && elite[pos].sumW >= sumW) pos++;\n        if (pos >= 8) return;\n        elite.insert(elite.begin() + pos, e);\n        if ((int)elite.size() > 8) elite.pop_back();\n    }\n\n    int pickEliteIndex(const vector<EliteEntry> &elite, XorShift64 &rng) const {\n        return pickRankedIndex((int)elite.size(), rng);\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t seed = 1469598103934665603ULL; // FNV offset\n        auto mix = [&](uint64_t v) {\n            seed ^= v;\n            seed *= 1099511628211ULL;\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        for (auto [x, y] : initDots) {\n            mix(((uint64_t)(uint32_t)x << 32) | (uint32_t)y);\n        }\n        return seed ? seed : 1ULL;\n    }\n\npublic:\n    void readInput() {\n        cin >> N >> M;\n        initDots.resize(M);\n        for (int i = 0; i < M; i++) {\n            int x, y;\n            cin >> x >> y;\n            initDots[i] = {x, y};\n        }\n        density = (double)M / (double)(N * N);\n        buildTables();\n    }\n\n    void solve() {\n        Core base = makeBaseState();\n\n        long long bestSum = base.sumW;\n        vector<Move> bestOps;\n\n        XorShift64 rng(makeSeed());\n        auto deadline = Clock::now() + chrono::milliseconds(4760);\n\n        auto mk = [&](double a0, double a1, double b0, double b1, double g0, double g1,\n                      double m0, double m1,\n                      bool stochastic, int pickK, int keep,\n                      bool lookahead, int laSteps, int laBranch, double laCoef) {\n            RunConfig c;\n            c.h = {a0, a1, b0, b1, g0, g1, m0, m1, stochastic, pickK, keep};\n            c.lookahead = lookahead;\n            c.laSteps = laSteps;\n            c.laBranch = laBranch;\n            c.laCoef = laCoef;\n            return c;\n        };\n\n        vector<EliteEntry> elites;\n\n        auto runAndUpdate = [&](RunConfig cfg) {\n            int remainMs = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            normalizeConfig(cfg, remainMs);\n            if (Clock::now() + chrono::milliseconds(6) >= deadline) return;\n            RunResult rr = runOne(base, cfg, rng, deadline);\n            addElite(elites, rr.sumW, cfg);\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = move(rr.ops);\n            }\n        };\n\n        // ---- Stable + diverse presets (include previous strong lineups) ----\n        vector<RunConfig> presets;\n        presets.push_back(mk(3.0, 0.2, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0.0));\n        presets.push_back(mk(1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0.0));\n        presets.push_back(mk(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0.0));\n\n        presets.push_back(mk(2.5, 0.3, 0.010, 0.001, 1.2, 0.1, 0.95, 0.85, true, 4, 20, false, 0, 0, 0.0));\n        presets.push_back(mk(0.9, 0.0, 0.001, 0.0, 0.5, 0.0, 0.65, 0.50, true, 6, 24, false, 0, 0, 0.0));\n\n        presets.push_back(mk(4.4, 0.9, 0.020, 0.002, 1.8, 0.2, 1.0, 0.9, false, 1, 12, true, 90, 4, 0.78));\n        presets.push_back(mk(3.2, 0.6, 0.013, 0.002, 1.1, 0.1, 0.95, 0.85, true, 3, 14, true, 70, 4, 0.68));\n\n        if (density < 0.040) {\n            presets.push_back(mk(5.4, 1.2, 0.030, 0.005, 1.8, 0.25, 1.0, 0.9, false, 1, 10, false, 0, 0, 0.0));\n        } else {\n            presets.push_back(mk(1.3, 0.1, 0.003, 0.0, 0.7, 0.0, 0.8, 0.65, true, 5, 18, false, 0, 0, 0.0));\n        }\n\n        for (auto cfg : presets) {\n            if (Clock::now() + chrono::milliseconds(12) >= deadline) break;\n            runAndUpdate(cfg);\n        }\n\n        // ---- Adaptive multi-start: global random + elite mutation ----\n        while (Clock::now() + chrono::milliseconds(24) < deadline) {\n            int remainMs = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n\n            RunConfig cfg;\n            int mode = rng.nextInt(100);\n\n            if (elites.empty() || mode < 35) {\n                cfg = randomGlobalConfig(rng, remainMs);\n            } else {\n                int ei = pickEliteIndex(elites, rng);\n                if (mode < 58 && elites[ei].cfg.h.stochastic) {\n                    cfg = elites[ei].cfg; // resample same good stochastic policy\n                } else {\n                    cfg = mutateConfig(elites[ei].cfg, rng, remainMs);\n                }\n            }\n\n            runAndUpdate(cfg);\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (const auto &m : bestOps) {\n            cout << m.x1 << ' ' << m.y1 << ' '\n                 << m.x2 << ' ' << m.y2 << ' '\n                 << m.x3 << ' ' << m.y3 << ' '\n                 << m.x4 << ' ' << m.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int CELLS = 100;\nstatic constexpr double TIME_LIMIT = 1.90;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Board {\n    uint8_t a[CELLS];\n    int filled;\n};\n\nint F[101];\nint SUF[102][4]; // SUF[t][c] = count of flavor c in [t..100]\nint NEI[CELLS][4];\n\ninline void init_neighbors() {\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int id = r * N + c;\n            NEI[id][0] = (r > 0) ? id - N : -1;      // F (up)\n            NEI[id][1] = (r + 1 < N) ? id + N : -1;  // B (down)\n            NEI[id][2] = (c > 0) ? id - 1 : -1;      // L\n            NEI[id][3] = (c + 1 < N) ? id + 1 : -1;  // R\n        }\n    }\n}\n\ninline void tilt(const Board& src, Board& dst, int dir) {\n    dst.filled = src.filled;\n    if (dir == 2) { // L\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = 0;\n            for (int c = 0; c < N; ++c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w++)] = v;\n            }\n            while (w < N) dst.a[base + (w++)] = 0;\n        }\n    } else if (dir == 3) { // R\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w--)] = v;\n            }\n            while (w >= 0) dst.a[base + (w--)] = 0;\n        }\n    } else if (dir == 0) { // F\n        for (int c = 0; c < N; ++c) {\n            int w = 0;\n            for (int r = 0; r < N; ++r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w++) * N + c] = v;\n            }\n            while (w < N) dst.a[(w++) * N + c] = 0;\n        }\n    } else { // B\n        for (int c = 0; c < N; ++c) {\n            int w = N - 1;\n            for (int r = N - 1; r >= 0; --r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w--) * N + c] = v;\n            }\n            while (w >= 0) dst.a[(w--) * N + c] = 0;\n        }\n    }\n}\n\ninline void place_by_rank(Board& b, int rank, uint8_t flavor) {\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            if (--rank == 0) {\n                b.a[i] = flavor;\n                ++b.filled;\n                return;\n            }\n        }\n    }\n    // Fallback (shouldn't happen)\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            b.a[i] = flavor;\n            ++b.filled;\n            return;\n        }\n    }\n}\n\ninline void comp_sq_by_flavor(const Board& b, int out[4]) {\n    out[0] = out[1] = out[2] = out[3] = 0;\n\n    static uint32_t seen[CELLS];\n    static uint32_t stamp = 1;\n    ++stamp;\n    if (stamp == 0) {\n        memset(seen, 0, sizeof(seen));\n        stamp = 1;\n    }\n\n    int q[CELLS];\n    for (int i = 0; i < CELLS; ++i) {\n        uint8_t col = b.a[i];\n        if (col == 0 || seen[i] == stamp) continue;\n\n        seen[i] = stamp;\n        int head = 0, tail = 0;\n        q[tail++] = i;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            ++sz;\n            int to;\n\n            to = NEI[v][0];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n            to = NEI[v][1];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n            to = NEI[v][2];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n            to = NEI[v][3];\n            if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                seen[to] = stamp;\n                q[tail++] = to;\n            }\n        }\n        out[col] += sz * sz;\n    }\n}\n\ninline int comp_sq_total(const Board& b) {\n    int c[4];\n    comp_sq_by_flavor(b, c);\n    return c[1] + c[2] + c[3];\n}\n\n// Heuristic score used in rollout / lookahead.\n// nextTurn: first future turn index not yet processed (1..101).\ninline long long state_score(const Board& b, int nextTurn) {\n    if (nextTurn > 101) nextTurn = 101;\n    int c[4];\n    comp_sq_by_flavor(b, c);\n\n    long long total = static_cast<long long>(c[1] + c[2] + c[3]);\n\n    // Main objective + mild bias to flavors with many future candies.\n    long long score = total * 96LL;\n    score += 1LL * c[1] * SUF[nextTurn][1];\n    score += 1LL * c[2] * SUF[nextTurn][2];\n    score += 1LL * c[3] * SUF[nextTurn][3];\n    return score;\n}\n\ninline void greedy_tilt_rollout(Board& b, int turn) {\n    // turn = current turn u (after placing candy u), choose tilt for u\n    Board tmp, bestB;\n    long long bestVal = LLONG_MIN;\n    int nextTurn = turn + 1;\n\n    for (int d = 0; d < 4; ++d) {\n        tilt(b, tmp, d);\n        long long v = state_score(tmp, nextTurn);\n        if (v > bestVal) {\n            bestVal = v;\n            bestB = tmp;\n        }\n    }\n    b = bestB;\n}\n\ndouble exact_expect(const Board& b, int nextTurn) {\n    // State: board after previous tilt, before placing candy nextTurn.\n    if (nextTurn == 101) {\n        return static_cast<double>(comp_sq_total(b));\n    }\n\n    int empties = 101 - nextTurn;\n    double sum = 0.0;\n\n    for (int p = 1; p <= empties; ++p) {\n        Board placed = b;\n        place_by_rank(placed, p, static_cast<uint8_t>(F[nextTurn]));\n\n        if (nextTurn == 100) {\n            // Last candy: final tilt has no effect.\n            sum += static_cast<double>(comp_sq_total(placed));\n        } else {\n            double best = -1e100;\n            Board nxt;\n            for (int d = 0; d < 4; ++d) {\n                tilt(placed, nxt, d);\n                double v = exact_expect(nxt, nextTurn + 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n    }\n    return sum / static_cast<double>(empties);\n}\n\nint choose_move(const Board& cur, int t, XorShift& rng, const Timer& timer) {\n    int rem = 100 - t;\n    if (rem <= 0) return 0;\n\n    Board first[4];\n    long long firstScore[4];\n    for (int d = 0; d < 4; ++d) {\n        tilt(cur, first[d], d);\n        firstScore[d] = state_score(first[d], t + 1);\n    }\n\n    int bestImmediate = 0;\n    for (int d = 1; d < 4; ++d) {\n        if (firstScore[d] > firstScore[bestImmediate]) bestImmediate = d;\n    }\n\n    double timeLeft = TIME_LIMIT - timer.elapsed();\n    if (timeLeft < 0.010) return bestImmediate;\n\n    // Exact endgame optimization.\n    if (rem <= 5 && timeLeft > 0.050) {\n        int bestDir = bestImmediate;\n        double bestVal = -1e100;\n        for (int d = 0; d < 4; ++d) {\n            double v = exact_expect(first[d], t + 1);\n            if (v > bestVal + 1e-12 ||\n                (fabs(v - bestVal) <= 1e-12 && firstScore[d] > firstScore[bestDir])) {\n                bestVal = v;\n                bestDir = d;\n            }\n        }\n        return bestDir;\n    }\n\n    // Adaptive horizon.\n    int H;\n    if (rem >= 70) H = 10;\n    else if (rem >= 50) H = 14;\n    else if (rem >= 35) H = 18;\n    else if (rem >= 22) H = 24;\n    else H = rem;\n\n    H = min(H, rem);\n    int endTurn = t + H;\n    int evalNextTurn = min(101, endTurn + 1);\n\n    // Adaptive per-turn time budget.\n    double reserve = 0.050;\n    double budget = timeLeft / (rem + 1) * 1.35;\n    if (rem <= 15) budget *= 1.20;\n\n    budget = min(budget, 0.040);\n    budget = max(budget, 0.0015);\n    if (timeLeft - reserve < budget) budget = max(0.0008, timeLeft - reserve);\n\n    if (budget <= 0.0009) return bestImmediate;\n\n    long long total[4] = {0, 0, 0, 0};\n    int cnt = 0;\n    uint8_t ranks[101];\n\n    double deadline = timer.elapsed() + budget;\n    const int MAX_SCENARIOS = 96;\n    int minScen = (budget < 0.0035 ? 1 : 2);\n\n    while (cnt < MAX_SCENARIOS) {\n        if (cnt >= minScen && timer.elapsed() > deadline) break;\n\n        // Common random numbers across 4 candidate first moves.\n        for (int u = t + 1; u <= endTurn; ++u) {\n            ranks[u] = static_cast<uint8_t>(rng.next_int(1, 101 - u));\n        }\n\n        for (int d = 0; d < 4; ++d) {\n            Board b = first[d];\n\n            for (int u = t + 1; u <= endTurn; ++u) {\n                place_by_rank(b, static_cast<int>(ranks[u]), static_cast<uint8_t>(F[u]));\n                if (u < 100) {\n                    greedy_tilt_rollout(b, u);\n                }\n            }\n            total[d] += state_score(b, evalNextTurn);\n        }\n\n        ++cnt;\n    }\n\n    if (cnt == 0) return bestImmediate;\n\n    int bestDir = 0;\n    for (int d = 1; d < 4; ++d) {\n        if (total[d] > total[bestDir] ||\n            (total[d] == total[bestDir] && firstScore[d] > firstScore[bestDir])) {\n            bestDir = d;\n        }\n    }\n    return bestDir;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 1; i <= 100; ++i) {\n        if (!(cin >> F[i])) return 0;\n    }\n\n    for (int c = 1; c <= 3; ++c) SUF[101][c] = 0;\n    for (int t = 100; t >= 1; --t) {\n        for (int c = 1; c <= 3; ++c) SUF[t][c] = SUF[t + 1][c];\n        SUF[t][F[t]]++;\n    }\n\n    init_neighbors();\n\n    uint64_t seed = 1469598103934665603ull;\n    for (int i = 1; i <= 100; ++i) {\n        seed ^= static_cast<uint64_t>(F[i] + 131 * i);\n        seed *= 1099511628211ull;\n    }\n    XorShift rng(seed);\n    Timer timer;\n\n    Board cur{};\n    memset(cur.a, 0, sizeof(cur.a));\n    cur.filled = 0;\n\n    for (int t = 1; t <= 100; ++t) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        place_by_rank(cur, p, static_cast<uint8_t>(F[t]));\n\n        int dir = 0; // F\n        if (t < 100) {\n            dir = choose_move(cur, t, rng, timer);\n            Board nxt;\n            tilt(cur, nxt, dir);\n            cur = nxt;\n        }\n\n        cout << DIR_CH[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    inline 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    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline uint64_t prob_to_u64(double p) {\n    if (p <= 0.0) return 0ULL;\n    if (p >= 1.0) return numeric_limits<uint64_t>::max();\n    long double v = p * (long double)numeric_limits<uint64_t>::max();\n    if (v < 0) v = 0;\n    if (v > (long double)numeric_limits<uint64_t>::max()) v = (long double)numeric_limits<uint64_t>::max();\n    return (uint64_t)v;\n}\n\nstruct Sig3 {\n    int d, n1, n2;\n    bool operator<(const Sig3& o) const {\n        if (d != o.d) return d < o.d;\n        if (n1 != o.n1) return n1 < o.n1;\n        return n2 < o.n2;\n    }\n};\n\nstruct Graph {\n    vector<uint8_t> bits; // length L\n    vector<int> deg_sorted;\n    vector<int> nd_sorted;\n    vector<int> nd2_sorted;\n    int edges = 0;\n    int uniq_sig = 0;\n};\n\nstruct Codebook {\n    int N = 0;\n    int L = 0;\n    int B = 0;\n    int FB = 0;\n    int distinct = 0;\n\n    vector<int> eu, ev;        // edge endpoints by lex order\n    vector<int> pairId;        // size B*B\n    vector<int> blockCap;      // size FB\n    vector<Graph> graphs;      // size M\n};\n\nstruct FeatureWork {\n    vector<int> deg, nd, nd2;\n    vector<int> ord, bin;\n    vector<uint64_t> key;      // random tiebreak keys\n    vector<uint8_t> bits;      // noisy sampled bits\n\n    FeatureWork() {}\n    FeatureWork(int N, int L) { init(N, L); }\n\n    void init(int N, int L) {\n        deg.assign(N, 0);\n        nd.assign(N, 0);\n        nd2.assign(N, 0);\n        ord.resize(N);\n        bin.assign(N, 0);\n        key.assign(N, 0);\n        bits.assign(L, 0);\n    }\n};\n\nstruct ProtoBank {\n    int M = 0, N = 0, S = 0, FB = 0;\n    // samples\n    vector<int16_t> sdeg;   // M*S*N\n    vector<int32_t> snd;    // M*S*N\n    vector<int32_t> snd2;   // M*S*N\n    vector<uint16_t> sblk;  // M*S*FB\n\n    // centers\n    vector<float> cdeg;     // M*N\n    vector<float> cnd;      // M*N\n    vector<float> cnd2;     // M*N\n    vector<float> cblk;     // M*FB\n\n    // inverse variances (global)\n    double invD = 1.0;\n    double invN1 = 1.0;\n    double invN2 = 1.0;\n    vector<double> invB;    // FB\n};\n\nstruct DecodeParam {\n    double m1 = 1.0;    // nd multiplier\n    double m2 = 0.0;    // nd2 multiplier\n    double mB = 0.0;    // block multiplier\n\n    double a1 = 0.7;    // min1 sample weight\n    double a2 = 0.1;    // min2 sample weight\n    double a3 = 0.2;    // center weight\n    bool useSecond = true;\n    string name;\n};\n\nstatic inline uint64_t fnv_mix(uint64_t h, uint64_t x) {\n    h ^= x;\n    h *= 1099511628211ULL;\n    return h;\n}\n\nuint64_t hash_sorted3(const vector<int>& a, const vector<int>& b, const vector<int>& c) {\n    uint64_t h = 1469598103934665603ULL;\n    int n = (int)a.size();\n    for (int i = 0; i < n; i++) {\n        h = fnv_mix(h, (uint64_t)(a[i] + 1));\n        h = fnv_mix(h, (uint64_t)(b[i] + 10007));\n        h = fnv_mix(h, (uint64_t)(c[i] + 1000003));\n    }\n    return h;\n}\n\nuint64_t hash_signature(const Graph& g) {\n    uint64_t h = 1469598103934665603ULL;\n    h = fnv_mix(h, (uint64_t)(g.edges + 1));\n    h = fnv_mix(h, (uint64_t)(g.uniq_sig + 3));\n    int n = (int)g.deg_sorted.size();\n    for (int i = 0; i < n; i++) {\n        h = fnv_mix(h, (uint64_t)(g.deg_sorted[i] + 1));\n        h = fnv_mix(h, (uint64_t)(g.nd_sorted[i] + 10007));\n        h = fnv_mix(h, (uint64_t)(g.nd2_sorted[i] + 1000003));\n    }\n    return h;\n}\n\nvoid build_edges(int N, vector<int>& eu, vector<int>& ev) {\n    eu.clear();\n    ev.clear();\n    eu.reserve(N * (N - 1) / 2);\n    ev.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            eu.push_back(i);\n            ev.push_back(j);\n        }\n    }\n}\n\nint choose_bins(int N) {\n    if (N <= 10) return 3;\n    if (N <= 16) return 4;\n    if (N <= 25) return 5;\n    if (N <= 40) return 6;\n    if (N <= 64) return 8;\n    return 10;\n}\n\nvoid init_block_meta(Codebook& cb) {\n    cb.B = choose_bins(cb.N);\n    cb.FB = cb.B * (cb.B + 1) / 2;\n    cb.pairId.assign(cb.B * cb.B, -1);\n    cb.blockCap.assign(cb.FB, 0);\n\n    vector<int> sz(cb.B);\n    for (int b = 0; b < cb.B; b++) {\n        int l = (long long)b * cb.N / cb.B;\n        int r = (long long)(b + 1) * cb.N / cb.B;\n        sz[b] = r - l;\n    }\n\n    int id = 0;\n    for (int i = 0; i < cb.B; i++) {\n        for (int j = i; j < cb.B; j++) {\n            cb.pairId[i * cb.B + j] = id;\n            cb.pairId[j * cb.B + i] = id;\n            int cap = (i == j) ? (sz[i] * (sz[i] - 1) / 2) : (sz[i] * sz[j]);\n            cb.blockCap[id] = cap;\n            id++;\n        }\n    }\n}\n\nGraph make_graph_from_bits(vector<uint8_t>&& bits, int N, const vector<int>& eu, const vector<int>& ev) {\n    Graph g;\n    g.bits = std::move(bits);\n    int L = (int)eu.size();\n\n    vector<int> deg(N, 0), nd(N, 0), nd2(N, 0);\n    g.edges = 0;\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            g.edges++;\n            int u = eu[e], v = ev[e];\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd[u] += deg[v];\n            nd[v] += deg[u];\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd2[u] += nd[v];\n            nd2[v] += nd[u];\n        }\n    }\n\n    vector<Sig3> sig(N);\n    for (int i = 0; i < N; i++) sig[i] = {deg[i], nd[i], nd2[i]};\n    sort(sig.begin(), sig.end());\n\n    g.deg_sorted.resize(N);\n    g.nd_sorted.resize(N);\n    g.nd2_sorted.resize(N);\n    g.uniq_sig = 0;\n    for (int i = 0; i < N; i++) {\n        g.deg_sorted[i] = sig[i].d;\n        g.nd_sorted[i] = sig[i].n1;\n        g.nd2_sorted[i] = sig[i].n2;\n        if (i == 0 || sig[i].d != sig[i - 1].d || sig[i].n1 != sig[i - 1].n1 || sig[i].n2 != sig[i - 1].n2) {\n            g.uniq_sig++;\n        }\n    }\n    return g;\n}\n\nvector<int> random_group_ids(int N, int K, RNG& rng) {\n    K = min(K, N);\n    vector<int> sz(K, 1);\n    int rem = N - K;\n    for (int i = 0; i < rem; i++) sz[rng.next_int(0, K - 1)]++;\n\n    vector<int> gid;\n    gid.reserve(N);\n    for (int g = 0; g < K; g++) {\n        for (int c = 0; c < sz[g]; c++) gid.push_back(g);\n    }\n    for (int i = N - 1; i >= 1; i--) {\n        int j = rng.next_int(0, i);\n        swap(gid[i], gid[j]);\n    }\n    return gid;\n}\n\nint pick_mode(double eps, RNG& rng) {\n    double r = rng.next_double();\n    if (eps >= 0.28) {\n        // More random/threshold-like for high noise\n        if (r < 0.25) return 0;   // ER\n        if (r < 0.45) return 4;   // sum threshold\n        if (r < 0.63) return 5;   // product threshold\n        if (r < 0.78) return 6;   // interval\n        if (r < 0.90) return 7;   // xor partitions\n        if (r < 0.97) return 9;   // hub threshold\n        return 8;                 // threshold insertion\n    } else if (eps >= 0.15) {\n        if (r < 0.18) return 0;\n        if (r < 0.32) return 1;\n        if (r < 0.44) return 2;\n        if (r < 0.56) return 3;\n        if (r < 0.68) return 4;\n        if (r < 0.78) return 5;\n        if (r < 0.87) return 6;\n        if (r < 0.94) return 7;\n        if (r < 0.97) return 8;\n        return 9;\n    } else {\n        return rng.next_int(0, 9);\n    }\n}\n\nGraph generate_candidate_graph(int N, const vector<int>& eu, const vector<int>& ev, RNG& rng, double eps) {\n    int L = (int)eu.size();\n    vector<uint8_t> bits(L, 0);\n\n    int mode = pick_mode(eps, rng);\n\n    if (mode == 0) {\n        // ER (biased to extremes)\n        double u = rng.next_double();\n        double p = (rng.next_double() < 0.5) ? (u * u) : (1.0 - (1.0 - u) * (1.0 - u));\n        uint64_t th = prob_to_u64(p);\n        for (int e = 0; e < L; e++) bits[e] = (rng.next_u64() < th);\n    } else if (mode == 1) {\n        // Binary SBM\n        int K = rng.next_int(2, min(10, N));\n        auto gid = random_group_ids(N, K, rng);\n        vector<vector<uint8_t>> B(K, vector<uint8_t>(K, 0));\n        for (int i = 0; i < K; i++) {\n            for (int j = i; j < K; j++) {\n                uint8_t x = (uint8_t)(rng.next_u64() & 1ULL);\n                B[i][j] = B[j][i] = x;\n            }\n        }\n        for (int e = 0; e < L; e++) bits[e] = B[gid[eu[e]]][gid[ev[e]]];\n    } else if (mode == 2) {\n        // Union of cliques\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] == gid[ev[e]]);\n    } else if (mode == 3) {\n        // Complete multipartite\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] != gid[ev[e]]);\n    } else if (mode == 4) {\n        // Sum threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 2000);\n        for (int e = 0; e < L; e++) bits[e] = (w[eu[e]] + w[ev[e]] >= th);\n    } else if (mode == 5) {\n        // Product threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000000);\n        for (int e = 0; e < L; e++) {\n            long long v = 1LL * w[eu[e]] * w[ev[e]];\n            bits[e] = (v >= th);\n        }\n    } else if (mode == 6) {\n        // Interval/circle graph\n        vector<double> x(N);\n        for (int i = 0; i < N; i++) x[i] = rng.next_double();\n        bool circle = (rng.next_u64() & 1ULL);\n        double th = rng.next_double() * 0.85;\n        for (int e = 0; e < L; e++) {\n            double d = fabs(x[eu[e]] - x[ev[e]]);\n            if (circle) d = min(d, 1.0 - d);\n            bits[e] = (d <= th);\n        }\n    } else if (mode == 7) {\n        // XOR of two partitions\n        int K1 = rng.next_int(2, min(7, N));\n        int K2 = rng.next_int(2, min(7, N));\n        auto g1 = random_group_ids(N, K1, rng);\n        auto g2 = random_group_ids(N, K2, rng);\n        for (int e = 0; e < L; e++) {\n            bool a = (g1[eu[e]] == g1[ev[e]]);\n            bool b = (g2[eu[e]] == g2[ev[e]]);\n            bits[e] = (uint8_t)(a ^ b);\n        }\n    } else if (mode == 8) {\n        // Threshold insertion style\n        vector<uint8_t> dom(N, 0);\n        double p1 = 0.15 + 0.7 * rng.next_double();\n        for (int i = 1; i < N; i++) dom[i] = (uint8_t)(rng.next_double() < p1);\n        for (int e = 0; e < L; e++) bits[e] = dom[ev[e]];\n    } else {\n        // Hub threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000);\n        for (int e = 0; e < L; e++) bits[e] = (max(w[eu[e]], w[ev[e]]) >= th);\n    }\n\n    // occasional complement\n    if (rng.next_double() < 0.08) {\n        for (int e = 0; e < L; e++) bits[e] ^= 1;\n    }\n\n    // small perturbation\n    double pmax = (eps >= 0.25 ? 0.05 : 0.07);\n    if (rng.next_double() < 0.85) {\n        double pf = rng.next_double() * pmax;\n        uint64_t th = prob_to_u64(pf);\n        for (int e = 0; e < L; e++) {\n            if (rng.next_u64() < th) bits[e] ^= 1;\n        }\n    }\n\n    return make_graph_from_bits(std::move(bits), N, eu, ev);\n}\n\nCodebook build_codebook(int N, int M, double eps, int C, RNG& rng) {\n    Codebook cb;\n    cb.N = N;\n    build_edges(N, cb.eu, cb.ev);\n    cb.L = (int)cb.eu.size();\n    init_block_meta(cb);\n\n    vector<Graph> cand;\n    cand.reserve(C);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve((size_t)C * 3);\n\n    int attempts = 0;\n    int maxAttempts = C * 30;\n\n    while ((int)cand.size() < C && attempts < maxAttempts) {\n        Graph g = generate_candidate_graph(N, cb.eu, cb.ev, rng, eps);\n\n        if (eps >= 0.22) {\n            int th = (eps >= 0.30 ? max(3, N / 4) : max(3, N / 6));\n            if (g.uniq_sig < th && rng.next_double() < 0.75) {\n                attempts++;\n                continue;\n            }\n        }\n\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        attempts++;\n    }\n\n    // fallback: edge-prefix\n    for (int m = 0; (int)cand.size() < C && m <= cb.L; m++) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < m; e++) bits[e] = 1;\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n    }\n\n    // fallback: random bits\n    int extra = 0;\n    while ((int)cand.size() < C && extra < C * 10) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < cb.L; e++) bits[e] = (uint8_t)(rng.next_u64() & 1ULL);\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        extra++;\n    }\n\n    if (cand.empty()) {\n        vector<uint8_t> bits(cb.L, 0);\n        cand.push_back(make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev));\n    }\n\n    int Cn = (int)cand.size();\n\n    // Distance in sorted-feature space\n    double a = max(0.0, 1.0 - 2.0 * eps);\n    double w1 = (0.04 + 1.0 * a * a) / ((double)N * N);\n    double w2 = (eps < 0.25 ? (0.002 + 0.3 * a * a * a * a) / ((double)N * N * N * N) : 0.0);\n\n    auto dist_idx = [&](int ia, int ib) -> double {\n        const auto& A = cand[ia];\n        const auto& B = cand[ib];\n        double s = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)A.deg_sorted[i] - (double)B.deg_sorted[i];\n            s += d * d;\n        }\n        if (w1 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd_sorted[i] - (double)B.nd_sorted[i];\n                s += w1 * d * d;\n            }\n        }\n        if (w2 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd2_sorted[i] - (double)B.nd2_sorted[i];\n                s += w2 * d * d;\n            }\n        }\n        return s;\n    };\n\n    vector<int> selected;\n    selected.reserve(M);\n    vector<char> used(Cn, false);\n\n    int imin = 0, imax = 0;\n    for (int i = 1; i < Cn; i++) {\n        if (cand[i].edges < cand[imin].edges) imin = i;\n        if (cand[i].edges > cand[imax].edges) imax = i;\n    }\n    selected.push_back(imin);\n    used[imin] = true;\n    if ((int)selected.size() < M && imax != imin) {\n        selected.push_back(imax);\n        used[imax] = true;\n    }\n\n    vector<double> minDist(Cn, 1e300);\n    for (int i = 0; i < Cn; i++) {\n        double d = 1e300;\n        for (int s : selected) d = min(d, dist_idx(i, s));\n        minDist[i] = d;\n    }\n\n    double lambdaUniq = (eps >= 0.25 ? 0.5 : (eps >= 0.15 ? 0.3 : 0.1));\n\n    while ((int)selected.size() < M && (int)selected.size() < Cn) {\n        int best = -1;\n        double bestVal = -1.0;\n        for (int i = 0; i < Cn; i++) {\n            if (used[i]) continue;\n            double qual = 1.0 + lambdaUniq * ((double)cand[i].uniq_sig / max(1, N));\n            double val = minDist[i] * qual;\n            if (val > bestVal) {\n                bestVal = val;\n                best = i;\n            }\n        }\n        if (best == -1) break;\n        selected.push_back(best);\n        used[best] = true;\n\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i]) {\n                double d = dist_idx(i, best);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    int uniqueSel = (int)selected.size();\n    if (uniqueSel == 0) {\n        selected.push_back(0);\n        uniqueSel = 1;\n    }\n    while ((int)selected.size() < M) {\n        selected.push_back(selected[(int)selected.size() % uniqueSel]);\n    }\n\n    cb.distinct = min(uniqueSel, M);\n    cb.graphs.reserve(M);\n    for (int i = 0; i < M; i++) cb.graphs.push_back(cand[selected[i]]);\n    return cb;\n}\n\nvoid extract_features_from_string(\n    const string& H, const Codebook& cb, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2, vector<int>& outBlk\n) {\n    int N = cb.N, L = cb.L, B = cb.B, FB = cb.FB;\n\n    if ((int)outDeg.size() != N) {\n        outDeg.assign(N, 0);\n        outNd.assign(N, 0);\n        outNd2.assign(N, 0);\n    }\n    if ((int)outBlk.size() != FB) outBlk.assign(FB, 0);\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.ord[i] = i;\n    sort(w.ord.begin(), w.ord.end(), [&](int a, int b) {\n        if (w.deg[a] != w.deg[b]) return w.deg[a] < w.deg[b];\n        if (w.nd[a] != w.nd[b]) return w.nd[a] < w.nd[b];\n        if (w.nd2[a] != w.nd2[b]) return w.nd2[a] < w.nd2[b];\n        return a < b; // query labels are already shuffled randomly by judge\n    });\n\n    for (int pos = 0; pos < N; pos++) {\n        int v = w.ord[pos];\n        outDeg[pos] = w.deg[v];\n        outNd[pos] = w.nd[v];\n        outNd2[pos] = w.nd2[v];\n        w.bin[v] = (long long)pos * B / N;\n    }\n\n    fill(outBlk.begin(), outBlk.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            int bu = w.bin[u], bv = w.bin[v];\n            if (bu > bv) swap(bu, bv);\n            int id = cb.pairId[bu * B + bv];\n            outBlk[id]++;\n        }\n    }\n}\n\nvoid sample_noisy_features(\n    const Graph& g, const Codebook& cb, double eps, uint64_t flipThr,\n    RNG& rng, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2, vector<int>& outBlk\n) {\n    int N = cb.N, L = cb.L, B = cb.B, FB = cb.FB;\n\n    if ((int)outDeg.size() != N) {\n        outDeg.assign(N, 0);\n        outNd.assign(N, 0);\n        outNd2.assign(N, 0);\n    }\n    if ((int)outBlk.size() != FB) outBlk.assign(FB, 0);\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    if (eps <= 0.0) {\n        for (int e = 0; e < L; e++) {\n            uint8_t b = g.bits[e];\n            w.bits[e] = b;\n            if (b) {\n                int u = cb.eu[e], v = cb.ev[e];\n                w.deg[u]++;\n                w.deg[v]++;\n            }\n        }\n    } else {\n        for (int e = 0; e < L; e++) {\n            uint8_t b = g.bits[e];\n            if (rng.next_u64() < flipThr) b ^= 1;\n            w.bits[e] = b;\n            if (b) {\n                int u = cb.eu[e], v = cb.ev[e];\n                w.deg[u]++;\n                w.deg[v]++;\n            }\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    // Random tiebreak keys emulate random vertex shuffling in actual judge\n    for (int i = 0; i < N; i++) {\n        w.ord[i] = i;\n        w.key[i] = rng.next_u64();\n    }\n    sort(w.ord.begin(), w.ord.end(), [&](int a, int b) {\n        if (w.deg[a] != w.deg[b]) return w.deg[a] < w.deg[b];\n        if (w.nd[a] != w.nd[b]) return w.nd[a] < w.nd[b];\n        if (w.nd2[a] != w.nd2[b]) return w.nd2[a] < w.nd2[b];\n        if (w.key[a] != w.key[b]) return w.key[a] < w.key[b];\n        return a < b;\n    });\n\n    for (int pos = 0; pos < N; pos++) {\n        int v = w.ord[pos];\n        outDeg[pos] = w.deg[v];\n        outNd[pos] = w.nd[v];\n        outNd2[pos] = w.nd2[v];\n        w.bin[v] = (long long)pos * B / N;\n    }\n\n    fill(outBlk.begin(), outBlk.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            int bu = w.bin[u], bv = w.bin[v];\n            if (bu > bv) swap(bu, bv);\n            int id = cb.pairId[bu * B + bv];\n            outBlk[id]++;\n        }\n    }\n}\n\nProtoBank calibrate_prototypes(const Codebook& cb, double eps, int S, RNG& rng) {\n    ProtoBank pb;\n    pb.M = (int)cb.graphs.size();\n    pb.N = cb.N;\n    pb.S = (eps <= 0.0 ? 1 : max(1, S));\n    pb.FB = cb.FB;\n\n    size_t sampleN = (size_t)pb.M * pb.S * pb.N;\n    size_t sampleB = (size_t)pb.M * pb.S * pb.FB;\n\n    pb.sdeg.assign(sampleN, 0);\n    pb.snd.assign(sampleN, 0);\n    pb.snd2.assign(sampleN, 0);\n    pb.sblk.assign(sampleB, 0);\n\n    pb.cdeg.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd2.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cblk.assign((size_t)pb.M * pb.FB, 0.0f);\n\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N), ob(cb.FB);\n    vector<double> sumD(cb.N), sumN(cb.N), sumN2(cb.N), sumB(cb.FB);\n\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int k = 0; k < pb.M; k++) {\n        fill(sumD.begin(), sumD.end(), 0.0);\n        fill(sumN.begin(), sumN.end(), 0.0);\n        fill(sumN2.begin(), sumN2.end(), 0.0);\n        fill(sumB.begin(), sumB.end(), 0.0);\n\n        for (int s = 0; s < pb.S; s++) {\n            sample_noisy_features(cb.graphs[k], cb, eps, flipThr, rng, w, od, on, on2, ob);\n\n            size_t baseN = ((size_t)k * pb.S + s) * pb.N;\n            size_t baseB = ((size_t)k * pb.S + s) * pb.FB;\n\n            for (int i = 0; i < pb.N; i++) {\n                pb.sdeg[baseN + i] = (int16_t)od[i];\n                pb.snd[baseN + i] = (int32_t)on[i];\n                pb.snd2[baseN + i] = (int32_t)on2[i];\n                sumD[i] += od[i];\n                sumN[i] += on[i];\n                sumN2[i] += on2[i];\n            }\n            for (int b = 0; b < pb.FB; b++) {\n                pb.sblk[baseB + b] = (uint16_t)ob[b];\n                sumB[b] += ob[b];\n            }\n        }\n\n        for (int i = 0; i < pb.N; i++) {\n            pb.cdeg[(size_t)k * pb.N + i] = (float)(sumD[i] / pb.S);\n            pb.cnd[(size_t)k * pb.N + i] = (float)(sumN[i] / pb.S);\n            pb.cnd2[(size_t)k * pb.N + i] = (float)(sumN2[i] / pb.S);\n        }\n        for (int b = 0; b < pb.FB; b++) {\n            pb.cblk[(size_t)k * pb.FB + b] = (float)(sumB[b] / pb.S);\n        }\n    }\n\n    // Global variances\n    double varD = 0.0, varN1 = 0.0, varN2 = 0.0;\n    vector<double> varB(pb.FB, 0.0);\n\n    for (int k = 0; k < pb.M; k++) {\n        for (int s = 0; s < pb.S; s++) {\n            size_t baseN = ((size_t)k * pb.S + s) * pb.N;\n            size_t baseB = ((size_t)k * pb.S + s) * pb.FB;\n            size_t cN = (size_t)k * pb.N;\n            size_t cB = (size_t)k * pb.FB;\n\n            for (int i = 0; i < pb.N; i++) {\n                double d0 = (double)pb.sdeg[baseN + i] - (double)pb.cdeg[cN + i];\n                double d1 = (double)pb.snd[baseN + i] - (double)pb.cnd[cN + i];\n                double d2 = (double)pb.snd2[baseN + i] - (double)pb.cnd2[cN + i];\n                varD += d0 * d0;\n                varN1 += d1 * d1;\n                varN2 += d2 * d2;\n            }\n            for (int b = 0; b < pb.FB; b++) {\n                double db = (double)pb.sblk[baseB + b] - (double)pb.cblk[cB + b];\n                varB[b] += db * db;\n            }\n        }\n    }\n\n    double cntN = (double)pb.M * pb.S * pb.N;\n    double cntB = (double)pb.M * pb.S;\n    if (cntN <= 0) cntN = 1.0;\n    if (cntB <= 0) cntB = 1.0;\n\n    varD /= cntN;\n    varN1 /= cntN;\n    varN2 /= cntN;\n    for (int b = 0; b < pb.FB; b++) varB[b] /= cntB;\n\n    // Baseline floor (stability)\n    double baseD = max(0.0, (cb.N - 1) * eps * (1.0 - eps));\n    varD = max(varD, 0.5 * baseD);\n\n    pb.invD = 1.0 / (varD + 1.0);\n    pb.invN1 = 1.0 / (varN1 + 1.0);\n    pb.invN2 = 1.0 / (varN2 + 1.0);\n\n    pb.invB.assign(pb.FB, 1.0);\n    for (int b = 0; b < pb.FB; b++) {\n        double baseB = 0.35 * cb.blockCap[b] * eps * (1.0 - eps);\n        double vb = max(varB[b], baseB);\n        pb.invB[b] = 1.0 / (vb + 1.0);\n    }\n\n    return pb;\n}\n\nint decode_with_param(\n    const vector<int>& od, const vector<int>& on, const vector<int>& on2, const vector<int>& ob,\n    const ProtoBank& pb, const DecodeParam& prm\n) {\n    int M = pb.M, N = pb.N, S = pb.S, FB = pb.FB;\n\n    double cD = pb.invD;\n    double cN1 = prm.m1 * pb.invN1;\n    double cN2 = prm.m2 * pb.invN2;\n    double cB = prm.mB;\n\n    int bestK = 0;\n    double bestScore = 1e300;\n\n    for (int k = 0; k < M; k++) {\n        double best1 = 1e300, best2 = 1e300;\n\n        for (int s = 0; s < S; s++) {\n            size_t baseN = ((size_t)k * S + s) * N;\n            size_t baseB = ((size_t)k * S + s) * FB;\n\n            const int16_t* pd = pb.sdeg.data() + baseN;\n            const int32_t* pn = pb.snd.data() + baseN;\n            const int32_t* p2 = pb.snd2.data() + baseN;\n            const uint16_t* pbk = pb.sblk.data() + baseB;\n\n            double dsum = 0.0;\n\n            for (int i = 0; i < N; i++) {\n                double d = (double)od[i] - (double)pd[i];\n                dsum += cD * d * d;\n            }\n            if (cN1 != 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on[i] - (double)pn[i];\n                    dsum += cN1 * d * d;\n                }\n            }\n            if (cN2 != 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on2[i] - (double)p2[i];\n                    dsum += cN2 * d * d;\n                }\n            }\n            if (cB != 0.0) {\n                for (int b = 0; b < FB; b++) {\n                    double d = (double)ob[b] - (double)pbk[b];\n                    dsum += cB * pb.invB[b] * d * d;\n                }\n            }\n\n            if (dsum < best1) {\n                best2 = best1;\n                best1 = dsum;\n            } else if (dsum < best2) {\n                best2 = dsum;\n            }\n        }\n\n        if (!prm.useSecond || best2 > 1e299) best2 = best1;\n\n        // center distance\n        size_t cN = (size_t)k * N;\n        size_t cBidx = (size_t)k * FB;\n        const float* cd = pb.cdeg.data() + cN;\n        const float* cn = pb.cnd.data() + cN;\n        const float* c2 = pb.cnd2.data() + cN;\n        const float* cbk = pb.cblk.data() + cBidx;\n\n        double cdist = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)od[i] - (double)cd[i];\n            cdist += cD * d * d;\n        }\n        if (cN1 != 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on[i] - (double)cn[i];\n                cdist += cN1 * d * d;\n            }\n        }\n        if (cN2 != 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on2[i] - (double)c2[i];\n                cdist += cN2 * d * d;\n            }\n        }\n        if (cB != 0.0) {\n            for (int b = 0; b < FB; b++) {\n                double d = (double)ob[b] - (double)cbk[b];\n                cdist += cB * pb.invB[b] * d * d;\n            }\n        }\n\n        double score = prm.a1 * best1 + prm.a2 * best2 + prm.a3 * cdist;\n        if (score < bestScore) {\n            bestScore = score;\n            bestK = k;\n        }\n    }\n\n    return bestK;\n}\n\ndouble evaluate_codebook(\n    const Codebook& cb, const ProtoBank& pb, const DecodeParam& prm,\n    double eps, int T, RNG& rng\n) {\n    if (cb.distinct < pb.M) return -1e100;\n    if (T <= 0) return -1e100;\n\n    int err = 0;\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N), ob(cb.FB);\n\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int t = 0; t < T; t++) {\n        int s = rng.next_int(0, pb.M - 1);\n        sample_noisy_features(cb.graphs[s], cb, eps, flipThr, rng, w, od, on, on2, ob);\n        int p = decode_with_param(od, on, on2, ob, pb, prm);\n        if (p != s) err++;\n    }\n\n    double q = (double)err / (double)T;\n    double st = sqrt(max(1e-12, q * (1.0 - q) / T));\n    double qu = min(1.0, q + 1.1 * st + 0.5 / T); // conservative\n    double survive = max(0.0, 1.0 - 0.1 * qu);\n    return pow(survive, 100.0) / (double)cb.N;\n}\n\nvector<int> choose_candidate_Ns(int M, double eps) {\n    // unlabeled graph counts A000088 (0..10)\n    static const vector<long long> unl = {\n        0LL, 1LL, 1LL, 2LL, 4LL, 11LL, 34LL, 156LL, 1044LL, 12346LL, 274668LL\n    };\n\n    int nlb = 4;\n    while (nlb + 1 < (int)unl.size() && unl[nlb] < M) nlb++;\n\n    vector<int> Ns;\n    auto add = [&](int n) {\n        n = max(4, min(100, n));\n        if (find(Ns.begin(), Ns.end(), n) == Ns.end()) Ns.push_back(n);\n    };\n\n    add(nlb);\n\n    if (eps < 0.04) {\n        add(nlb + 1); add(8); add(10); add(14); add(20); add(28);\n    } else if (eps < 0.10) {\n        add(max(nlb, 8)); add(12); add(18); add(26); add(36); add(48); add(62);\n    } else if (eps < 0.18) {\n        add(max(nlb, 9)); add(16); add(24); add(34); add(46); add(62); add(80);\n    } else if (eps < 0.26) {\n        int base = (int)llround(18.0 + 0.45 * M);\n        add(max(nlb, 12)); add(base - 10); add(base); add(base + 12); add(78); add(92); add(100);\n    } else if (eps < 0.33) {\n        int base = (int)llround(24.0 + 0.55 * M);\n        add(max(nlb, 16)); add(base - 10); add(base); add(base + 10); add(88); add(100);\n    } else {\n        int base = (int)llround(30.0 + 0.60 * M);\n        add(max(nlb, 20)); add(base - 8); add(base); add(base + 8); add(96); add(100);\n    }\n\n    sort(Ns.begin(), Ns.end());\n    Ns.erase(unique(Ns.begin(), Ns.end()), Ns.end());\n    return Ns;\n}\n\nDecodeParam degree_only_param() {\n    DecodeParam p;\n    p.m1 = 0.0; p.m2 = 0.0; p.mB = 0.0;\n    p.a1 = 1.0; p.a2 = 0.0; p.a3 = 0.0;\n    p.useSecond = false;\n    p.name = \"deg_only\";\n    return p;\n}\n\nDecodeParam block_heavy_param() {\n    DecodeParam p;\n    p.m1 = 0.2; p.m2 = 0.0; p.mB = 1.2;\n    p.a1 = 0.60; p.a2 = 0.20; p.a3 = 0.20;\n    p.useSecond = true;\n    p.name = \"block_heavy\";\n    return p;\n}\n\nDecodeParam default_param(double eps) {\n    DecodeParam p;\n    if (eps < 0.08) {\n        p.m1 = 1.0; p.m2 = 0.7; p.mB = 0.1;\n        p.a1 = 0.70; p.a2 = 0.10; p.a3 = 0.20;\n    } else if (eps < 0.20) {\n        p.m1 = 1.0; p.m2 = 0.4; p.mB = 0.5;\n        p.a1 = 0.65; p.a2 = 0.15; p.a3 = 0.20;\n    } else if (eps < 0.30) {\n        p.m1 = 0.8; p.m2 = 0.15; p.mB = 0.9;\n        p.a1 = 0.60; p.a2 = 0.20; p.a3 = 0.20;\n    } else {\n        p.m1 = 0.6; p.m2 = 0.0; p.mB = 1.1;\n        p.a1 = 0.55; p.a2 = 0.25; p.a3 = 0.20;\n    }\n    p.useSecond = true;\n    p.name = \"default\";\n    return p;\n}\n\nvector<DecodeParam> make_param_candidates(double eps, const DecodeParam& defp) {\n    vector<DecodeParam> v;\n    v.push_back(defp);\n    v.push_back(degree_only_param());\n\n    auto push = [&](double m1, double m2, double mB, double a1, double a2, double a3, bool s, string nm) {\n        DecodeParam p;\n        p.m1 = m1; p.m2 = m2; p.mB = mB;\n        p.a1 = a1; p.a2 = a2; p.a3 = a3;\n        p.useSecond = s;\n        p.name = nm;\n        v.push_back(p);\n    };\n\n    if (eps < 0.10) {\n        push(1.0, 0.4, 0.0, 0.75, 0.05, 0.20, true, \"low1\");\n        push(1.0, 0.8, 0.1, 0.65, 0.15, 0.20, true, \"low2\");\n        push(1.0, 0.0, 0.2, 0.70, 0.10, 0.20, true, \"low3\");\n    } else if (eps < 0.25) {\n        push(1.0, 0.3, 0.7, 0.62, 0.18, 0.20, true, \"mid1\");\n        push(0.8, 0.0, 0.9, 0.64, 0.16, 0.20, true, \"mid2\");\n        push(1.0, 0.0, 0.4, 0.72, 0.08, 0.20, true, \"mid3\");\n        push(0.8, 0.2, 0.2, 0.70, 0.10, 0.20, true, \"mid4\");\n    } else {\n        push(0.0, 0.0, 1.2, 0.65, 0.15, 0.20, true, \"high1\");\n        push(0.4, 0.0, 1.0, 0.60, 0.20, 0.20, true, \"high2\");\n        push(0.8, 0.0, 0.5, 0.65, 0.15, 0.20, true, \"high3\");\n        push(0.6, 0.0, 0.0, 0.80, 0.00, 0.20, false, \"high4\");\n        v.push_back(block_heavy_param());\n    }\n\n    return v;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - t0).count();\n    };\n\n    uint64_t epsInt = (uint64_t)llround(eps * 100.0);\n    uint64_t baseSeed = 0x1234abcddcba4321ULL ^ (uint64_t)M * 10007ULL ^ epsInt * 1000003ULL;\n\n    vector<int> Ns = choose_candidate_Ns(M, eps);\n    if (eps > 0.22) reverse(Ns.begin(), Ns.end());\n\n    DecodeParam pDef = default_param(eps);\n    DecodeParam pDeg = degree_only_param();\n    DecodeParam pBlk = block_heavy_param();\n\n    double bestEst = -1e100;\n    Codebook bestCb;\n    DecodeParam bestInitParam = pDef;\n    bool haveBest = false;\n\n    long long searchDeadline = 2900;\n\n    for (int ni = 0; ni < (int)Ns.size(); ni++) {\n        int N = Ns[ni];\n        int tries = (eps < 0.10 ? 1 : (eps < 0.25 ? 2 : 3));\n\n        for (int att = 0; att < tries; att++) {\n            if (elapsed_ms() > searchDeadline) break;\n\n            int C = max(500, M * 10);\n            if (eps > 0.20) C += M * 4;\n            if (N <= 12) C += 300;\n            C += att * 80;\n            C = min(C, 1800);\n\n            RNG rngBuild(baseSeed + 1000003ULL * (uint64_t)N + 1009ULL * (uint64_t)att + 97ULL * (uint64_t)ni + 11ULL);\n            Codebook cb = build_codebook(N, M, eps, C, rngBuild);\n            if (cb.distinct < M) continue;\n\n            int Se = (eps < 0.08 ? 3 : (eps < 0.20 ? 4 : 5));\n            if (M > 80) Se++;\n            if (eps > 0.30) Se++;\n            if (elapsed_ms() > 2200) Se = max(3, Se - 1);\n\n            RNG rngCal(baseSeed + 2000003ULL * (uint64_t)N + 1237ULL * (uint64_t)att + 17ULL);\n            ProtoBank pb = calibrate_prototypes(cb, eps, Se, rngCal);\n\n            int T = (eps < 0.08 ? 140 : (eps < 0.20 ? 180 : 220));\n            if (M > 80) T += 40;\n            T = max(100, T - att * 20);\n            if (elapsed_ms() > 2400) T = max(90, T - 50);\n\n            uint64_t evalSeed = baseSeed + 3000017ULL * (uint64_t)N + 2713ULL * (uint64_t)att + 233ULL * (uint64_t)ni;\n\n            RNG reA(evalSeed);\n            double est = evaluate_codebook(cb, pb, pDef, eps, T, reA);\n            DecodeParam selParam = pDef;\n\n            if (eps >= 0.14 && elapsed_ms() < searchDeadline - 250) {\n                RNG reB(evalSeed);\n                double estB = evaluate_codebook(cb, pb, pDeg, eps, max(60, T / 2), reB);\n                if (estB > est) {\n                    est = estB;\n                    selParam = pDeg;\n                }\n            }\n            if (eps >= 0.22 && elapsed_ms() < searchDeadline - 250) {\n                RNG reC(evalSeed);\n                double estC = evaluate_codebook(cb, pb, pBlk, eps, max(60, T / 2), reC);\n                if (estC > est) {\n                    est = estC;\n                    selParam = pBlk;\n                }\n            }\n\n            if (est > bestEst) {\n                bestEst = est;\n                bestCb = std::move(cb);\n                bestInitParam = selParam;\n                haveBest = true;\n            }\n        }\n        if (elapsed_ms() > searchDeadline) break;\n    }\n\n    if (!haveBest || bestCb.graphs.empty() || bestCb.distinct < M) {\n        vector<int> fallbackNs = {100, 90, 80, 70, 60, 50, 40, 30, 20, 12, 8};\n        for (int n : fallbackNs) {\n            RNG rb(baseSeed + 777ULL * (uint64_t)n + 99991ULL);\n            Codebook cb = build_codebook(n, M, eps, max(900, M * 14), rb);\n            if (bestCb.graphs.empty()) bestCb = cb;\n            if (cb.distinct >= M) {\n                bestCb = std::move(cb);\n                break;\n            }\n        }\n        bestInitParam = pDef;\n    }\n\n    int Sf;\n    if (eps < 0.05) Sf = 8;\n    else if (eps < 0.15) Sf = 12;\n    else if (eps < 0.25) Sf = 16;\n    else if (eps < 0.35) Sf = 20;\n    else Sf = 24;\n    if (M > 80) Sf += 2;\n    if (elapsed_ms() > 3200) Sf = max(8, Sf - 4);\n    if (elapsed_ms() > 3900) Sf = max(6, Sf / 2);\n\n    RNG rngFinal(baseSeed ^ 0x9e3779b97f4a7c15ULL);\n    ProtoBank pbFinal = calibrate_prototypes(bestCb, eps, Sf, rngFinal);\n\n    DecodeParam bestParam = bestInitParam;\n\n    // Lightweight parameter tuning\n    if (elapsed_ms() < 3600) {\n        auto pcands = make_param_candidates(eps, bestParam);\n        int Tt = (eps < 0.15 ? 50 : 70);\n        if (M > 80) Tt += 20;\n        if (elapsed_ms() > 3300) Tt = max(40, Tt - 20);\n\n        double bestPEst = -1e100;\n        for (int i = 0; i < (int)pcands.size(); i++) {\n            if (elapsed_ms() > 4400) break;\n            RNG rt(baseSeed + 5555555ULL); // same seed for fair comparison\n            double est = evaluate_codebook(bestCb, pbFinal, pcands[i], eps, Tt, rt);\n            if (est > bestPEst) {\n                bestPEst = est;\n                bestParam = pcands[i];\n            }\n        }\n    }\n\n    // Output codebook\n    cout << bestCb.N << '\\n';\n    for (int k = 0; k < M; k++) {\n        string s(bestCb.L, '0');\n        const auto& bits = bestCb.graphs[k].bits;\n        for (int e = 0; e < bestCb.L; e++) {\n            if (bits[e]) s[e] = '1';\n        }\n        cout << s << '\\n';\n    }\n    cout.flush();\n\n    bool useExact = (eps <= 0.0);\n    unordered_map<uint64_t, int> exactMap;\n    if (useExact) {\n        exactMap.reserve((size_t)M * 2);\n        for (int k = 0; k < M; k++) {\n            uint64_t h = hash_sorted3(\n                bestCb.graphs[k].deg_sorted,\n                bestCb.graphs[k].nd_sorted,\n                bestCb.graphs[k].nd2_sorted\n            );\n            if (!exactMap.count(h)) exactMap[h] = k;\n        }\n    }\n\n    FeatureWork qwork(bestCb.N, bestCb.L);\n    vector<int> od(bestCb.N), on(bestCb.N), on2(bestCb.N), ob(bestCb.FB);\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) return 0;\n\n        extract_features_from_string(H, bestCb, qwork, od, on, on2, ob);\n\n        int ans = 0;\n        if (useExact) {\n            uint64_t h = hash_sorted3(od, on, on2);\n            auto it = exactMap.find(h);\n            if (it != exactMap.end()) ans = it->second;\n            else ans = decode_with_param(od, on, on2, ob, pbFinal, bestParam);\n        } else {\n            ans = decode_with_param(od, on, on2, ob, pbFinal, bestParam);\n        }\n\n        if (ans < 0) ans = 0;\n        if (ans >= M) ans = M - 1;\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;\nstatic constexpr int UNREACH = 1'000'000'000;\nstatic constexpr ll DISCONNECT_UNIT = 100'000'000LL;\n\nstruct Edge {\n    int u, v, w;\n    int cell = 0;\n    double imp = 0.0;\n};\n\nint N, M, D, K;\nint GRID = 10;\n\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj; // (to, edge id)\nvector<int> X, Y, degv;\n\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\nvector<int> samples;\nint S = 0;\nvector<vector<int>> baseDist;\nvector<int> tmpDist;\n\n// current solution state\nvector<int> dayOf;               // edge -> day [0..D-1]\nvector<int> cntDay;              // day -> count\nvector<vector<int>> incCnt;      // vertex, day -> #incident edges repaired that day\nvector<vector<int>> dayEdges;    // day -> edge list\nvector<int> posInDay;            // edge -> position in dayEdges[dayOf[edge]]\nvector<ll> dayScore;             // approximate score per day\n\nvector<int> seen;\nint seenToken = 1;\n\ninline int rnd_int(int n) {\n    return (int)(rng() % (uint32_t)n);\n}\ninline double rnd01() {\n    return (rng() + 0.5) * (1.0 / 4294967296.0);\n}\n\nvoid dijkstra_full_parent(int src, vector<int>& dist, vector<int>& parent) {\n    fill(dist.begin(), dist.end(), UNREACH);\n    fill(parent.begin(), parent.end(), -1);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                parent[to] = eid;\n                pq.push({nd, to});\n            } else if (nd == dist[to] && parent[to] != -1) {\n                // deterministic tie-break\n                if (eid < parent[to]) parent[to] = eid;\n            }\n        }\n    }\n}\n\nvoid dijkstra_ban_day(int src, int banDay, vector<int>& dist) {\n    fill(dist.begin(), dist.end(), UNREACH);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            if (dayOf[eid] == banDay) continue;\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                pq.push({nd, to});\n            }\n        }\n    }\n}\n\n// ordered pairs across different connected components after removing banDay edges.\n// 0 means connected.\nll disconnected_cross_pairs(int banDay) {\n    static vector<int> q;\n    if ((int)q.size() < N) q.resize(N);\n\n    ll sameOrdered = 0;\n    for (int st = 0; st < N; st++) {\n        if (seen[st] == seenToken) continue;\n        int head = 0, tail = 0;\n        q[tail++] = st;\n        seen[st] = seenToken;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (auto [to, eid] : adj[v]) {\n                if (dayOf[eid] == banDay) continue;\n                if (seen[to] == seenToken) continue;\n                seen[to] = seenToken;\n                q[tail++] = to;\n            }\n        }\n        sameOrdered += 1LL * sz * (sz - 1);\n    }\n\n    seenToken++;\n    if (seenToken == INT_MAX) {\n        fill(seen.begin(), seen.end(), 0);\n        seenToken = 1;\n    }\n\n    ll totalOrdered = 1LL * N * (N - 1);\n    return totalOrdered - sameOrdered;\n}\n\nll compute_day_score(int day) {\n    // Strong connectivity penalty to avoid hidden catastrophic solutions.\n    ll crossPairs = disconnected_cross_pairs(day);\n    if (crossPairs > 0) {\n        return crossPairs * DISCONNECT_UNIT;\n    }\n\n    ll sum = 0;\n    for (int si = 0; si < S; si++) {\n        dijkstra_ban_day(samples[si], day, tmpDist);\n        const auto& b = baseDist[si];\n        for (int v = 0; v < N; v++) {\n            sum += (ll)tmpDist[v] - b[v];\n        }\n    }\n    return sum;\n}\n\nll evaluate_total(vector<ll>& outDayScore) {\n    outDayScore.assign(D, 0);\n    ll tot = 0;\n    for (int d = 0; d < D; d++) {\n        outDayScore[d] = compute_day_score(d);\n        tot += outDayScore[d];\n    }\n    return tot;\n}\n\nvector<int> select_samples(int cnt) {\n    cnt = min(cnt, N);\n    vector<int> res;\n    vector<double> minD2(N, 1e100);\n    vector<char> used(N, false);\n\n    int first = 0;\n    for (int i = 1; i < N; i++) {\n        if (degv[i] > degv[first]) first = i;\n    }\n\n    for (int it = 0; it < cnt; it++) {\n        int cur = -1;\n        if (it == 0) {\n            cur = first;\n        } else {\n            double best = -1.0;\n            for (int v = 0; v < N; v++) {\n                if (used[v]) continue;\n                if (minD2[v] > best) {\n                    best = minD2[v];\n                    cur = v;\n                }\n            }\n        }\n        used[cur] = true;\n        res.push_back(cur);\n\n        for (int v = 0; v < N; v++) {\n            if (used[v]) continue;\n            double dx = (double)X[v] - X[cur];\n            double dy = (double)Y[v] - Y[cur];\n            double d2 = dx * dx + dy * dy;\n            if (d2 < minD2[v]) minD2[v] = d2;\n        }\n    }\n\n    return res;\n}\n\nvector<int> build_initial_schedule(double alpha, double beta, double gamma) {\n    vector<int> assign(M, -1);\n    vector<int> cnt(D, 0);\n    vector<vector<int>> inc(N, vector<int>(D, 0));\n    int C = GRID * GRID;\n    vector<vector<int>> cellCnt(C, vector<int>(D, 0));\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n\n    vector<double> key(M);\n    for (int e = 0; e < M; e++) {\n        key[e] = edges[e].imp + (double)(rng() & 2047) * 1e-6;\n    }\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (key[a] != key[b]) return key[a] > key[b];\n        return a < b;\n    });\n\n    double maxImp = 1e-9;\n    for (int e = 0; e < M; e++) maxImp = max(maxImp, edges[e].imp);\n\n    for (int eid : order) {\n        const Edge& E = edges[eid];\n        int u = E.u, v = E.v, c = E.cell;\n        double impf = 1.0 + E.imp / maxImp;\n\n        int bestDay = -1;\n        double bestP = 1e100;\n\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] >= K) continue;\n            if (inc[u][d] >= degv[u] - 1) continue;\n            if (inc[v][d] >= degv[v] - 1) continue;\n\n            double p = alpha * cnt[d]\n                     + beta * impf * (inc[u][d] + inc[v][d])\n                     + gamma * cellCnt[c][d];\n            if (p < bestP) {\n                bestP = p;\n                bestDay = d;\n            }\n        }\n\n        // If hard constraints block all days, relax slightly with heavy penalty.\n        if (bestDay == -1) {\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] >= K) continue;\n                double viol = 0.0;\n                if (inc[u][d] >= degv[u] - 1) viol += 1000.0;\n                if (inc[v][d] >= degv[v] - 1) viol += 1000.0;\n                double p = alpha * cnt[d]\n                         + beta * impf * (inc[u][d] + inc[v][d])\n                         + gamma * cellCnt[c][d]\n                         + viol;\n                if (p < bestP) {\n                    bestP = p;\n                    bestDay = d;\n                }\n            }\n        }\n\n        if (bestDay == -1) {\n            // very defensive fallback\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] < K) {\n                    bestDay = d;\n                    break;\n                }\n            }\n            if (bestDay == -1) bestDay = 0;\n        }\n\n        assign[eid] = bestDay;\n        cnt[bestDay]++;\n        inc[u][bestDay]++;\n        inc[v][bestDay]++;\n        cellCnt[c][bestDay]++;\n    }\n\n    return assign;\n}\n\nvoid build_state_from_assignment() {\n    cntDay.assign(D, 0);\n    incCnt.assign(N, vector<int>(D, 0));\n    dayEdges.assign(D, vector<int>());\n    posInDay.assign(M, -1);\n\n    for (int e = 0; e < M; e++) {\n        int d = dayOf[e];\n        cntDay[d]++;\n        int u = edges[e].u, v = edges[e].v;\n        incCnt[u][d]++;\n        incCnt[v][d]++;\n        posInDay[e] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(e);\n    }\n}\n\ninline void day_remove_edge(int e, int d) {\n    int p = posInDay[e];\n    int last = dayEdges[d].back();\n    dayEdges[d][p] = last;\n    posInDay[last] = p;\n    dayEdges[d].pop_back();\n}\n\ninline void day_add_edge(int e, int d) {\n    posInDay[e] = (int)dayEdges[d].size();\n    dayEdges[d].push_back(e);\n}\n\nvoid apply_move(int e, int from, int to) {\n    day_remove_edge(e, from);\n    day_add_edge(e, to);\n\n    dayOf[e] = to;\n    cntDay[from]--;\n    cntDay[to]++;\n\n    int u = edges[e].u, v = edges[e].v;\n    incCnt[u][from]--;\n    incCnt[v][from]--;\n    incCnt[u][to]++;\n    incCnt[v][to]++;\n}\n\nvoid apply_swap(int e, int f, int d1, int d2) {\n    // e: d1 -> d2, f: d2 -> d1\n    int pe = posInDay[e];\n    int pf = posInDay[f];\n\n    dayEdges[d1][pe] = f;\n    posInDay[f] = pe;\n    dayEdges[d2][pf] = e;\n    posInDay[e] = pf;\n\n    dayOf[e] = d2;\n    dayOf[f] = d1;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    incCnt[eu][d1]--;\n    incCnt[ev][d1]--;\n    incCnt[eu][d2]++;\n    incCnt[ev][d2]++;\n\n    incCnt[fu][d2]--;\n    incCnt[fv][d2]--;\n    incCnt[fu][d1]++;\n    incCnt[fv][d1]++;\n}\n\nbool can_move_edge(int e, int to) {\n    int from = dayOf[e];\n    if (from == to) return false;\n    if (cntDay[to] >= K) return false;\n    int u = edges[e].u, v = edges[e].v;\n    if (incCnt[u][to] + 1 > degv[u] - 1) return false;\n    if (incCnt[v][to] + 1 > degv[v] - 1) return false;\n    return true;\n}\n\nbool can_swap_edges(int e, int f) {\n    int d1 = dayOf[e];\n    int d2 = dayOf[f];\n    if (d1 == d2) return false;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    int vv[4] = {eu, ev, fu, fv};\n    sort(vv, vv + 4);\n    int m = (int)(unique(vv, vv + 4) - vv);\n\n    for (int i = 0; i < m; i++) {\n        int x = vv[i];\n        int nd1 = incCnt[x][d1] - (eu == x) - (ev == x) + (fu == x) + (fv == x);\n        int nd2 = incCnt[x][d2] - (fu == x) - (fv == x) + (eu == x) + (ev == x);\n        if (nd1 > degv[x] - 1) return false;\n        if (nd2 > degv[x] - 1) return false;\n    }\n    return true;\n}\n\nint day_with_max_score() {\n    int id = 0;\n    for (int d = 1; d < D; d++) {\n        if (dayScore[d] > dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_move(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (cntDay[d] >= K) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_swap(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (dayEdges[d].empty()) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    adj.assign(N, {});\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        adj[u].push_back({v, i});\n        adj[v].push_back({u, i});\n    }\n\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n    }\n\n    degv.assign(N, 0);\n    for (int v = 0; v < N; v++) degv[v] = (int)adj[v].size();\n\n    // edge cell id\n    for (int e = 0; e < M; e++) {\n        int mx = X[edges[e].u] + X[edges[e].v]; // [0,2000]\n        int my = Y[edges[e].u] + Y[edges[e].v];\n        int gx = min(GRID - 1, mx * GRID / 2001);\n        int gy = min(GRID - 1, my * GRID / 2001);\n        edges[e].cell = gx * GRID + gy;\n    }\n\n    int sampleTarget = 14;\n    if (N > 850 || M > 2500) sampleTarget = 12;\n    S = min(N, sampleTarget);\n\n    samples = select_samples(S);\n\n    baseDist.assign(S, vector<int>(N, UNREACH));\n    vector<double> imp(M, 0.0);\n\n    vector<int> dist(N), parent(N);\n    for (int si = 0; si < S; si++) {\n        int src = samples[si];\n        dijkstra_full_parent(src, dist, parent);\n        baseDist[si] = dist;\n        for (int v = 0; v < N; v++) {\n            if (v == src) continue;\n            int pe = parent[v];\n            if (pe >= 0) imp[pe] += 1.0;\n        }\n    }\n\n    for (int e = 0; e < M; e++) {\n        imp[e] += 1000.0 / edges[e].w;\n        imp[e] += 0.1 * (1.0 / degv[edges[e].u] + 1.0 / degv[edges[e].v]);\n        edges[e].imp = imp[e];\n    }\n\n    dayOf.assign(M, 0);\n    tmpDist.assign(N, UNREACH);\n    seen.assign(N, 0);\n    seenToken = 1;\n\n    vector<array<double,3>> params = {\n        {1.0, 4.0, 1.8},\n        {0.8, 5.0, 0.7},\n        {1.2, 3.2, 2.6}\n    };\n\n    vector<int> bestAssignInit;\n    vector<ll> bestDayScoreInit;\n    ll bestTotInit = (1LL << 62);\n\n    for (auto p : params) {\n        auto initAssign = build_initial_schedule(p[0], p[1], p[2]);\n        dayOf = initAssign;\n        vector<ll> ds;\n        ll tot = evaluate_total(ds);\n        if (tot < bestTotInit) {\n            bestTotInit = tot;\n            bestAssignInit = move(initAssign);\n            bestDayScoreInit = move(ds);\n        }\n    }\n\n    dayOf = bestAssignInit;\n    dayScore = bestDayScoreInit;\n    ll currentTotal = bestTotInit;\n\n    build_state_from_assignment();\n\n    vector<int> bestAssign = dayOf;\n    ll bestTotal = currentTotal;\n\n    const double TIME_LIMIT = 5.60;\n    const double T0 = 5e6;\n    const double T1 = 1e3;\n    const double logT0 = log(T0);\n    const double logT1 = log(T1);\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= TIME_LIMIT) break;\n        }\n        iter++;\n\n        bool generated = false;\n        bool isMove = false;\n        int e = -1, f = -1, toDay = -1;\n\n        for (int tr = 0; tr < 25 && !generated; tr++) {\n            int mode = rnd_int(100);\n\n            if (mode < 35) {\n                // targeted move: bad day -> good day\n                int d1 = day_with_max_score();\n                if (dayEdges[d1].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                int d2 = day_with_min_score_move(d1);\n                if (d2 < 0) continue;\n                if (!can_move_edge(e, d2)) continue;\n                isMove = true;\n                toDay = d2;\n                generated = true;\n\n            } else if (mode < 65) {\n                // targeted swap: bad day <-> good day\n                int d1 = day_with_max_score();\n                int d2 = day_with_min_score_swap(d1);\n                if (d2 < 0) continue;\n                if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                f = dayEdges[d2][rnd_int((int)dayEdges[d2].size())];\n                if (!can_swap_edges(e, f)) continue;\n                isMove = false;\n                generated = true;\n\n            } else {\n                // random\n                e = rnd_int(M);\n                if (rnd_int(2) == 0) {\n                    int d2 = rnd_int(D);\n                    if (!can_move_edge(e, d2)) continue;\n                    isMove = true;\n                    toDay = d2;\n                    generated = true;\n                } else {\n                    f = rnd_int(M);\n                    if (e == f) continue;\n                    if (!can_swap_edges(e, f)) continue;\n                    isMove = false;\n                    generated = true;\n                }\n            }\n        }\n\n        if (!generated) continue;\n\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        double temp = exp(logT0 + (logT1 - logT0) * progress);\n\n        if (isMove) {\n            int from = dayOf[e];\n            int to = toDay;\n\n            ll oldA = dayScore[from];\n            ll oldB = dayScore[to];\n\n            apply_move(e, from, to);\n\n            ll newA = compute_day_score(from);\n            ll newB = compute_day_score(to);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[from] = newA;\n                dayScore[to] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_move(e, to, from); // revert\n            }\n\n        } else {\n            int d1 = dayOf[e];\n            int d2 = dayOf[f];\n\n            ll oldA = dayScore[d1];\n            ll oldB = dayScore[d2];\n\n            apply_swap(e, f, d1, d2);\n\n            ll newA = compute_day_score(d1);\n            ll newB = compute_day_score(d2);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[d1] = newA;\n                dayScore[d2] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_swap(e, f, d2, d1); // revert\n            }\n        }\n    }\n\n    dayOf = bestAssign;\n\n    // defensive validity check\n    bool ok = true;\n    vector<int> checkCnt(D, 0);\n    for (int e = 0; e < M; e++) {\n        if (dayOf[e] < 0 || dayOf[e] >= D) ok = false;\n        else checkCnt[dayOf[e]]++;\n    }\n    for (int d = 0; d < D; d++) if (checkCnt[d] > K) ok = false;\n\n    if (!ok) {\n        // guaranteed feasible fallback\n        for (int e = 0; e < M; e++) dayOf[e] = e % D;\n    }\n\n    for (int e = 0; e < M; e++) {\n        if (e) cout << ' ';\n        cout << (dayOf[e] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seg { int s, stride; };\nstruct LayerData {\n    vector<int> X, Y;\n    vector<int> allowed; // x*D+y\n    int base = 0;\n    int cap = 0;\n};\nstruct Occupancy {\n    vector<char> occ;\n    int vol = 0;\n    int zadj = 0;\n    int adj6 = 0;\n};\nstruct Solution {\n    long double score = 1e100L;\n    int n = 0;\n    vector<int> b1, b2;\n};\n\nstruct Pt { int x, y, z; };\nstruct Rot { int p[3], s[3]; };\n\nstruct ShapeGroup {\n    int k = 0;\n    bool isLine = false;\n    vector<array<int, 8>> plc; // first k entries used\n};\n\nint D, N;\nint SX, SY, SZ;\n\narray<vector<string>, 2> F, Rv;\narray<vector<LayerData>, 2> LAY;\narray<int, 2> VminObj, VmaxObj;\n\nvector<Rot> ROTS;\nvector<vector<Seg>> allSegs; // allSegs[L], L>=3\n\nShapeGroup cubeGroup;\nvector<ShapeGroup> groups3, groups4;\n\nvector<vector<int>> neighbors;\nvector<int> parityCell;\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline int clampi(int v, int lo, int hi) {\n    return (v < lo ? lo : (v > hi ? hi : v));\n}\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++) if (p[i] > p[j]) inv++;\n    return (inv % 2 == 0 ? 1 : -1);\n}\n\nvoid build_rotations() {\n    ROTS.clear();\n    vector<array<int,3>> perms = {\n        array<int,3>{0,1,2}, array<int,3>{0,2,1},\n        array<int,3>{1,0,2}, array<int,3>{1,2,0},\n        array<int,3>{2,0,1}, array<int,3>{2,1,0}\n    };\n    for (auto perm : perms) {\n        int pp = perm_parity(perm);\n        for (int sx : {-1, 1}) for (int sy : {-1, 1}) for (int sz : {-1, 1}) {\n            int det = pp * sx * sy * sz;\n            if (det != 1) continue;\n            Rot r;\n            r.p[0] = perm[0]; r.p[1] = perm[1]; r.p[2] = perm[2];\n            r.s[0] = sx;      r.s[1] = sy;      r.s[2] = sz;\n            ROTS.push_back(r);\n        }\n    }\n}\n\nPt rotate_pt(const Pt& a, const Rot& r) {\n    int v[3] = {a.x, a.y, a.z};\n    return Pt{r.s[0] * v[r.p[0]], r.s[1] * v[r.p[1]], r.s[2] * v[r.p[2]]};\n}\n\nvector<Pt> normalize_pts(vector<Pt> v) {\n    int mnx = 1e9, mny = 1e9, mnz = 1e9;\n    for (auto& p : v) {\n        mnx = min(mnx, p.x);\n        mny = min(mny, p.y);\n        mnz = min(mnz, p.z);\n    }\n    for (auto& p : v) {\n        p.x -= mnx;\n        p.y -= mny;\n        p.z -= mnz;\n    }\n    sort(v.begin(), v.end(), [](const Pt& a, const Pt& b) {\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    return v;\n}\n\nstring encode_pts(const vector<Pt>& v) {\n    string s;\n    s.reserve(v.size() * 12);\n    for (auto& p : v) {\n        s += to_string(p.x); s.push_back(',');\n        s += to_string(p.y); s.push_back(',');\n        s += to_string(p.z); s.push_back(';');\n    }\n    return s;\n}\n\npair<string, vector<Pt>> canonical_repr(const vector<Pt>& cells) {\n    string bestKey;\n    vector<Pt> best;\n    bool first = true;\n\n    for (auto& r : ROTS) {\n        vector<Pt> t;\n        t.reserve(cells.size());\n        for (auto& p : cells) t.push_back(rotate_pt(p, r));\n        t = normalize_pts(move(t));\n        string key = encode_pts(t);\n        if (first || key < bestKey) {\n            first = false;\n            bestKey = move(key);\n            best = move(t);\n        }\n    }\n    return {bestKey, best};\n}\n\nvector<vector<Pt>> enumerate_free_shapes(int K) {\n    static const int dx[6] = {1, -1, 0, 0, 0, 0};\n    static const int dy[6] = {0, 0, 1, -1, 0, 0};\n    static const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    vector<vector<vector<Pt>>> by(K + 1);\n    by[1].push_back(vector<Pt>{{0, 0, 0}});\n\n    for (int s = 1; s < K; s++) {\n        unordered_map<string, vector<Pt>> mp;\n        mp.reserve(1024);\n\n        for (const auto& sh : by[s]) {\n            unordered_set<long long> have;\n            have.reserve(sh.size() * 4 + 16);\n\n            for (auto& p : sh) {\n                long long code = ((long long)(p.x + 32) << 40)\n                               + ((long long)(p.y + 32) << 20)\n                               + (long long)(p.z + 32);\n                have.insert(code);\n            }\n\n            set<tuple<int,int,int>> cand;\n            for (auto& p : sh) {\n                for (int d = 0; d < 6; d++) {\n                    int nx = p.x + dx[d], ny = p.y + dy[d], nz = p.z + dz[d];\n                    long long code = ((long long)(nx + 32) << 40)\n                                   + ((long long)(ny + 32) << 20)\n                                   + (long long)(nz + 32);\n                    if (!have.count(code)) cand.emplace(nx, ny, nz);\n                }\n            }\n\n            for (auto [nx, ny, nz] : cand) {\n                vector<Pt> ns = sh;\n                ns.push_back({nx, ny, nz});\n                auto [key, canon] = canonical_repr(ns);\n                if (mp.find(key) == mp.end()) {\n                    mp.emplace(key, move(canon));\n                }\n            }\n        }\n\n        by[s + 1].reserve(mp.size());\n        for (auto& kv : mp) by[s + 1].push_back(move(kv.second));\n    }\n\n    return by[K];\n}\n\nbool consecutive_unique(vector<int> v) {\n    sort(v.begin(), v.end());\n    for (int i = 1; i < (int)v.size(); i++) if (v[i] == v[i - 1]) return false;\n    return v.back() - v.front() + 1 == (int)v.size();\n}\n\nbool is_line_shape(const vector<Pt>& sh) {\n    int k = (int)sh.size();\n    if (k <= 1) return true;\n\n    bool lineX = true, lineY = true, lineZ = true;\n    for (auto& p : sh) {\n        if (p.y != sh[0].y || p.z != sh[0].z) lineX = false;\n        if (p.x != sh[0].x || p.z != sh[0].z) lineY = false;\n        if (p.x != sh[0].x || p.y != sh[0].y) lineZ = false;\n    }\n\n    if (lineX) {\n        vector<int> xs; xs.reserve(k);\n        for (auto& p : sh) xs.push_back(p.x);\n        if (consecutive_unique(xs)) return true;\n    }\n    if (lineY) {\n        vector<int> ys; ys.reserve(k);\n        for (auto& p : sh) ys.push_back(p.y);\n        if (consecutive_unique(ys)) return true;\n    }\n    if (lineZ) {\n        vector<int> zs; zs.reserve(k);\n        for (auto& p : sh) zs.push_back(p.z);\n        if (consecutive_unique(zs)) return true;\n    }\n    return false;\n}\n\nvector<ShapeGroup> build_groups_from_shapes(const vector<vector<Pt>>& shapes, int k) {\n    vector<ShapeGroup> gs;\n\n    for (auto& sh : shapes) {\n        unordered_map<string, vector<Pt>> oriMap;\n        oriMap.reserve(64);\n\n        for (auto& r : ROTS) {\n            vector<Pt> t;\n            t.reserve(k);\n            for (auto& p : sh) t.push_back(rotate_pt(p, r));\n            t = normalize_pts(move(t));\n            string key = encode_pts(t);\n            if (oriMap.find(key) == oriMap.end()) {\n                oriMap.emplace(key, move(t));\n            }\n        }\n\n        ShapeGroup g;\n        g.k = k;\n        g.isLine = is_line_shape(sh);\n\n        for (auto& kv : oriMap) {\n            const auto& o = kv.second;\n            int mx = 0, my = 0, mz = 0;\n            for (auto& p : o) {\n                mx = max(mx, p.x);\n                my = max(my, p.y);\n                mz = max(mz, p.z);\n            }\n\n            for (int ox = 0; ox + mx < D; ox++) {\n                for (int oy = 0; oy + my < D; oy++) {\n                    for (int oz = 0; oz + mz < D; oz++) {\n                        array<int,8> arr{};\n                        for (int i = 0; i < k; i++) {\n                            arr[i] = idx3(ox + o[i].x, oy + o[i].y, oz + o[i].z);\n                        }\n                        g.plc.push_back(arr);\n                    }\n                }\n            }\n        }\n\n        if (!g.plc.empty()) gs.push_back(move(g));\n    }\n\n    return gs;\n}\n\nvoid precompute() {\n    SX = D * D;\n    SY = D;\n    SZ = 1;\n    N = D * D * D;\n\n    // Layer data and min/max feasible volume\n    for (int obj = 0; obj < 2; obj++) {\n        LAY[obj].assign(D, LayerData{});\n        int vmin = 0, vmax = 0;\n\n        for (int z = 0; z < D; z++) {\n            LayerData ld;\n            for (int x = 0; x < D; x++) if (F[obj][z][x] == '1') ld.X.push_back(x);\n            for (int y = 0; y < D; y++) if (Rv[obj][z][y] == '1') ld.Y.push_back(y);\n\n            int a = (int)ld.X.size();\n            int b = (int)ld.Y.size();\n            ld.base = max(a, b);\n            ld.cap = a * b - ld.base;\n            ld.allowed.reserve(a * b);\n            for (int x : ld.X) for (int y : ld.Y) ld.allowed.push_back(x * D + y);\n\n            vmin += ld.base;\n            vmax += a * b;\n            LAY[obj][z] = move(ld);\n        }\n\n        VminObj[obj] = vmin;\n        VmaxObj[obj] = vmax;\n    }\n\n    // Neighbors / parity\n    parityCell.assign(N, 0);\n    neighbors.assign(N, {});\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        parityCell[id] = (x + y + z) & 1;\n        auto& nb = neighbors[id];\n        if (x > 0) nb.push_back(id - SX);\n        if (x + 1 < D) nb.push_back(id + SX);\n        if (y > 0) nb.push_back(id - SY);\n        if (y + 1 < D) nb.push_back(id + SY);\n        if (z > 0) nb.push_back(id - SZ);\n        if (z + 1 < D) nb.push_back(id + SZ);\n    }\n\n    // Segments (all orientations merged per L)\n    allSegs.assign(D + 1, {});\n    for (int L = 3; L <= D; L++) {\n        auto& v = allSegs[L];\n        v.reserve(3 * (D - L + 1) * D * D);\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int s = idx3(x, y, z);\n            if (x + L <= D) v.push_back({s, SX});\n            if (y + L <= D) v.push_back({s, SY});\n            if (z + L <= D) v.push_back({s, SZ});\n        }\n    }\n\n    // Cube 2x2x2 placements\n    cubeGroup = ShapeGroup{};\n    cubeGroup.k = 8;\n    cubeGroup.isLine = false;\n    for (int x = 0; x + 1 < D; x++) for (int y = 0; y + 1 < D; y++) for (int z = 0; z + 1 < D; z++) {\n        array<int,8> c = {\n            idx3(x, y, z), idx3(x + 1, y, z), idx3(x, y + 1, z), idx3(x + 1, y + 1, z),\n            idx3(x, y, z + 1), idx3(x + 1, y, z + 1), idx3(x, y + 1, z + 1), idx3(x + 1, y + 1, z + 1)\n        };\n        cubeGroup.plc.push_back(c);\n    }\n\n    // Auto enumerate tricubes and tetracubes\n    build_rotations();\n    auto sh3 = enumerate_free_shapes(3);\n    auto sh4 = enumerate_free_shapes(4);\n\n    groups3 = build_groups_from_shapes(sh3, 3);\n    groups4 = build_groups_from_shapes(sh4, 4);\n}\n\nvector<int> allocate_add(int obj, int target, int mode, mt19937_64& rng) {\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    target = max(lo, min(hi, target));\n\n    int need = target - lo;\n    vector<int> add(D, 0);\n    if (need <= 0) return add;\n\n    int totalCap = hi - lo;\n    if (totalCap <= 0) return add;\n\n    // mode=1: random slot allocation\n    if (mode == 1) {\n        vector<int> slots;\n        slots.reserve(totalCap);\n        for (int z = 0; z < D; z++) {\n            int c = LAY[obj][z].cap;\n            for (int t = 0; t < c; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < need; i++) add[slots[i]]++;\n        return add;\n    }\n\n    // mode=0: proportional + fractional remainder\n    vector<long double> frac(D, -1.0L);\n    int used = 0;\n    for (int z = 0; z < D; z++) {\n        int cap = LAY[obj][z].cap;\n        if (!cap) continue;\n        long double ex = (long double)need * (long double)cap / (long double)totalCap;\n        int a = (int)floor(ex);\n        a = min(a, cap);\n        add[z] = a;\n        used += a;\n        frac[z] = ex - a + (long double)(rng() % 1000) * 1e-12L;\n    }\n\n    int rem = need - used;\n    vector<int> ord(D);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int p, int q) { return frac[p] > frac[q]; });\n\n    while (rem > 0) {\n        bool any = false;\n        for (int z : ord) {\n            if (!rem) break;\n            int cap = LAY[obj][z].cap;\n            if (add[z] < cap) {\n                add[z]++;\n                rem--;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n\n    if (rem > 0) {\n        vector<int> slots;\n        for (int z = 0; z < D; z++) {\n            int cap = LAY[obj][z].cap;\n            for (int t = add[z]; t < cap; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < rem && i < (int)slots.size(); i++) add[slots[i]]++;\n    }\n\n    return add;\n}\n\n// nLeft >= nRight\nvector<int> surjection_dp(const vector<vector<int>>& w, mt19937_64& rng) {\n    int nLeft = (int)w.size();\n    int nRight = (int)w[0].size();\n    int M = 1 << nRight;\n    const int NEG = -1000000000;\n\n    vector<int> dp(M, NEG), ndp(M, NEG);\n    vector<int> parMask((nLeft + 1) * M, -1);\n    vector<short> parChoice((nLeft + 1) * M, -1);\n\n    dp[0] = 0;\n    for (int i = 0; i < nLeft; i++) {\n        fill(ndp.begin(), ndp.end(), NEG);\n        int base = (i + 1) * M;\n\n        for (int mask = 0; mask < M; mask++) {\n            int cur = dp[mask];\n            if (cur <= NEG / 2) continue;\n            for (int j = 0; j < nRight; j++) {\n                int m2 = mask | (1 << j);\n                int val = cur + w[i][j];\n                if (val > ndp[m2] || (val == ndp[m2] && (rng() & 1ULL))) {\n                    ndp[m2] = val;\n                    parMask[base + m2] = mask;\n                    parChoice[base + m2] = (short)j;\n                }\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    int full = M - 1;\n    vector<int> assign(nLeft, 0);\n    if (dp[full] <= NEG / 2) {\n        for (int i = 0; i < nLeft; i++) assign[i] = i % nRight;\n        return assign;\n    }\n\n    int mask = full;\n    for (int i = nLeft; i >= 1; i--) {\n        int pos = i * M + mask;\n        short c = parChoice[pos];\n        int pm = parMask[pos];\n        if (c < 0 || pm < 0) {\n            for (int t = 0; t < nLeft; t++) assign[t] = t % nRight;\n            return assign;\n        }\n        assign[i - 1] = (int)c;\n        mask = pm;\n    }\n\n    return assign;\n}\n\nvoid compute_features(Occupancy& oc) {\n    int adj6 = 0, zadj = 0;\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        if (!oc.occ[id]) continue;\n        if (x + 1 < D && oc.occ[id + SX]) adj6++;\n        if (y + 1 < D && oc.occ[id + SY]) adj6++;\n        if (z + 1 < D && oc.occ[id + SZ]) { adj6++; zadj++; }\n    }\n    oc.adj6 = adj6;\n    oc.zadj = zadj;\n}\n\n// style:\n// 0 = DP surjection continuity-biased\n// 1 = grouped shift continuity-biased\n// 2 = random surjection\nOccupancy build_occ_target(int obj, int target, int style, mt19937_64& rng) {\n    Occupancy oc;\n    oc.occ.assign(N, 0);\n    oc.vol = 0;\n\n    int allocMode = (style == 2 ? 1 : 0);\n    vector<int> addz = allocate_add(obj, target, allocMode, rng);\n\n    vector<char> prevXY(D * D, 0), usedXY(D * D, 0);\n\n    for (int z = 0; z < D; z++) {\n        const auto& ld = LAY[obj][z];\n        int a = (int)ld.X.size();\n        int b = (int)ld.Y.size();\n        int m = ld.base + addz[z];\n\n        fill(usedXY.begin(), usedXY.end(), 0);\n        int edgeCount = 0;\n\n        auto put_edge = [&](int x, int y) {\n            int idxy = x * D + y;\n            if (usedXY[idxy]) return;\n            usedXY[idxy] = 1;\n            edgeCount++;\n            int id = idx3(x, y, z);\n            if (!oc.occ[id]) {\n                oc.occ[id] = 1;\n                oc.vol++;\n            }\n        };\n\n        // Build minimal cover\n        if (style == 0) {\n            // DP optimized surjection\n            if (a >= b) {\n                vector<vector<int>> w(a, vector<int>(b, 0));\n                for (int i = 0; i < a; i++) {\n                    int x = ld.X[i];\n                    for (int j = 0; j < b; j++) {\n                        int y = ld.Y[j];\n                        int idxy = x * D + y;\n                        int val = (prevXY[idxy] ? 1000 : 0) + (int)(rng() % 31);\n                        w[i][j] = val;\n                    }\n                }\n                auto assign = surjection_dp(w, rng);\n                for (int i = 0; i < a; i++) put_edge(ld.X[i], ld.Y[assign[i]]);\n            } else {\n                vector<vector<int>> w(b, vector<int>(a, 0));\n                for (int j = 0; j < b; j++) {\n                    int y = ld.Y[j];\n                    for (int i = 0; i < a; i++) {\n                        int x = ld.X[i];\n                        int idxy = x * D + y;\n                        int val = (prevXY[idxy] ? 1000 : 0) + (int)(rng() % 31);\n                        w[j][i] = val;\n                    }\n                }\n                auto assign = surjection_dp(w, rng);\n                for (int j = 0; j < b; j++) put_edge(ld.X[assign[j]], ld.Y[j]);\n            }\n        } else if (style == 1) {\n            // Grouped mapping with best shift\n            vector<int> Xv = ld.X, Yv = ld.Y;\n            if (rng() & 1ULL) reverse(Xv.begin(), Xv.end());\n            if (rng() & 1ULL) reverse(Yv.begin(), Yv.end());\n\n            if (a >= b) {\n                int best = -1;\n                vector<int> bestSh;\n                for (int sh = 0; sh < b; sh++) {\n                    int mat = 0;\n                    for (int j = 0; j < a; j++) {\n                        int g = (int)((long long)j * b / a);\n                        int x = Xv[j];\n                        int y = Yv[(g + sh) % b];\n                        if (prevXY[x * D + y]) mat++;\n                    }\n                    if (mat > best) { best = mat; bestSh = {sh}; }\n                    else if (mat == best) bestSh.push_back(sh);\n                }\n                int shift = bestSh[(size_t)(rng() % bestSh.size())];\n                for (int j = 0; j < a; j++) {\n                    int g = (int)((long long)j * b / a);\n                    put_edge(Xv[j], Yv[(g + shift) % b]);\n                }\n            } else {\n                int best = -1;\n                vector<int> bestSh;\n                for (int sh = 0; sh < a; sh++) {\n                    int mat = 0;\n                    for (int j = 0; j < b; j++) {\n                        int g = (int)((long long)j * a / b);\n                        int x = Xv[(g + sh) % a];\n                        int y = Yv[j];\n                        if (prevXY[x * D + y]) mat++;\n                    }\n                    if (mat > best) { best = mat; bestSh = {sh}; }\n                    else if (mat == best) bestSh.push_back(sh);\n                }\n                int shift = bestSh[(size_t)(rng() % bestSh.size())];\n                for (int j = 0; j < b; j++) {\n                    int g = (int)((long long)j * a / b);\n                    put_edge(Xv[(g + shift) % a], Yv[j]);\n                }\n            }\n        } else {\n            // Random surjection\n            if (a >= b) {\n                vector<int> Xv = ld.X;\n                shuffle(Xv.begin(), Xv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(a);\n                for (int y : ld.Y) pool.push_back(y);\n                for (int t = 0; t < a - b; t++) pool.push_back(ld.Y[(int)(rng() % b)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < a; j++) put_edge(Xv[j], pool[j]);\n            } else {\n                vector<int> Yv = ld.Y;\n                shuffle(Yv.begin(), Yv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(b);\n                for (int x : ld.X) pool.push_back(x);\n                for (int t = 0; t < b - a; t++) pool.push_back(ld.X[(int)(rng() % a)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < b; j++) put_edge(pool[j], Yv[j]);\n            }\n        }\n\n        // Add extras to reach m\n        int extra = m - edgeCount;\n        if (extra > 0) {\n            vector<int> cand;\n            cand.reserve(ld.allowed.size());\n            for (int idxy : ld.allowed) if (!usedXY[idxy]) cand.push_back(idxy);\n\n            if (extra >= (int)cand.size()) {\n                for (int idxy : cand) put_edge(idxy / D, idxy % D);\n            } else if (style == 2) {\n                shuffle(cand.begin(), cand.end(), rng);\n                for (int t = 0; t < extra; t++) {\n                    int idxy = cand[t];\n                    put_edge(idxy / D, idxy % D);\n                }\n            } else {\n                for (int t = 0; t < extra; t++) {\n                    int bestId = -1, bestV = -1;\n                    for (int idxy : cand) {\n                        if (usedXY[idxy]) continue;\n                        int x = idxy / D, y = idxy % D;\n                        int sc = 0;\n                        sc += (prevXY[idxy] ? (style == 0 ? 120 : 60) : 0);\n                        int adj = 0;\n                        if (x > 0 && usedXY[(x - 1) * D + y]) adj++;\n                        if (x + 1 < D && usedXY[(x + 1) * D + y]) adj++;\n                        if (y > 0 && usedXY[x * D + (y - 1)]) adj++;\n                        if (y + 1 < D && usedXY[x * D + (y + 1)]) adj++;\n                        sc += adj * (style == 0 ? 12 : 8);\n                        sc += (int)(rng() % 16);\n\n                        if (sc > bestV) {\n                            bestV = sc;\n                            bestId = idxy;\n                        }\n                    }\n                    if (bestId < 0) break;\n                    put_edge(bestId / D, bestId % D);\n                }\n            }\n        }\n\n        prevXY = usedXY;\n    }\n\n    compute_features(oc);\n    return oc;\n}\n\nvector<Occupancy> generate_candidates(int obj, mt19937_64& rng) {\n    vector<Occupancy> cands;\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    int span = hi - lo;\n\n    vector<int> targets;\n    int lowSteps = min(span, 8);\n    for (int d = 0; d <= lowSteps; d++) targets.push_back(lo + d);\n\n    for (int q = 0; q <= 8; q++) {\n        targets.push_back(lo + (int)((long long)span * q * q / 64));\n    }\n\n    targets.push_back(lo + span / 4);\n    targets.push_back(lo + span / 2);\n    targets.push_back(lo + (3 * span) / 4);\n    targets.push_back(hi);\n\n    sort(targets.begin(), targets.end());\n    targets.erase(unique(targets.begin(), targets.end()), targets.end());\n\n    int softCap = 42;\n    for (int T : targets) {\n        if ((int)cands.size() >= softCap) break;\n\n        if (T <= lo + max(1, span / 4)) {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            cands.push_back(build_occ_target(obj, T, 1, rng));\n            cands.push_back(build_occ_target(obj, T, 2, rng));\n            if ((rng() % 100) < 30 && (int)cands.size() < softCap) {\n                cands.push_back(build_occ_target(obj, T, 0, rng));\n            }\n        } else {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            if ((int)cands.size() < softCap) cands.push_back(build_occ_target(obj, T, 2, rng));\n        }\n    }\n\n    for (int t = 0; t < 6; t++) {\n        long double u = (long double)(rng() % 1000000) / 1000000.0L;\n        u = u * u;\n        int T = lo + (int)llround((long double)span * u);\n        int style = ((rng() % 100) < 58 ? 0 : (rng() % 2 ? 1 : 2));\n        cands.push_back(build_occ_target(obj, T, style, rng));\n    }\n\n    return cands;\n}\n\nvector<int> pack_line_best_idx(const vector<char>& freeCells, int L, mt19937_64& rng, int tries = 2) {\n    const auto& pls = allSegs[L];\n\n    vector<int> valid;\n    valid.reserve(pls.size());\n\n    for (int i = 0; i < (int)pls.size(); i++) {\n        const auto& sg = pls[i];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!freeCells[p]) { ok = false; break; }\n        }\n        if (ok) valid.push_back(i);\n    }\n\n    if (valid.empty()) return {};\n\n    vector<int> best;\n    vector<int> rareOrder;\n\n    if (tries >= 2) {\n        vector<int> freq(N, 0);\n        for (int id : valid) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            for (int t = 0; t < L; t++, p += sg.stride) freq[p]++;\n        }\n\n        vector<pair<long long,int>> scored;\n        scored.reserve(valid.size());\n        for (int id : valid) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            int s = 0;\n            for (int t = 0; t < L; t++, p += sg.stride) s += freq[p];\n            long long key = (long long)s * 2048LL + (long long)(rng() & 2047ULL);\n            scored.push_back({key, id});\n        }\n        sort(scored.begin(), scored.end(), [](auto& a, auto& b) {\n            return a.first < b.first;\n        });\n        rareOrder.reserve(scored.size());\n        for (auto& p : scored) rareOrder.push_back(p.second);\n    }\n\n    for (int tr = 0; tr < tries; tr++) {\n        vector<int> order;\n        if (tr == 0 && !rareOrder.empty()) order = rareOrder;\n        else {\n            order = valid;\n            shuffle(order.begin(), order.end(), rng);\n        }\n\n        vector<char> tmp = freeCells;\n        vector<int> sel;\n        sel.reserve(order.size() / max(1, L) + 1);\n\n        for (int id : order) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            bool ok = true;\n            for (int t = 0; t < L; t++, p += sg.stride) {\n                if (!tmp[p]) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            sel.push_back(id);\n            p = sg.s;\n            for (int t = 0; t < L; t++, p += sg.stride) tmp[p] = 0;\n        }\n\n        if (sel.size() > best.size()) best.swap(sel);\n    }\n\n    return best;\n}\n\nvector<int> pack_group_best(const vector<char>& freeCells, const ShapeGroup& g, mt19937_64& rng, int tries = 2) {\n    int k = g.k;\n    const auto& pls = g.plc;\n\n    vector<int> valid;\n    valid.reserve(pls.size());\n\n    for (int i = 0; i < (int)pls.size(); i++) {\n        const auto& a = pls[i];\n        bool ok = true;\n        for (int t = 0; t < k; t++) {\n            if (!freeCells[a[t]]) { ok = false; break; }\n        }\n        if (ok) valid.push_back(i);\n    }\n\n    if (valid.empty()) return {};\n\n    vector<int> best;\n    vector<int> rareOrder;\n\n    if (tries >= 2) {\n        vector<int> freq(N, 0);\n        for (int id : valid) {\n            const auto& a = pls[id];\n            for (int t = 0; t < k; t++) freq[a[t]]++;\n        }\n\n        vector<pair<long long,int>> scored;\n        scored.reserve(valid.size());\n        for (int id : valid) {\n            const auto& a = pls[id];\n            int s = 0;\n            for (int t = 0; t < k; t++) s += freq[a[t]];\n            long long key = (long long)s * 2048LL + (long long)(rng() & 2047ULL);\n            scored.push_back({key, id});\n        }\n        sort(scored.begin(), scored.end(), [](auto& p, auto& q) {\n            return p.first < q.first;\n        });\n        rareOrder.reserve(scored.size());\n        for (auto& p : scored) rareOrder.push_back(p.second);\n    }\n\n    for (int tr = 0; tr < tries; tr++) {\n        vector<int> order;\n        if (tr == 0 && !rareOrder.empty()) order = rareOrder;\n        else {\n            order = valid;\n            shuffle(order.begin(), order.end(), rng);\n        }\n\n        vector<char> tmp = freeCells;\n        vector<int> sel;\n        sel.reserve(order.size() / max(1, k) + 1);\n\n        for (int id : order) {\n            const auto& a = pls[id];\n            bool ok = true;\n            for (int t = 0; t < k; t++) {\n                if (!tmp[a[t]]) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            sel.push_back(id);\n            for (int t = 0; t < k; t++) tmp[a[t]] = 0;\n        }\n\n        if (sel.size() > best.size()) best.swap(sel);\n    }\n\n    return best;\n}\n\nvector<pair<int,int>> max_domino_matching(const vector<char>& freeCells) {\n    vector<int> lid(N, -1), rid(N, -1);\n    vector<int> Lc, Rc;\n    Lc.reserve(N); Rc.reserve(N);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i]) continue;\n        if (parityCell[i] == 0) {\n            lid[i] = (int)Lc.size();\n            Lc.push_back(i);\n        } else {\n            rid[i] = (int)Rc.size();\n            Rc.push_back(i);\n        }\n    }\n\n    int Ls = (int)Lc.size();\n    int Rs = (int)Rc.size();\n\n    vector<vector<int>> g(Ls);\n    for (int u = 0; u < Ls; u++) {\n        int c = Lc[u];\n        for (int nb : neighbors[c]) {\n            if (!freeCells[nb]) continue;\n            int v = rid[nb];\n            if (v != -1) g[u].push_back(v);\n        }\n    }\n\n    vector<int> dist(Ls), matchL(Ls, -1), matchR(Rs, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(dist.begin(), dist.end(), -1);\n        bool found = false;\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                int u2 = matchR[v];\n                if (u2 == -1) {\n                    found = true;\n                } else if (dist[u2] == -1) {\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n            }\n        }\n        return found;\n    };\n\n    auto dfs = [&](auto&& self, int u) -> bool {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && self(self, u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int u = 0; u < Ls; u++) if (matchL[u] == -1) dfs(dfs, u);\n    }\n\n    vector<pair<int,int>> pairs;\n    pairs.reserve(Ls);\n    for (int u = 0; u < Ls; u++) {\n        if (matchL[u] != -1) pairs.push_back({Lc[u], Rc[matchL[u]]});\n    }\n    return pairs;\n}\n\nSolution make_solution(const Occupancy& o1, const Occupancy& o2, mt19937_64& rng) {\n    vector<char> free1 = o1.occ;\n    vector<char> free2 = o2.occ;\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int id = 0;\n    int sharedVol = 0;\n    long double sharedTerm = 0.0L;\n\n    auto apply_line_pair = [&](int L, int tries) {\n        if (L < 3) return;\n        auto s1 = pack_line_best_idx(free1, L, rng, tries);\n        auto s2 = pack_line_best_idx(free2, L, rng, tries);\n\n        int s = min((int)s1.size(), (int)s2.size());\n        if (s == 0) return;\n\n        if ((int)s1.size() > s) {\n            shuffle(s1.begin(), s1.end(), rng);\n            s1.resize(s);\n        }\n        if ((int)s2.size() > s) {\n            shuffle(s2.begin(), s2.end(), rng);\n            s2.resize(s);\n        }\n\n        const auto& pls = allSegs[L];\n        for (int i = 0; i < s; i++) {\n            ++id;\n\n            const auto& a = pls[s1[i]];\n            int p = a.s;\n            for (int t = 0; t < L; t++, p += a.stride) {\n                b1[p] = id;\n                free1[p] = 0;\n            }\n\n            const auto& b = pls[s2[i]];\n            p = b.s;\n            for (int t = 0; t < L; t++, p += b.stride) {\n                b2[p] = id;\n                free2[p] = 0;\n            }\n\n            sharedVol += L;\n            sharedTerm += 1.0L / (long double)L;\n        }\n    };\n\n    auto apply_group_pair = [&](const ShapeGroup& g, int tries) {\n        auto s1 = pack_group_best(free1, g, rng, tries);\n        auto s2 = pack_group_best(free2, g, rng, tries);\n\n        int s = min((int)s1.size(), (int)s2.size());\n        if (s == 0) return;\n\n        if ((int)s1.size() > s) {\n            shuffle(s1.begin(), s1.end(), rng);\n            s1.resize(s);\n        }\n        if ((int)s2.size() > s) {\n            shuffle(s2.begin(), s2.end(), rng);\n            s2.resize(s);\n        }\n\n        int k = g.k;\n        for (int i = 0; i < s; i++) {\n            ++id;\n            const auto& a = g.plc[s1[i]];\n            const auto& b = g.plc[s2[i]];\n\n            for (int t = 0; t < k; t++) {\n                b1[a[t]] = id;\n                free1[a[t]] = 0;\n            }\n            for (int t = 0; t < k; t++) {\n                b2[b[t]] = id;\n                free2[b[t]] = 0;\n            }\n\n            sharedVol += k;\n            sharedTerm += 1.0L / (long double)k;\n        }\n    };\n\n    int variant = (int)(rng() % 5);\n\n    if (variant == 0) {\n        for (int L = D; L >= 9; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n        for (int L = min(8, D); L >= 5; L--) apply_line_pair(L, 2);\n    } else if (variant == 1) {\n        apply_group_pair(cubeGroup, 2);\n        for (int L = D; L >= 5; L--) apply_line_pair(L, 2);\n    } else if (variant == 2) {\n        for (int L = D; L >= 5; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n    } else if (variant == 3) {\n        for (int L = D; L >= 6; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n        if (D >= 5) apply_line_pair(5, 2);\n    } else {\n        for (int L = D; L >= 7; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 1);\n        for (int L = min(6, D); L >= 5; L--) apply_line_pair(L, 2);\n    }\n\n    // Tetracubes (all free size-4 shapes)\n    vector<int> ord4(groups4.size());\n    iota(ord4.begin(), ord4.end(), 0);\n\n    int p4 = (int)(rng() % 4);\n    if (p4 == 0) {\n        shuffle(ord4.begin(), ord4.end(), rng);\n    } else if (p4 == 1) {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            return groups4[i].plc.size() < groups4[j].plc.size();\n        });\n    } else if (p4 == 2) {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            return groups4[i].plc.size() > groups4[j].plc.size();\n        });\n    } else {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            if (groups4[i].isLine != groups4[j].isLine) return groups4[i].isLine > groups4[j].isLine;\n            return groups4[i].plc.size() < groups4[j].plc.size();\n        });\n    }\n\n    for (int idx : ord4) {\n        int tries = 2;\n        if (groups4[idx].isLine && (rng() % 100) < 30) tries = 3;\n        apply_group_pair(groups4[idx], tries);\n    }\n\n    // Tricubes (all free size-3 shapes)\n    vector<int> ord3(groups3.size());\n    iota(ord3.begin(), ord3.end(), 0);\n\n    if ((rng() & 1ULL) == 0) {\n        sort(ord3.begin(), ord3.end(), [&](int i, int j) {\n            if (groups3[i].isLine != groups3[j].isLine) return groups3[i].isLine > groups3[j].isLine;\n            return groups3[i].plc.size() < groups3[j].plc.size();\n        });\n    } else {\n        shuffle(ord3.begin(), ord3.end(), rng);\n    }\n\n    for (int idx : ord3) {\n        apply_group_pair(groups3[idx], 2);\n    }\n\n    // Domino matching\n    auto d1 = max_domino_matching(free1);\n    auto d2 = max_domino_matching(free2);\n    int sd = min((int)d1.size(), (int)d2.size());\n\n    if (sd > 0) {\n        if ((int)d1.size() > sd) {\n            shuffle(d1.begin(), d1.end(), rng);\n            d1.resize(sd);\n        }\n        if ((int)d2.size() > sd) {\n            shuffle(d2.begin(), d2.end(), rng);\n            d2.resize(sd);\n        }\n\n        for (int i = 0; i < sd; i++) {\n            ++id;\n            auto [a, b] = d1[i];\n            b1[a] = id; b1[b] = id;\n            free1[a] = 0; free1[b] = 0;\n\n            auto [c, d] = d2[i];\n            b2[c] = id; b2[d] = id;\n            free2[c] = 0; free2[d] = 0;\n\n            sharedVol += 2;\n            sharedTerm += 0.5L;\n        }\n    }\n\n    // Monomino pairing + leftovers\n    vector<int> rem1, rem2;\n    rem1.reserve(N); rem2.reserve(N);\n\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) rem1.push_back(i);\n        if (free2[i]) rem2.push_back(i);\n    }\n\n    shuffle(rem1.begin(), rem1.end(), rng);\n    shuffle(rem2.begin(), rem2.end(), rng);\n\n    int sm = min((int)rem1.size(), (int)rem2.size());\n    for (int i = 0; i < sm; i++) {\n        ++id;\n        b1[rem1[i]] = id;\n        b2[rem2[i]] = id;\n        sharedVol += 1;\n        sharedTerm += 1.0L;\n    }\n    for (int i = sm; i < (int)rem1.size(); i++) {\n        ++id;\n        b1[rem1[i]] = id;\n    }\n    for (int i = sm; i < (int)rem2.size(); i++) {\n        ++id;\n        b2[rem2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = (long double)(o1.vol + o2.vol - 2 * sharedVol) + sharedTerm;\n    return sol;\n}\n\nbool check_silhouette_one(const vector<int>& b, int obj) {\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) {\n            bool seen = false;\n            for (int y = 0; y < D; y++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (F[obj][z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; y++) {\n            bool seen = false;\n            for (int x = 0; x < D; x++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (Rv[obj][z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nbool check_silhouette(const Solution& sol) {\n    if ((int)sol.b1.size() != N || (int)sol.b2.size() != N) return false;\n    return check_silhouette_one(sol.b1, 0) && check_silhouette_one(sol.b2, 1);\n}\n\nSolution fallback_simple() {\n    vector<int> b1(N, 0), b2(N, 0);\n    vector<int> c1, c2;\n    c1.reserve(N);\n    c2.reserve(N);\n\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (F[0][z][x] == '1' && Rv[0][z][y] == '1') c1.push_back(idx3(x, y, z));\n        if (F[1][z][x] == '1' && Rv[1][z][y] == '1') c2.push_back(idx3(x, y, z));\n    }\n\n    int id = 0;\n    int m = min((int)c1.size(), (int)c2.size());\n    for (int i = 0; i < m; i++) {\n        ++id;\n        b1[c1[i]] = id;\n        b2[c2[i]] = id;\n    }\n    for (int i = m; i < (int)c1.size(); i++) {\n        ++id;\n        b1[c1[i]] = id;\n    }\n    for (int i = m; i < (int)c2.size(); i++) {\n        ++id;\n        b2[c2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = 1e99L;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        Rv[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> Rv[i][z];\n    }\n\n    precompute();\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count()\n        ^ ((uint64_t)D * 1000003ULL)\n    );\n\n    const double TL = 5.25;\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    Solution best;\n    const long double INF = 1e100L;\n\n    int overlapL = max(VminObj[0], VminObj[1]);\n    int overlapU = min(VmaxObj[0], VmaxObj[1]);\n    bool hasOverlap = (overlapL <= overlapU);\n\n    auto try_pair = [&](const Occupancy& o1, const Occupancy& o2, int repsBase) -> long double {\n        if (elapsed() >= TL) return INF;\n\n        int mn = min(o1.vol, o2.vol);\n        long double lb = fabsl((long double)o1.vol - (long double)o2.vol) + 1.0L / (long double)mn;\n        if (lb + 1e-12L >= best.score) return INF;\n\n        int reps = repsBase;\n        if (best.score < INF / 2) {\n            if (lb < best.score * 0.72L) reps = max(reps, 2);\n            if (lb < best.score * 0.58L) reps = max(reps, 3);\n        }\n        if (elapsed() > TL * 0.90) reps = 1;\n\n        long double localBest = INF;\n        for (int t = 0; t < reps; t++) {\n            if (elapsed() >= TL) break;\n            Solution cur = make_solution(o1, o2, rng);\n            localBest = min(localBest, cur.score);\n            if (cur.score < best.score) best = move(cur);\n        }\n        return localBest;\n    };\n\n    // Initial solution\n    {\n        int t1, t2;\n        if (hasOverlap) {\n            t1 = overlapL;\n            t2 = overlapL;\n        } else if (VmaxObj[0] < VminObj[1]) {\n            t1 = VmaxObj[0];\n            t2 = VminObj[1];\n        } else {\n            t1 = VminObj[0];\n            t2 = VmaxObj[1];\n        }\n        Occupancy o1 = build_occ_target(0, t1, 0, rng);\n        Occupancy o2 = build_occ_target(1, t2, 0, rng);\n        try_pair(o1, o2, 3);\n    }\n\n    vector<Occupancy> cand1, cand2;\n    if (elapsed() < TL * 0.35) {\n        cand1 = generate_candidates(0, rng);\n        cand2 = generate_candidates(1, rng);\n    } else {\n        cand1.push_back(build_occ_target(0, VminObj[0], 0, rng));\n        cand2.push_back(build_occ_target(1, VminObj[1], 0, rng));\n    }\n\n    struct PairCand {\n        int i, j;\n        int diff;\n        int mn;\n        int zmin;\n        int amin;\n        uint64_t tie;\n    };\n\n    vector<PairCand> plist;\n    plist.reserve((int)cand1.size() * (int)cand2.size());\n\n    for (int i = 0; i < (int)cand1.size(); i++) {\n        for (int j = 0; j < (int)cand2.size(); j++) {\n            int diff = abs(cand1[i].vol - cand2[j].vol);\n            int mn = min(cand1[i].vol, cand2[j].vol);\n            int zmin = min(cand1[i].zadj, cand2[j].zadj);\n            int amin = min(cand1[i].adj6, cand2[j].adj6);\n            plist.push_back({i, j, diff, mn, zmin, amin, rng()});\n        }\n    }\n\n    sort(plist.begin(), plist.end(), [](const PairCand& a, const PairCand& b) {\n        if (a.diff != b.diff) return a.diff < b.diff;\n        if (a.mn != b.mn) return a.mn < b.mn;\n        if (a.zmin != b.zmin) return a.zmin > b.zmin;\n        if (a.amin != b.amin) return a.amin > b.amin;\n        return a.tie < b.tie;\n    });\n\n    vector<tuple<long double,int,int>> records;\n    int initLimit = min((int)plist.size(), 190);\n    for (int p = 0; p < initLimit; p++) {\n        if (elapsed() >= TL * 0.60) break;\n        const auto& pc = plist[p];\n        int reps = (p < 22 ? 2 : 1);\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], reps);\n        if (sc < INF / 10) records.emplace_back(sc, pc.i, pc.j);\n    }\n\n    if (records.empty() && !plist.empty() && elapsed() < TL) {\n        const auto& pc = plist[0];\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], 1);\n        if (sc < INF / 10) records.emplace_back(sc, pc.i, pc.j);\n    }\n\n    sort(records.begin(), records.end(), [](const auto& A, const auto& B) {\n        return get<0>(A) < get<0>(B);\n    });\n\n    vector<pair<int,int>> eliteIdx;\n    int eN = min((int)records.size(), 40);\n    for (int i = 0; i < eN; i++) {\n        eliteIdx.push_back({get<1>(records[i]), get<2>(records[i])});\n    }\n\n    struct DynPair {\n        Occupancy o1, o2;\n        long double sc;\n    };\n    vector<DynPair> dyn;\n\n    auto add_dyn = [&](const Occupancy& o1, const Occupancy& o2, long double sc) {\n        if (!(sc < INF / 10)) return;\n        if ((int)dyn.size() < 10) {\n            dyn.push_back({o1, o2, sc});\n        } else {\n            int worst = 0;\n            for (int i = 1; i < (int)dyn.size(); i++) if (dyn[i].sc > dyn[worst].sc) worst = i;\n            if (sc < dyn[worst].sc) dyn[worst] = {o1, o2, sc};\n        }\n    };\n\n    for (int i = 0; i < min((int)records.size(), 8); i++) {\n        int ii = get<1>(records[i]), jj = get<2>(records[i]);\n        add_dyn(cand1[ii], cand2[jj], get<0>(records[i]));\n    }\n\n    while (elapsed() < TL) {\n        int r = (int)(rng() % 100);\n\n        if (!eliteIdx.empty() && r < 52) {\n            auto [i, j] = eliteIdx[(size_t)(rng() % eliteIdx.size())];\n            int reps = ((rng() % 100) < 22 ? 2 : 1);\n            try_pair(cand1[i], cand2[j], reps);\n        } else if (!dyn.empty() && r < 80) {\n            int idp = (int)(rng() % dyn.size());\n            int reps = ((rng() % 100) < 28 ? 2 : 1);\n            long double sc = try_pair(dyn[idp].o1, dyn[idp].o2, reps);\n            dyn[idp].sc = min(dyn[idp].sc, sc);\n        } else {\n            int style1 = ((rng() % 100) < 58 ? 0 : (rng() % 2 ? 1 : 2));\n            int style2 = ((rng() % 100) < 58 ? 0 : (rng() % 2 ? 1 : 2));\n\n            int t1, t2;\n\n            if (hasOverlap && (rng() % 100) < 88) {\n                int span = overlapU - overlapL;\n                long double u = (long double)(rng() % 1000000) / 1000000.0L;\n                u = u * u;\n                int T = overlapL + (int)llround((long double)span * u);\n\n                int jit = max(0, span / 14);\n                int d1 = (jit ? (int)(rng() % (2 * jit + 1)) - jit : 0);\n                int d2 = (jit ? (int)(rng() % (2 * jit + 1)) - jit : 0);\n\n                t1 = clampi(T + d1, VminObj[0], VmaxObj[0]);\n                t2 = clampi(T + d2, VminObj[1], VmaxObj[1]);\n            } else if (VmaxObj[0] < VminObj[1]) {\n                int a = min(6, VmaxObj[0] - VminObj[0]);\n                int b = min(6, VmaxObj[1] - VminObj[1]);\n                t1 = VmaxObj[0] - (a ? (int)(rng() % (a + 1)) : 0);\n                t2 = VminObj[1] + (b ? (int)(rng() % (b + 1)) : 0);\n            } else if (VmaxObj[1] < VminObj[0]) {\n                int a = min(6, VmaxObj[0] - VminObj[0]);\n                int b = min(6, VmaxObj[1] - VminObj[1]);\n                t1 = VminObj[0] + (a ? (int)(rng() % (a + 1)) : 0);\n                t2 = VmaxObj[1] - (b ? (int)(rng() % (b + 1)) : 0);\n            } else {\n                int span1 = VmaxObj[0] - VminObj[0];\n                int span2 = VmaxObj[1] - VminObj[1];\n                long double u1 = (long double)(rng() % 1000000) / 1000000.0L;\n                long double u2 = (long double)(rng() % 1000000) / 1000000.0L;\n                u1 = u1 * u1;\n                u2 = u2 * u2;\n                t1 = VminObj[0] + (int)llround((long double)span1 * u1);\n                t2 = VminObj[1] + (int)llround((long double)span2 * u2);\n            }\n\n            Occupancy o1 = build_occ_target(0, t1, style1, rng);\n            Occupancy o2 = build_occ_target(1, t2, style2, rng);\n\n            long double sc = try_pair(o1, o2, 1);\n            if (sc < best.score * 1.30L) add_dyn(o1, o2, sc);\n        }\n    }\n\n    if (best.n == 0 || !check_silhouette(best)) {\n        best = fallback_simple();\n    }\n\n    cout << best.n << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b2[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(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    using ll = long long;\n    static constexpr ll INF = (1LL << 62);\n    static constexpr int MAXN = 105;\n    static constexpr int MAXM = 305;\n\n    int N, M, K;\n\n    struct Edge {\n        int u, v, w;\n    };\n\n    vector<int> x, y;\n    vector<Edge> edges;\n    vector<int> a, b;\n\n    vector<vector<pair<int, int>>> g; // (to, edge_id)\n    vector<vector<int>> incident;\n    vector<int> edgeOrder;\n\n    // dist station-resident (ceil Euclid)\n    vector<vector<uint16_t>> distSR; // [N][K]\n\n    // candidates per resident within 5000: (dist, station), sorted by dist\n    vector<vector<pair<uint16_t, int>>> cand; // [K]\n\n    // residents per station within 5000: (dist, resident), sorted by dist\n    vector<vector<pair<uint16_t, int>>> byStation; // [N]\n    vector<vector<int>> coverResidents; // [N] residents within 5000\n\n    // APSP on station graph\n    vector<vector<ll>> spDist; // [N][N]\n    vector<vector<int>> prevNode; // [src][v]\n    vector<vector<int>> prevEdge; // [src][v]\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point startTime;\n\n    struct Key {\n        uint64_t lo = 0, hi = 0;\n        bool operator==(const Key &o) const noexcept {\n            return lo == o.lo && hi == o.hi;\n        }\n    };\n    struct KeyHash {\n        size_t operator()(const Key &k) const noexcept {\n            size_t h1 = std::hash<uint64_t>{}(k.lo);\n            size_t h2 = std::hash<uint64_t>{}(k.hi);\n            return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));\n        }\n    };\n\n    unordered_map<Key, ll, KeyHash> cacheFast;\n    unordered_map<Key, ll, KeyHash> cacheExact;\n\n    struct Solution {\n        bool feasible = false;\n        ll cost = INF;\n        vector<int> P;\n        vector<char> B;\n    };\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static int ceilDistInt(int x1, int y1, int x2, int y2) {\n        long long dx = 1LL * x1 - x2;\n        long long dy = 1LL * y1 - y2;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)std::sqrt((double)sq);\n        while (1LL * d * d < sq) ++d;\n        while (d > 0 && 1LL * (d - 1) * (d - 1) >= sq) --d;\n        return d;\n    }\n\n    Key makeKey(const vector<char> &active) const {\n        Key k;\n        for (int i = 0; i < N; i++) {\n            if (!active[i]) continue;\n            if (i < 64) k.lo |= (1ULL << i);\n            else k.hi |= (1ULL << (i - 64));\n        }\n        return k;\n    }\n\n    bool sameState(const vector<char> &A, const vector<char> &B) const {\n        if ((int)A.size() != N || (int)B.size() != N) return false;\n        for (int i = 0; i < N; i++) {\n            if (A[i] != B[i]) return false;\n        }\n        return true;\n    }\n\n    void addUniqueState(vector<vector<char>> &vec, const vector<char> &st) {\n        for (auto &v : vec) {\n            if (sameState(v, st)) return;\n        }\n        vec.push_back(st);\n    }\n\n    void pushPool(vector<pair<ll, vector<char>>> &pool, const vector<char> &st, ll cost, int lim = 12) {\n        for (auto &p : pool) {\n            if (sameState(p.second, st)) {\n                if (cost < p.first) p.first = cost;\n                sort(pool.begin(), pool.end(), [](auto &L, auto &R) { return L.first < R.first; });\n                if ((int)pool.size() > lim) pool.resize(lim);\n                return;\n            }\n        }\n        pool.push_back({cost, st});\n        sort(pool.begin(), pool.end(), [](auto &L, auto &R) { return L.first < R.first; });\n        if ((int)pool.size() > lim) pool.resize(lim);\n    }\n\n    void readInput() {\n        cin >> N >> M >> K;\n        x.resize(N);\n        y.resize(N);\n        for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(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            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        }\n\n        a.resize(K);\n        b.resize(K);\n        for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n        edgeOrder.resize(M);\n        iota(edgeOrder.begin(), edgeOrder.end(), 0);\n        sort(edgeOrder.begin(), edgeOrder.end(), [&](int e1, int e2) {\n            return edges[e1].w < edges[e2].w;\n        });\n    }\n\n    void precomputeDistances() {\n        distSR.assign(N, vector<uint16_t>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                int d = ceilDistInt(x[i], y[i], a[k], b[k]);\n                if (d > 65535) d = 65535;\n                distSR[i][k] = (uint16_t)d;\n            }\n        }\n\n        cand.assign(K, {});\n        byStation.assign(N, {});\n        for (int k = 0; k < K; k++) {\n            auto &v = cand[k];\n            v.reserve(N);\n            for (int i = 0; i < N; i++) {\n                int d = distSR[i][k];\n                if (d <= 5000) v.push_back({(uint16_t)d, i});\n            }\n            sort(v.begin(), v.end(), [](auto &L, auto &R) {\n                if (L.first != R.first) return L.first < R.first;\n                return L.second < R.second;\n            });\n\n            // safety fallback (generator should avoid empty)\n            if (v.empty()) {\n                int bestI = 0, bestD = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    int d = distSR[i][k];\n                    if (d < bestD) bestD = d, bestI = i;\n                }\n                v.push_back({(uint16_t)bestD, bestI});\n            }\n\n            for (auto &pr : v) {\n                byStation[pr.second].push_back({pr.first, k});\n            }\n        }\n\n        coverResidents.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            auto &bs = byStation[i];\n            sort(bs.begin(), bs.end(), [](auto &L, auto &R) {\n                if (L.first != R.first) return L.first < R.first;\n                return L.second < R.second;\n            });\n            coverResidents[i].reserve(bs.size());\n            for (auto &pr : bs) coverResidents[i].push_back(pr.second);\n        }\n    }\n\n    void precomputeShortestPaths() {\n        spDist.assign(N, vector<ll>(N, INF));\n        prevNode.assign(N, vector<int>(N, -1));\n        prevEdge.assign(N, vector<int>(N, -1));\n\n        for (int s = 0; s < N; s++) {\n            vector<ll> d(N, INF);\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            d[s] = 0;\n            prevNode[s][s] = s;\n            prevEdge[s][s] = -1;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n                if (cd != d[v]) continue;\n\n                for (auto [to, eid] : g[v]) {\n                    ll nd = cd + edges[eid].w;\n                    if (nd < d[to]) {\n                        d[to] = nd;\n                        prevNode[s][to] = v;\n                        prevEdge[s][to] = eid;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n\n            spDist[s] = move(d);\n        }\n    }\n\n    bool buildPNearest(const vector<char> &active, int P[]) {\n        for (int i = 0; i < N; i++) P[i] = 0;\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1;\n            int d = 0;\n            for (auto &pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return false;\n            if (d > P[chosen]) P[chosen] = d;\n        }\n        return true;\n    }\n\n    void shrinkP(int P[], bool full) {\n        vector<int> cnt(K, 0);\n\n        for (int i = 0; i < N; i++) {\n            int pi = P[i];\n            if (pi <= 0) continue;\n            for (auto &pr : byStation[i]) {\n                int d = pr.first;\n                int k = pr.second;\n                if (d > pi) break;\n                cnt[k]++;\n            }\n        }\n\n        int pass = 0;\n        int maxPass = full ? 1000 : 2;\n\n        while (pass < maxPass) {\n            pass++;\n            bool changed = false;\n\n            for (int i = 0; i < N; i++) {\n                int old = P[i];\n                if (old <= 0) continue;\n\n                int req = 0;\n                for (auto &pr : byStation[i]) {\n                    int d = pr.first;\n                    int k = pr.second;\n                    if (d > old) break;\n                    if (cnt[k] == 1 && d > req) req = d;\n                }\n\n                if (req < old) {\n                    for (auto &pr : byStation[i]) {\n                        int d = pr.first;\n                        int k = pr.second;\n                        if (d > old) break;\n                        if (d > req) cnt[k]--;\n                    }\n                    P[i] = req;\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    ll pruneAlive(vector<char> &alive, const vector<int> &terminals) {\n        vector<int> deg(N, 0);\n        vector<char> isTerm(N, 0);\n        for (int v : terminals) isTerm[v] = 1;\n\n        ll cost = 0;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            cost += edges[eid].w;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        return cost;\n    }\n\n    ll steinerKMB(const int terminals[], int t, vector<char> *outB) {\n        if (outB) outB->assign(M, 0);\n        if (t <= 1) return 0;\n\n        ll minD[MAXN];\n        int parent[MAXN];\n        bool used[MAXN];\n        for (int i = 0; i < t; i++) {\n            minD[i] = INF;\n            parent[i] = -1;\n            used[i] = false;\n        }\n        minD[0] = 0;\n\n        // Prim on metric closure\n        for (int it = 0; it < t; it++) {\n            int v = -1;\n            for (int i = 0; i < t; i++) {\n                if (!used[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            if (v == -1) return INF;\n            used[v] = true;\n\n            int tv = terminals[v];\n            for (int j = 0; j < t; j++) {\n                if (used[j]) continue;\n                ll nd = spDist[tv][terminals[j]];\n                if (nd < minD[j]) {\n                    minD[j] = nd;\n                    parent[j] = v;\n                }\n            }\n        }\n\n        unsigned char marked[MAXM] = {};\n        unsigned char alive[MAXM] = {};\n\n        // expand closure MST edges to shortest paths\n        for (int i = 1; i < t; i++) {\n            int s = terminals[parent[i]];\n            int cur = terminals[i];\n            while (cur != s) {\n                int eid = prevEdge[s][cur];\n                if (eid < 0) return INF;\n                marked[eid] = 1;\n                cur = prevNode[s][cur];\n            }\n        }\n\n        // MST on marked subgraph\n        DSU dsu(N);\n        ll cost = 0;\n        for (int eid : edgeOrder) {\n            if (!marked[eid]) continue;\n            auto &e = edges[eid];\n            if (dsu.merge(e.u, e.v)) {\n                alive[eid] = 1;\n                cost += e.w;\n            }\n        }\n\n        // prune non-terminal leaves\n        int deg[MAXN] = {};\n        bool isTerm[MAXN] = {};\n        for (int i = 0; i < t; i++) isTerm[terminals[i]] = true;\n\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        if (outB) {\n            outB->assign(M, 0);\n            for (int eid = 0; eid < M; eid++) {\n                if (alive[eid]) (*outB)[eid] = 1;\n            }\n        }\n\n        return cost;\n    }\n\n    ll steinerRootUnion(const vector<int> &terminals, vector<char> &outB) {\n        outB.assign(M, 0);\n        for (int t : terminals) {\n            if (t == 0) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevEdge[0][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[0][cur];\n            }\n        }\n        return pruneAlive(outB, terminals);\n    }\n\n    ll steinerSPH(const vector<int> &terminals, int startTerm, vector<char> &outB) {\n        outB.assign(M, 0);\n        if ((int)terminals.size() <= 1) return 0;\n\n        vector<char> inTree(N, 0), isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n        if (!isTerm[startTerm]) startTerm = 0;\n        inTree[startTerm] = 1;\n\n        while (true) {\n            ll bestD = INF;\n            int bestSrc = -1, bestTerm = -1;\n\n            for (int t : terminals) {\n                if (inTree[t]) continue;\n                for (int v = 0; v < N; v++) {\n                    if (!inTree[v]) continue;\n                    ll d = spDist[v][t];\n                    if (d < bestD) {\n                        bestD = d;\n                        bestSrc = v;\n                        bestTerm = t;\n                    }\n                }\n            }\n\n            if (bestTerm == -1) break;\n\n            int cur = bestTerm;\n            inTree[cur] = 1;\n            while (cur != bestSrc) {\n                int eid = prevEdge[bestSrc][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[bestSrc][cur];\n                inTree[cur] = 1;\n            }\n        }\n\n        return pruneAlive(outB, terminals);\n    }\n\n    ll steinerBestFinal(const int terminals[], int t, vector<char> &outB) {\n        outB.assign(M, 0);\n        if (t <= 1) return 0;\n\n        vector<char> bestB;\n        ll best = steinerKMB(terminals, t, &bestB);\n\n        vector<int> tv(terminals, terminals + t);\n\n        vector<char> b2;\n        ll c2 = steinerRootUnion(tv, b2);\n        if (c2 < best) {\n            best = c2;\n            bestB = b2;\n        }\n\n        int far = 0, near = 0;\n        ll farD = -1, nearD = INF;\n        for (int v : tv) {\n            ll d = spDist[0][v];\n            if (d > farD) farD = d, far = v;\n            if (v != 0 && d < nearD) nearD = d, near = v;\n        }\n\n        vector<int> starts = {0, far, near};\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int s : starts) {\n            vector<char> bs;\n            ll cs = steinerSPH(tv, s, bs);\n            if (cs < best) {\n                best = cs;\n                bestB = bs;\n            }\n        }\n\n        outB = move(bestB);\n        return best;\n    }\n\n    ll evaluateFast(const vector<char> &active) {\n        Key key = makeKey(active);\n        auto it = cacheFast.find(key);\n        if (it != cacheFast.end()) return it->second;\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) {\n            cacheFast.emplace(key, INF);\n            return INF;\n        }\n\n        ll power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge = steinerKMB(terminals, t, nullptr);\n        ll ret = (edge >= INF / 2 ? INF : power + edge);\n        cacheFast.emplace(key, ret);\n        return ret;\n    }\n\n    ll evaluateExactKMB(const vector<char> &active) {\n        Key key = makeKey(active);\n        auto it = cacheExact.find(key);\n        if (it != cacheExact.end()) return it->second;\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) {\n            cacheExact.emplace(key, INF);\n            return INF;\n        }\n\n        shrinkP(P, true);\n\n        ll power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge = steinerKMB(terminals, t, nullptr);\n        ll ret = (edge >= INF / 2 ? INF : power + edge);\n        cacheExact.emplace(key, ret);\n        return ret;\n    }\n\n    double initScore(int d, int st, double lambda) {\n        return 1.0 * d * d + lambda * (double)spDist[0][st];\n    }\n\n    vector<char> makeInitAssign(double lambda) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            int bestSt = cand[k][0].second;\n            double best = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < best) {\n                    best = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    vector<char> makeInitRepair(double lambda, const vector<int> &order) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            int k = order[idx];\n\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                if (active[pr.second]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double best = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < best) {\n                    best = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n\n        return active;\n    }\n\n    void repairActive(vector<char> &active, double lambda) {\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                if (active[pr.second]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double best = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < best) {\n                    best = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n    }\n\n    pair<vector<char>, ll> hillClimb1(vector<char> active, int maxIter, double endTime) {\n        ll cur = evaluateFast(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateFast(active);\n        }\n\n        for (int it = 0; it < maxIter && elapsed() < endTime; it++) {\n            ll best = cur;\n            int bestFlip = -1;\n\n            for (int i = 1; i < N; i++) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n\n            if (bestFlip == -1) break;\n            active[bestFlip] ^= 1;\n            cur = best;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> localSearchWithSwap(vector<char> active, double endTime) {\n        ll cur = evaluateFast(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateFast(active);\n        }\n\n        while (elapsed() < endTime) {\n            bool improved = false;\n\n            ll best = cur;\n            int bestFlip = -1;\n            for (int i = 1; i < N; i++) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n            if (bestFlip != -1) {\n                active[bestFlip] ^= 1;\n                cur = best;\n                improved = true;\n                continue;\n            }\n\n            vector<int> on, off;\n            on.reserve(N);\n            off.reserve(N);\n            for (int i = 1; i < N; i++) {\n                if (active[i]) on.push_back(i);\n                else off.push_back(i);\n            }\n            if (on.empty() || off.empty()) break;\n\n            ll bestSwap = cur;\n            int bi = -1, bj = -1;\n            long long pairs = 1LL * on.size() * off.size();\n\n            if (pairs <= 2600) {\n                for (int i : on) {\n                    if (elapsed() >= endTime) break;\n                    for (int j : off) {\n                        if (elapsed() >= endTime) break;\n                        active[i] ^= 1;\n                        active[j] ^= 1;\n                        ll c = evaluateFast(active);\n                        active[i] ^= 1;\n                        active[j] ^= 1;\n                        if (c < bestSwap) {\n                            bestSwap = c;\n                            bi = i; bj = j;\n                        }\n                    }\n                }\n            } else {\n                int trials = 2600;\n                for (int t = 0; t < trials && elapsed() < endTime; t++) {\n                    int i = on[rng() % on.size()];\n                    int j = off[rng() % off.size()];\n                    active[i] ^= 1;\n                    active[j] ^= 1;\n                    ll c = evaluateFast(active);\n                    active[i] ^= 1;\n                    active[j] ^= 1;\n                    if (c < bestSwap) {\n                        bestSwap = c;\n                        bi = i; bj = j;\n                    }\n                }\n            }\n\n            if (bi != -1) {\n                active[bi] ^= 1;\n                active[bj] ^= 1;\n                cur = bestSwap;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    bool initCoverCount(const vector<char> &active, vector<int> &cnt) {\n        cnt.assign(K, 0);\n        for (int i = 0; i < N; i++) {\n            if (!active[i]) continue;\n            for (int k : coverResidents[i]) cnt[k]++;\n        }\n        for (int k = 0; k < K; k++) {\n            if (cnt[k] == 0) return false;\n        }\n        return true;\n    }\n\n    bool canOff(int st, const vector<int> &cnt) const {\n        for (int k : coverResidents[st]) {\n            if (cnt[k] == 1) return false;\n        }\n        return true;\n    }\n\n    bool canSwap(int offSt, int onSt, const vector<int> &cnt) const {\n        for (int k : coverResidents[offSt]) {\n            if (cnt[k] == 1 && distSR[onSt][k] > 5000) return false;\n        }\n        return true;\n    }\n\n    void applyOn(int st, vector<char> &active, vector<int> &cnt) {\n        if (active[st]) return;\n        active[st] = 1;\n        for (int k : coverResidents[st]) cnt[k]++;\n    }\n\n    void applyOff(int st, vector<char> &active, vector<int> &cnt) {\n        if (!active[st]) return;\n        active[st] = 0;\n        for (int k : coverResidents[st]) cnt[k]--;\n    }\n\n    int pickOn(const vector<char> &active) {\n        for (int t = 0; t < 24; t++) {\n            int i = 1 + (rng() % (N - 1));\n            if (active[i]) return i;\n        }\n        for (int i = 1; i < N; i++) if (active[i]) return i;\n        return -1;\n    }\n\n    int pickOff(const vector<char> &active) {\n        for (int t = 0; t < 24; t++) {\n            int i = 1 + (rng() % (N - 1));\n            if (!active[i]) return i;\n        }\n        for (int i = 1; i < N; i++) if (!active[i]) return i;\n        return -1;\n    }\n\n    pair<vector<char>, ll> exactRefineState(vector<char> active, double endTime) {\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCount(active, cnt)) {\n            repairActive(active, 0.05);\n            initCoverCount(active, cnt);\n        }\n\n        ll cur = evaluateExactKMB(active);\n        if (cur >= INF / 2) return {active, cur};\n\n        while (elapsed() < endTime) {\n            bool improved = false;\n\n            // 1) remove first-improvement\n            vector<int> onList;\n            for (int i = 1; i < N; i++) if (active[i]) onList.push_back(i);\n            shuffle(onList.begin(), onList.end(), rng);\n\n            for (int i : onList) {\n                if (elapsed() >= endTime) break;\n                if (!canOff(i, cnt)) continue;\n\n                applyOff(i, active, cnt);\n                ll c = evaluateExactKMB(active);\n                if (c < cur) {\n                    cur = c;\n                    improved = true;\n                    break; // keep move\n                } else {\n                    applyOn(i, active, cnt);\n                }\n            }\n            if (improved) continue;\n\n            // 2) add first-improvement (sampled)\n            vector<int> offList;\n            for (int i = 1; i < N; i++) if (!active[i]) offList.push_back(i);\n            shuffle(offList.begin(), offList.end(), rng);\n            int addTrials = min<int>(16, offList.size());\n\n            for (int idx = 0; idx < addTrials && elapsed() < endTime; idx++) {\n                int i = offList[idx];\n                applyOn(i, active, cnt);\n                ll c = evaluateExactKMB(active);\n                if (c < cur) {\n                    cur = c;\n                    improved = true;\n                    break; // keep move\n                } else {\n                    applyOff(i, active, cnt);\n                }\n            }\n            if (improved) continue;\n\n            // 3) sampled swap\n            onList.clear();\n            offList.clear();\n            for (int i = 1; i < N; i++) {\n                if (active[i]) onList.push_back(i);\n                else offList.push_back(i);\n            }\n            if (onList.empty() || offList.empty()) break;\n\n            int swapTrials = min<ll>(40, 1LL * onList.size() * offList.size());\n            for (int tr = 0; tr < swapTrials && elapsed() < endTime; tr++) {\n                int i = onList[rng() % onList.size()];\n                int j = offList[rng() % offList.size()];\n                if (!canSwap(i, j, cnt)) continue;\n\n                applyOff(i, active, cnt);\n                applyOn(j, active, cnt);\n\n                ll c = evaluateExactKMB(active);\n                if (c < cur) {\n                    cur = c;\n                    improved = true;\n                    break; // keep move\n                } else {\n                    applyOff(j, active, cnt);\n                    applyOn(i, active, cnt);\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    Solution buildSolution(const vector<char> &active, bool fullShrink, bool strongEdge) {\n        Solution sol;\n        sol.P.assign(N, 0);\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) return sol;\n\n        shrinkP(P, fullShrink);\n\n        ll power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n\n        for (int i = 0; i < N; i++) {\n            sol.P[i] = P[i];\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge;\n        if (strongEdge) edge = steinerBestFinal(terminals, t, sol.B);\n        else edge = steinerKMB(terminals, t, &sol.B);\n\n        if (edge >= INF / 2) return sol;\n\n        sol.feasible = true;\n        sol.cost = power + edge;\n        return sol;\n    }\n\n    void solve() {\n        readInput();\n        startTime = chrono::steady_clock::now();\n\n        precomputeDistances();\n        precomputeShortestPaths();\n\n        cacheFast.reserve(1 << 15);\n        cacheExact.reserve(1 << 14);\n        cacheFast.max_load_factor(0.7f);\n        cacheExact.max_load_factor(0.7f);\n\n        vector<char> allOn(N, 1);\n        allOn[0] = 1;\n\n        ll bestFast = evaluateFast(allOn);\n        vector<char> bestActive = allOn;\n\n        vector<pair<ll, vector<char>>> pool;\n        pushPool(pool, allOn, bestFast, 12);\n\n        // init states\n        vector<int> ord(K), ordRev, ordRnd1, ordRnd2;\n        iota(ord.begin(), ord.end(), 0);\n        ordRev = ord;\n        reverse(ordRev.begin(), ordRev.end());\n        ordRnd1 = ord;\n        ordRnd2 = ord;\n        shuffle(ordRnd1.begin(), ordRnd1.end(), rng);\n        shuffle(ordRnd2.begin(), ordRnd2.end(), rng);\n\n        vector<vector<char>> inits;\n        addUniqueState(inits, allOn);\n\n        for (double lam : {0.00, 0.02, 0.05, 0.10, 0.20}) {\n            addUniqueState(inits, makeInitAssign(lam));\n        }\n        for (double lam : {0.00, 0.04, 0.10, 0.20}) {\n            addUniqueState(inits, makeInitRepair(lam, ord));\n            addUniqueState(inits, makeInitRepair(lam, ordRev));\n        }\n        addUniqueState(inits, makeInitRepair(0.08, ordRnd1));\n        addUniqueState(inits, makeInitRepair(0.12, ordRnd2));\n\n        const double T_INIT = 0.60;\n        const double T_SWAP = 0.95;\n        const double T_KICK = 1.45;\n        const double T_EXACT = 1.90;\n\n        for (auto st : inits) {\n            if (elapsed() >= T_INIT) break;\n            repairActive(st, 0.05);\n            auto res = hillClimb1(st, 14, T_INIT);\n            if (res.second < bestFast) {\n                bestFast = res.second;\n                bestActive = res.first;\n            }\n            pushPool(pool, res.first, res.second, 12);\n        }\n\n        if (elapsed() < T_SWAP) {\n            auto res = localSearchWithSwap(bestActive, T_SWAP);\n            if (res.second < bestFast) {\n                bestFast = res.second;\n                bestActive = res.first;\n            }\n            pushPool(pool, res.first, res.second, 12);\n        }\n\n        // random kicks + short climb\n        while (elapsed() < T_KICK) {\n            vector<char> trial;\n            if (!pool.empty() && (rng() % 100) < 70) {\n                int lim = min<int>(4, pool.size());\n                trial = pool[rng() % lim].second;\n            } else {\n                trial = bestActive;\n            }\n\n            int flips = 2 + (rng() % 4); // 2..5\n            for (int t = 0; t < flips; t++) {\n                int idx = 1 + (rng() % (N - 1));\n                trial[idx] ^= 1;\n            }\n            repairActive(trial, 0.08);\n\n            auto res = hillClimb1(trial, 8, T_KICK);\n            if (elapsed() < T_KICK && (rng() % 100) < 25) {\n                double lim = min(T_KICK, elapsed() + 0.03);\n                auto sw = localSearchWithSwap(res.first, lim);\n                if (sw.second < res.second) res = sw;\n            }\n\n            if (res.second < bestFast) {\n                bestFast = res.second;\n                bestActive = res.first;\n            }\n            pushPool(pool, res.first, res.second, 12);\n        }\n\n        // exact-ish endgame on elite pool\n        ll bestExactCost = evaluateExactKMB(bestActive);\n        vector<char> bestExactState = bestActive;\n\n        vector<vector<char>> eliteStates;\n        addUniqueState(eliteStates, bestActive);\n        for (int i = 0; i < (int)pool.size() && i < 6; i++) {\n            addUniqueState(eliteStates, pool[i].second);\n        }\n\n        vector<vector<char>> refinedStates;\n        for (int idx = 0; idx < (int)eliteStates.size() && elapsed() < T_EXACT; idx++) {\n            double remain = T_EXACT - elapsed();\n            if (remain <= 0.0) break;\n            double slice = min(0.10, remain);\n\n            auto res = exactRefineState(eliteStates[idx], elapsed() + slice);\n            refinedStates.push_back(res.first);\n            if (res.second < bestExactCost) {\n                bestExactCost = res.second;\n                bestExactState = res.first;\n            }\n        }\n\n        if (elapsed() < T_EXACT) {\n            auto res = exactRefineState(bestExactState, T_EXACT);\n            if (res.second < bestExactCost) {\n                bestExactCost = res.second;\n                bestExactState = res.first;\n            }\n            refinedStates.push_back(res.first);\n        }\n\n        // final candidate assembly\n        vector<vector<char>> finals;\n        addUniqueState(finals, bestActive);\n        addUniqueState(finals, bestExactState);\n        addUniqueState(finals, allOn);\n        for (auto &st : refinedStates) addUniqueState(finals, st);\n        for (int i = 0; i < (int)pool.size() && i < 10; i++) addUniqueState(finals, pool[i].second);\n\n        Solution bestSol;\n        for (auto &st : finals) {\n            if (elapsed() > 1.985) break;\n            auto sol = buildSolution(st, true, true);\n            if (sol.feasible && (!bestSol.feasible || sol.cost < bestSol.cost)) {\n                bestSol = move(sol);\n            }\n        }\n\n        if (!bestSol.feasible) {\n            auto sol = buildSolution(allOn, true, true);\n            if (sol.feasible) bestSol = move(sol);\n        }\n        if (!bestSol.feasible) {\n            auto sol = buildSolution(allOn, false, true);\n            if (sol.feasible) bestSol = move(sol);\n        }\n        if (!bestSol.feasible) {\n            bestSol.feasible = true;\n            bestSol.P.assign(N, 0);\n            bestSol.B.assign(M, 0);\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << bestSol.P[i];\n        }\n        cout << '\\n';\n\n        for (int j = 0; j < M; j++) {\n            if (j) cout << ' ';\n            cout << int(bestSol.B[j]);\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}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nusing Board = array<array<int, N>, N>;\n\nstruct Result {\n    vector<Move> ops;\n    int E = (int)1e9;\n};\n\nstatic inline bool same_unordered(const Move& a, const Move& b) {\n    return (a.x1 == b.x1 && a.y1 == b.y1 && a.x2 == b.x2 && a.y2 == b.y2) ||\n           (a.x1 == b.x2 && a.y1 == b.y2 && a.x2 == b.x1 && a.y2 == b.y1);\n}\n\nstatic vector<Move> compress_ops(const vector<Move>& ops) {\n    vector<Move> st;\n    st.reserve(ops.size());\n    for (const auto& mv : ops) {\n        if (!st.empty() && same_unordered(st.back(), mv)) st.pop_back();\n        else st.push_back(mv);\n    }\n    return st;\n}\n\nstatic Board mirror_board(const Board& b) {\n    Board m{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            m[x][y] = b[x][x - y];\n        }\n    }\n    return m;\n}\n\nstatic void unmirror_ops(vector<Move>& ops) {\n    for (auto& mv : ops) {\n        mv.y1 = mv.x1 - mv.y1;\n        mv.y2 = mv.x2 - mv.y2;\n    }\n}\n\nstatic inline int calcE(const Board& b) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int v = b[x][y];\n            if (v > b[x + 1][y]) ++E;\n            if (v > b[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nstatic inline void find_cone_min(const Board& a, int x, int y, int& bestv, int& sx, int& sy) {\n    bestv = INT_MAX;\n    sx = x; sy = y;\n    for (int r = x; r < N; ++r) {\n        int cmax = y + (r - x);\n        for (int c = y; c <= cmax; ++c) {\n            int v = a[r][c];\n            if (v < bestv) {\n                bestv = v;\n                sx = r; sy = c;\n            }\n        }\n    }\n}\n\n// mode: 0 asc, 1 desc, 2 edges-in, 3 center-out, 4 random\nstatic vector<int> fixed_order(int x, int mode, mt19937& rng) {\n    vector<int> ord(x + 1);\n    if (mode == 0) {\n        iota(ord.begin(), ord.end(), 0);\n    } else if (mode == 1) {\n        for (int i = 0; i <= x; ++i) ord[i] = x - i;\n    } else if (mode == 2) {\n        int l = 0, r = x, k = 0;\n        while (l <= r) {\n            ord[k++] = l++;\n            if (l <= r) ord[k++] = r--;\n        }\n    } else if (mode == 3) {\n        int k = 0;\n        int mid = x / 2;\n        ord[k++] = mid;\n        for (int d = 1; k <= x; ++d) {\n            int L = mid - d;\n            int R = mid + d;\n            if (L >= 0) ord[k++] = L;\n            if (k > x) break;\n            if (R <= x) ord[k++] = R;\n        }\n    } else {\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n    }\n    return ord;\n}\n\nstruct Stat {\n    int y, dep, val;\n};\n\n// mode: 5 dep asc, 6 dep desc, 7 min-val asc\nstatic vector<int> dynamic_order(const Board& a, int x, int mode) {\n    vector<Stat> st;\n    st.reserve(x + 1);\n    for (int y = 0; y <= x; ++y) {\n        int bestv, sx, sy;\n        find_cone_min(a, x, y, bestv, sx, sy);\n        st.push_back({y, sx - x, bestv});\n    }\n\n    if (mode == 5) {\n        sort(st.begin(), st.end(), [](const Stat& A, const Stat& B) {\n            if (A.dep != B.dep) return A.dep < B.dep;\n            if (A.val != B.val) return A.val < B.val;\n            return A.y < B.y;\n        });\n    } else if (mode == 6) {\n        sort(st.begin(), st.end(), [](const Stat& A, const Stat& B) {\n            if (A.dep != B.dep) return A.dep > B.dep;\n            if (A.val != B.val) return A.val < B.val;\n            return A.y < B.y;\n        });\n    } else {\n        sort(st.begin(), st.end(), [](const Stat& A, const Stat& B) {\n            if (A.val != B.val) return A.val < B.val;\n            if (A.dep != B.dep) return A.dep < B.dep;\n            return A.y < B.y;\n        });\n    }\n\n    vector<int> ord;\n    ord.reserve(x + 1);\n    for (auto& s : st) ord.push_back(s.y);\n    return ord;\n}\n\nstatic vector<int> build_order(const Board& a, int x, int mode, mt19937& rng) {\n    if (mode <= 4) return fixed_order(x, mode, rng);\n    if (mode <= 7) return dynamic_order(a, x, mode);\n    return fixed_order(x, 0, rng);\n}\n\nstatic inline bool choose_left_top(\n    const Board& a, int cx, int cy, int tx, int ty, int path_mode, mt19937& rng\n) {\n    int rem = cx - tx;\n    int delta = cy - ty;\n\n    bool canL = (delta > 0);      // (cx-1, cy-1)\n    bool canR = (delta < rem);    // (cx-1, cy)\n\n    if (canL && !canR) return true;\n    if (!canL && canR) return false;\n\n    int lv = a[cx - 1][cy - 1];\n    int rv = a[cx - 1][cy];\n\n    switch (path_mode) {\n        case 0: return true;\n        case 1: return false;\n        case 2: return (lv >= rv); // push larger up-neighbor down\n        case 3: return (lv <= rv);\n        case 4: {\n            int penL = 0, penR = 0;\n            if (cx + 1 < N) {\n                penL += (lv > a[cx + 1][cy]) ? 1 : 0;\n                penL += (lv > a[cx + 1][cy + 1]) ? 1 : 0;\n                penR += (rv > a[cx + 1][cy]) ? 1 : 0;\n                penR += (rv > a[cx + 1][cy + 1]) ? 1 : 0;\n            }\n            if (penL != penR) return penL < penR;\n            return (lv >= rv);\n        }\n        default:\n            return (rng() & 1);\n    }\n}\n\nstatic int run_top_row(\n    Board& a, int x, const vector<int>& ord, int path_mode, vector<Move>* out, mt19937& rng\n) {\n    int cost = 0;\n    for (int y : ord) {\n        int bestv, sx, sy;\n        find_cone_min(a, x, y, bestv, sx, sy);\n\n        int cx = sx, cy = sy;\n        while (cx > x) {\n            bool goL = choose_left_top(a, cx, cy, x, y, path_mode, rng);\n            int nx = cx - 1;\n            int ny = goL ? (cy - 1) : cy;\n            swap(a[cx][cy], a[nx][ny]);\n            if (out) out->push_back({cx, cy, nx, ny});\n            ++cost;\n            cx = nx; cy = ny;\n        }\n    }\n    return cost;\n}\n\nstatic int estimate_row_depth_sum(const Board& a, int x) {\n    if (x >= N) return 0;\n    int sum = 0;\n    for (int y = 0; y <= x; ++y) {\n        int bestv, sx, sy;\n        find_cone_min(a, x, y, bestv, sx, sy);\n        sum += (sx - x);\n    }\n    return sum;\n}\n\n// Repair (for E>0 candidates): local violating-edge swaps\nstatic void repair_heap(Board& a, vector<Move>& ops, int max_ops) {\n    while ((int)ops.size() < max_ops) {\n        int bx = -1, by = -1, dir = 0, best_gain = -1;\n        for (int x = 0; x < N - 1; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                int p = a[x][y];\n                int lv = a[x + 1][y];\n                int rv = a[x + 1][y + 1];\n                int ch = min(lv, rv);\n                if (p > ch) {\n                    int gain = p - ch;\n                    if (gain > best_gain) {\n                        best_gain = gain;\n                        bx = x;\n                        by = y;\n                        dir = (lv <= rv ? 0 : 1);\n                    }\n                }\n            }\n        }\n        if (bx < 0) break;\n        int nx = bx + 1;\n        int ny = by + dir;\n        swap(a[bx][by], a[nx][ny]);\n        ops.push_back({bx, by, nx, ny});\n    }\n}\n\nstatic Result run_topdown(const Board& init, bool mirror, int order_mode, int path_mode, mt19937& rng) {\n    Board a = mirror ? mirror_board(init) : init;\n    vector<Move> ops;\n    ops.reserve(7000);\n\n    int pm = path_mode;\n    if (order_mode >= 8 && pm == 5) pm = 2; // adaptive mode uses deterministic path\n\n    for (int x = 0; x < N; ++x) {\n        if (order_mode <= 7) {\n            vector<int> ord = build_order(a, x, order_mode, rng);\n            run_top_row(a, x, ord, pm, &ops, rng);\n        } else {\n            // Adaptive row order:\n            // mode 8: score = rowCost + 0.7 * nextRowEstimate\n            // mode 9: score = rowCost only\n            int alpha1000 = (order_mode == 8 ? 700 : 0);\n            int rand_cnt  = (order_mode == 8 ? 2 : 4);\n\n            vector<vector<int>> cands;\n            cands.reserve(16);\n\n            unordered_set<uint64_t> used;\n            used.reserve(32);\n\n            auto add_cand = [&](vector<int> ord) {\n                uint64_t h = 1469598103934665603ULL;\n                for (int v : ord) {\n                    h ^= (uint64_t)(v + 1);\n                    h *= 1099511628211ULL;\n                }\n                if (used.insert(h).second) cands.push_back(std::move(ord));\n            };\n\n            add_cand(fixed_order(x, 0, rng));\n            add_cand(fixed_order(x, 1, rng));\n            add_cand(fixed_order(x, 2, rng));\n            add_cand(fixed_order(x, 3, rng));\n            add_cand(dynamic_order(a, x, 5));\n            add_cand(dynamic_order(a, x, 6));\n            add_cand(dynamic_order(a, x, 7));\n            for (int t = 0; t < rand_cnt; ++t) add_cand(fixed_order(x, 4, rng));\n\n            long long bestScore = (1LL << 60);\n            int bestIdx = 0;\n            int bestRowCost = INT_MAX;\n\n            for (int i = 0; i < (int)cands.size(); ++i) {\n                Board tb = a;\n                int rowCost = run_top_row(tb, x, cands[i], pm, nullptr, rng);\n                int est = (alpha1000 == 0 || x + 1 >= N) ? 0 : estimate_row_depth_sum(tb, x + 1);\n                long long sc = 1000LL * rowCost + 1LL * alpha1000 * est;\n\n                if (sc < bestScore || (sc == bestScore && rowCost < bestRowCost)) {\n                    bestScore = sc;\n                    bestRowCost = rowCost;\n                    bestIdx = i;\n                }\n            }\n\n            run_top_row(a, x, cands[bestIdx], pm, &ops, rng);\n        }\n    }\n\n    int E = calcE(a);\n\n    // salvage slightly invalid candidates\n    if (E > 0 && (int)ops.size() < 9800) {\n        repair_heap(a, ops, min(10000, (int)ops.size() + 800));\n        E = calcE(a);\n    }\n\n    ops = compress_ops(ops);\n    if (mirror) unmirror_ops(ops);\n\n    Result r;\n    r.ops = std::move(ops);\n    r.E = E;\n    return r;\n}\n\nstatic inline void find_upcone_max(const Board& a, int x, int y, int& bestv, int& sx, int& sy) {\n    bestv = -1;\n    sx = x; sy = y;\n    for (int r = 0; r <= x; ++r) {\n        int d = x - r;\n        int cmin = max(0, y - d);\n        int cmax = min(r, y);\n        for (int c = cmin; c <= cmax; ++c) {\n            int v = a[r][c];\n            if (v > bestv) {\n                bestv = v;\n                sx = r; sy = c;\n            }\n        }\n    }\n}\n\nstatic Result run_bottomup(const Board& init, bool mirror, int order_mode, int path_mode, mt19937& rng) {\n    Board a = mirror ? mirror_board(init) : init;\n    vector<Move> ops;\n    ops.reserve(7000);\n\n    int om = order_mode;\n    if (om < 0 || om > 4) om = 0;\n\n    for (int x = N - 1; x >= 0; --x) {\n        vector<int> ord = fixed_order(x, om, rng);\n\n        for (int y : ord) {\n            int bestv, sx, sy;\n            find_upcone_max(a, x, y, bestv, sx, sy);\n\n            int cx = sx, cy = sy;\n            while (cx < x) {\n                int rem = x - cx;\n                int delta = y - cy;\n\n                bool canS = (delta <= rem - 1); // (cx+1, cy)\n                bool canP = (delta >= 1);       // (cx+1, cy+1)\n\n                bool goPlus;\n                if (canS && !canP) goPlus = false;\n                else if (!canS && canP) goPlus = true;\n                else {\n                    int sv = a[cx + 1][cy];\n                    int pv = a[cx + 1][cy + 1];\n                    switch (path_mode) {\n                        case 0: goPlus = false; break;\n                        case 1: goPlus = true; break;\n                        case 2: goPlus = (pv < sv); break; // smaller child up\n                        case 3: goPlus = (pv > sv); break;\n                        default: goPlus = (rng() & 1); break;\n                    }\n                }\n\n                int nx = cx + 1;\n                int ny = goPlus ? (cy + 1) : cy;\n                swap(a[cx][cy], a[nx][ny]);\n                ops.push_back({cx, cy, nx, ny});\n                cx = nx; cy = ny;\n            }\n        }\n    }\n\n    int E = calcE(a);\n    if (E > 0 && (int)ops.size() < 9800) {\n        repair_heap(a, ops, min(10000, (int)ops.size() + 900));\n        E = calcE(a);\n    }\n\n    ops = compress_ops(ops);\n    if (mirror) unmirror_ops(ops);\n\n    Result r;\n    r.ops = std::move(ops);\n    r.E = E;\n    return r;\n}\n\nstatic void add_pool(vector<Result>& pool, Result&& r, int pool_max = 12) {\n    if (r.E != 0) return;\n    if ((int)r.ops.size() > 10000) return;\n\n    if ((int)pool.size() < pool_max) {\n        pool.push_back(std::move(r));\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < (int)pool.size(); ++i) {\n        if (pool[i].ops.size() > pool[worst].ops.size()) worst = i;\n    }\n\n    if (r.ops.size() < pool[worst].ops.size()) {\n        pool[worst] = std::move(r);\n    }\n}\n\nstatic int calcE_after_ops(const Board& init, const vector<Move>& ops) {\n    Board b = init;\n    for (const auto& m : ops) {\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b);\n}\n\ntemplate<int M>\nstatic bool check_skip(const Board& init, const vector<Move>& ops, array<int, M> sk) {\n    sort(sk.begin(), sk.end());\n    Board b = init;\n    int p = 0;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (p < M && i == sk[p]) {\n            ++p;\n            continue;\n        }\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b) == 0;\n}\n\nstatic void prune_ops(\n    const Board& init,\n    vector<Move>& ops,\n    mt19937& rng,\n    const chrono::steady_clock::time_point& start,\n    double limit_sec\n) {\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start).count();\n    };\n\n    ops = compress_ops(ops);\n\n    // single deletion forward + backward\n    for (int pass = 0; pass < 1; ++pass) {\n        for (int i = 0; i < (int)ops.size(); ++i) {\n            if (elapsed() > limit_sec) return;\n            if (check_skip<1>(init, ops, array<int, 1>{i})) {\n                ops.erase(ops.begin() + i);\n                --i;\n            }\n        }\n        for (int i = (int)ops.size() - 1; i >= 0; --i) {\n            if (elapsed() > limit_sec) return;\n            if (check_skip<1>(init, ops, array<int, 1>{i})) {\n                ops.erase(ops.begin() + i);\n            }\n        }\n    }\n\n    // adjacent pair deletion\n    for (int i = 0; i + 1 < (int)ops.size(); ++i) {\n        if (elapsed() > limit_sec) return;\n        if (check_skip<2>(init, ops, array<int, 2>{i, i + 1})) {\n            ops.erase(ops.begin() + i, ops.begin() + i + 2);\n            i = max(-1, i - 2);\n        }\n    }\n\n    // random pair deletion\n    for (int t = 0; t < 700; ++t) {\n        if (elapsed() > limit_sec) return;\n        int n = (int)ops.size();\n        if (n < 2) break;\n        int i = (int)(rng() % n);\n        int j = (int)(rng() % n);\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n        if (check_skip<2>(init, ops, array<int, 2>{i, j})) {\n            ops.erase(ops.begin() + j);\n            ops.erase(ops.begin() + i);\n        }\n    }\n\n    // random triple deletion\n    for (int t = 0; t < 180; ++t) {\n        if (elapsed() > limit_sec) return;\n        int n = (int)ops.size();\n        if (n < 3) break;\n        int i = (int)(rng() % n);\n        int j = (int)(rng() % n);\n        int k = (int)(rng() % n);\n        if (i == j || j == k || i == k) continue;\n        array<int, 3> sk{i, j, k};\n        sort(sk.begin(), sk.end());\n        if (check_skip<3>(init, ops, sk)) {\n            ops.erase(ops.begin() + sk[2]);\n            ops.erase(ops.begin() + sk[1]);\n            ops.erase(ops.begin() + sk[0]);\n        }\n    }\n\n    // final single sweep\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (elapsed() > limit_sec) return;\n        if (check_skip<1>(init, ops, array<int, 1>{i})) {\n            ops.erase(ops.begin() + i);\n            --i;\n        }\n    }\n\n    ops = compress_ops(ops);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board init{};\n    uint64_t h = 1469598103934665603ULL;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n            h ^= (uint64_t)(init[x][y] + 1);\n            h *= 1099511628211ULL;\n        }\n    }\n\n    mt19937 rng((uint32_t)(h ^ (h >> 32) ^ 0x9e3779b9U));\n\n    using Clock = chrono::steady_clock;\n    const auto start = Clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(Clock::now() - start).count();\n    };\n\n    constexpr double SEARCH_T = 1.42;\n    constexpr double TOTAL_T  = 1.88;\n\n    vector<Result> pool;\n    pool.reserve(16);\n\n    // Safe baseline\n    add_pool(pool, run_topdown(init, false, 0, 2, rng));\n\n    // Deterministic top-down sweep (strong family \uc9d1\uc911)\n    vector<int> td_orders = {0, 1, 2, 3, 5, 6, 7, 8, 9, 4};\n    vector<int> td_paths  = {2, 4, 0, 1, 3};\n\n    bool stop = false;\n    for (int mir = 0; mir < 2 && !stop; ++mir) {\n        for (int om : td_orders) {\n            for (int pm : td_paths) {\n                if (elapsed() > SEARCH_T) { stop = true; break; }\n                add_pool(pool, run_topdown(init, (bool)mir, om, pm, rng));\n            }\n            if (stop) break;\n        }\n    }\n\n    // Light deterministic bottom-up\n    if (!stop) {\n        vector<int> bu_orders = {0, 1, 2, 3, 4};\n        vector<int> bu_paths  = {2, 0, 1, 3};\n        for (int mir = 0; mir < 2 && !stop; ++mir) {\n            for (int om : bu_orders) {\n                for (int pm : bu_paths) {\n                    if (elapsed() > SEARCH_T) { stop = true; break; }\n                    add_pool(pool, run_bottomup(init, (bool)mir, om, pm, rng));\n                }\n                if (stop) break;\n            }\n        }\n    }\n\n    // Random multi-start\n    while (elapsed() < SEARCH_T) {\n        int t = (int)(rng() % 100);\n        if (t < 88) {\n            bool mir = (rng() & 1);\n\n            int om;\n            int r = (int)(rng() % 100);\n            if (r < 35) om = 8;             // adaptive + lookahead\n            else if (r < 52) om = 9;        // adaptive row-only\n            else if (r < 67) om = 5 + (rng() % 3); // dynamic\n            else if (r < 92) om = (int)(rng() % 4); // fixed\n            else om = 4;                    // random row order\n\n            int pm;\n            int pr = (int)(rng() % 100);\n            if (pr < 56) pm = 2;\n            else if (pr < 80) pm = 4;\n            else if (pr < 90) pm = 0;\n            else if (pr < 98) pm = 1;\n            else pm = 5;\n\n            if (om >= 8 && pm == 5) pm = 2;\n\n            add_pool(pool, run_topdown(init, mir, om, pm, rng));\n        } else {\n            bool mir = (rng() & 1);\n            int om = (int)(rng() % 5);\n            int pm = (int)(rng() % 5);\n            add_pool(pool, run_bottomup(init, mir, om, pm, rng));\n        }\n    }\n\n    if (pool.empty()) {\n        pool.push_back(run_topdown(init, false, 0, 2, rng));\n    }\n\n    sort(pool.begin(), pool.end(), [](const Result& a, const Result& b) {\n        return a.ops.size() < b.ops.size();\n    });\n\n    Result best = pool[0];\n\n    // Prune top candidates\n    int prune_cnt = min((int)pool.size(), 4);\n    for (int i = 0; i < prune_cnt; ++i) {\n        if (elapsed() > TOTAL_T) break;\n        Result cand = pool[i];\n        prune_ops(init, cand.ops, rng, start, TOTAL_T);\n        cand.E = calcE_after_ops(init, cand.ops);\n        if (cand.E == 0 && cand.ops.size() < best.ops.size()) {\n            best = std::move(cand);\n        }\n    }\n\n    // Final extra prune on current best\n    if (elapsed() < TOTAL_T) {\n        Result cand = best;\n        prune_ops(init, cand.ops, rng, start, TOTAL_T);\n        cand.E = calcE_after_ops(init, cand.ops);\n        if (cand.E == 0 && cand.ops.size() < best.ops.size()) {\n            best = std::move(cand);\n        }\n    }\n\n    // Safety fallback\n    int finalE = calcE_after_ops(init, best.ops);\n    if (finalE != 0 || (int)best.ops.size() > 10000) {\n        Result fb = run_topdown(init, false, 0, 2, rng);\n        if (calcE_after_ops(init, fb.ops) == 0 && (int)fb.ops.size() <= 10000) {\n            best = std::move(fb);\n        }\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& m : best.ops) {\n        cout << m.x1 << ' ' << m.y1 << ' ' << m.x2 << ' ' << m.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos {\n    int r, c;\n};\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick(int n_ = 0) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int idx) const {\n        if (idx < 0) return 0;\n        int s = 0;\n        for (++idx; idx > 0; idx -= idx & -idx) s += bit[idx];\n        return s;\n    }\n};\n\nstatic inline bool bit_test(uint64_t lo, uint64_t hi, int b) {\n    if (b < 64) return (lo >> b) & 1ULL;\n    return (hi >> (b - 64)) & 1ULL;\n}\nstatic inline void bit_set(uint64_t& lo, uint64_t& hi, int b) {\n    if (b < 64) lo |= (1ULL << b);\n    else hi |= (1ULL << (b - 64));\n}\nstatic inline void bit_clear(uint64_t& lo, uint64_t& hi, int b) {\n    if (b < 64) lo &= ~(1ULL << b);\n    else hi &= ~(1ULL << (b - 64));\n}\nstatic inline int pop_below(uint64_t lo, uint64_t hi, int k) {\n    if (k <= 0) return 0;\n    if (k < 64) {\n        uint64_t mask = (1ULL << k) - 1ULL;\n        return __builtin_popcountll(lo & mask);\n    }\n    if (k == 64) {\n        return __builtin_popcountll(lo);\n    }\n    int kk = k - 64; // <= 16\n    uint64_t mask = (1ULL << kk) - 1ULL;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n}\ntemplate <class F>\nstatic inline void for_each_bit(uint64_t lo, uint64_t hi, F f) {\n    while (lo) {\n        int b = __builtin_ctzll(lo);\n        lo &= lo - 1;\n        f(b);\n    }\n    while (hi) {\n        int b = __builtin_ctzll(hi);\n        hi &= hi - 1;\n        f(b + 64);\n    }\n}\n\nstruct BeamState {\n    uint64_t rlo, rhi; // removed cells\n    uint64_t flo, fhi; // frontier\n    uint64_t llo, lhi; // removed labels\n    int cost;          // inversions among already removed in chosen order\n    int cross;         // unavoidable cross inversions (removed vs remaining)\n    int parent;\n    int mv;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    if (!(cin >> D >> N)) return 0;\n\n    const int er = 0;\n    const int ec = (D - 1) / 2;\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    auto inb = [&](int r, int c) -> bool {\n        return (0 <= r && r < D && 0 <= c && c < D);\n    };\n\n    // Build free cells (excluding entrance and obstacles)\n    vector<vector<int>> id(D, vector<int>(D, -1));\n    vector<Pos> cells;\n    for (int i = 0; i < D; i++) {\n        for (int j = 0; j < D; j++) {\n            if (i == er && j == ec) continue;\n            if (obstacle[i][j]) continue;\n            id[i][j] = (int)cells.size();\n            cells.push_back({i, j});\n        }\n    }\n\n    const int M = (int)cells.size();\n    const int ENT = M;\n\n    // Graph\n    vector<vector<int>> adj(M + 1);\n    vector<uint64_t> neiLo(M, 0), neiHi(M, 0);\n    vector<char> adjEnt(M, 0);\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = cells[i];\n        for (int d = 0; d < 4; d++) {\n            int nr = r + dr[d], nc = c + dc[d];\n            if (!inb(nr, nc) || obstacle[nr][nc]) continue;\n            if (nr == er && nc == ec) {\n                adj[i].push_back(ENT);\n                adj[ENT].push_back(i);\n                adjEnt[i] = 1;\n            } else {\n                int j = id[nr][nc];\n                if (j >= 0) {\n                    adj[i].push_back(j);\n                    if (j < 64) neiLo[i] |= (1ULL << j);\n                    else neiHi[i] |= (1ULL << (j - 64));\n                }\n            }\n        }\n    }\n\n    uint64_t entLo = 0, entHi = 0;\n    for (int i = 0; i < M; i++) {\n        if (adjEnt[i]) bit_set(entLo, entHi, i);\n    }\n\n    auto compute_articulation = [&](const vector<char>& active, vector<char>& isArt) {\n        vector<int> disc(M + 1, -1), low(M + 1, 0), par(M + 1, -1);\n        fill(isArt.begin(), isArt.end(), 0);\n        int timer = 0;\n\n        function<void(int)> dfs = [&](int u) {\n            disc[u] = low[u] = ++timer;\n            for (int v : adj[u]) {\n                if (v != ENT && !active[v]) continue;\n                if (disc[v] == -1) {\n                    par[v] = u;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (u != ENT && low[v] >= disc[u]) isArt[u] = 1;\n                } else if (v != par[u]) {\n                    low[u] = min(low[u], disc[v]);\n                }\n            }\n        };\n\n        dfs(ENT);\n    };\n\n    auto bfs_dist = [&](const vector<char>& active) -> vector<int> {\n        vector<int> dist(M, -1);\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            int du = (u == ENT ? 0 : dist[u]);\n\n            for (int v : adj[u]) {\n                if (v != ENT && !active[v]) continue;\n                if (vis[v]) continue;\n                vis[v] = 1;\n                if (v != ENT) dist[v] = du + 1;\n                q.push(v);\n            }\n        }\n        return dist;\n    };\n\n    // Dist on full graph\n    vector<char> allActive(M, 1);\n    vector<int> distStatic = bfs_dist(allActive);\n\n    // Must-before relation from full graph dominator-like test\n    vector<vector<unsigned char>> mustBefore(M, vector<unsigned char>(M, 0));\n    for (int ban = 0; ban < M; ban++) {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (v == ban) continue;\n                if (vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n            }\n        }\n\n        for (int v = 0; v < M; v++) {\n            if (v == ban) continue;\n            if (!vis[v]) mustBefore[ban][v] = 1;\n        }\n    }\n\n    // ---------- Structural priority by reverse peeling ----------\n    vector<char> alive(M, 1), isArt(M + 1, 0);\n    vector<int> peelStep(M, -1);\n\n    for (int step = 0; step < M; step++) {\n        compute_articulation(alive, isArt);\n        vector<int> dist = bfs_dist(alive);\n\n        int best = -1;\n        int bestD = -1;\n        int bestMan = -1;\n\n        for (int c = 0; c < M; c++) {\n            if (!alive[c]) continue;\n            if (isArt[c]) continue;\n\n            int d = dist[c];\n            int man = abs(cells[c].r - er) + abs(cells[c].c - ec);\n\n            if (best == -1 ||\n                d > bestD ||\n                (d == bestD && man > bestMan) ||\n                (d == bestD && man == bestMan &&\n                 (cells[c].r > cells[best].r ||\n                  (cells[c].r == cells[best].r && cells[c].c > cells[best].c)))) {\n                best = c;\n                bestD = d;\n                bestMan = man;\n            }\n        }\n\n        if (best == -1) {\n            for (int c = 0; c < M; c++) if (alive[c]) { best = c; break; }\n        }\n\n        peelStep[best] = step;\n        alive[best] = 0;\n    }\n\n    vector<int> prio(M);\n    for (int c = 0; c < M; c++) {\n        prio[c] = M - 1 - peelStep[c];\n    }\n\n    vector<int> orderByPrio(M);\n    iota(orderByPrio.begin(), orderByPrio.end(), 0);\n    sort(orderByPrio.begin(), orderByPrio.end(), [&](int a, int b) {\n        if (prio[a] != prio[b]) return prio[a] < prio[b];\n        if (cells[a].r != cells[b].r) return cells[a].r < cells[b].r;\n        return cells[a].c < cells[b].c;\n    });\n\n    // ---------- Online insertion ----------\n    vector<char> inU(M, 1);\n    vector<int> labelAt(M, -1);\n    vector<int> assigned;\n    assigned.reserve(M);\n\n    Fenwick unseen(M);\n    for (int x = 0; x < M; x++) unseen.add(x, 1);\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        if (!(cin >> t)) return 0;\n\n        int rem = M - step;\n        int qrank = unseen.sumPrefix(t - 1);\n\n        compute_articulation(inU, isArt);\n\n        vector<int> safe;\n        safe.reserve(rem);\n        for (int c = 0; c < M; c++) {\n            if (inU[c] && !isArt[c]) safe.push_back(c);\n        }\n        if (safe.empty()) {\n            for (int c = 0; c < M; c++) if (inU[c]) safe.push_back(c);\n        }\n\n        vector<int> remRank(M, -1);\n        int ridx = 0;\n        for (int c : orderByPrio) {\n            if (inU[c]) remRank[c] = ridx++;\n        }\n\n        bool low = (2 * qrank < rem);\n\n        auto better_tie = [&](int a, int b) -> bool {\n            if (b == -1) return true;\n            if (low) {\n                if (prio[a] != prio[b]) return prio[a] < prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] < distStatic[b];\n            } else {\n                if (prio[a] != prio[b]) return prio[a] > prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] > distStatic[b];\n            }\n            if (cells[a].r != cells[b].r) return cells[a].r < cells[b].r;\n            return cells[a].c < cells[b].c;\n        };\n\n        int best = -1;\n        long long bestScore = (1LL << 60);\n        int bestMand = INT_MAX;\n\n        for (int c : safe) {\n            int r = remRank[c];\n\n            int invPast = 0;\n            int mandBad = 0;\n\n            for (int a : assigned) {\n                int la = labelAt[a];\n\n                if (prio[a] < prio[c] && la > t) invPast++;\n                if (prio[a] > prio[c] && la < t) invPast++;\n\n                if (mustBefore[a][c] && la > t) mandBad++;\n                if (mustBefore[c][a] && t > la) mandBad++;\n            }\n\n            long long score = (long long)invPast + llabs((long long)r - qrank);\n\n            if (best == -1 ||\n                score < bestScore ||\n                (score == bestScore && mandBad < bestMand) ||\n                (score == bestScore && mandBad == bestMand && better_tie(c, best))) {\n                best = c;\n                bestScore = score;\n                bestMand = mandBad;\n            }\n        }\n\n        if (best == -1) {\n            for (int c = 0; c < M; c++) if (inU[c]) { best = c; break; }\n        }\n\n        inU[best] = 0;\n        labelAt[best] = t;\n        assigned.push_back(best);\n        unseen.add(t, -1);\n\n        cout << cells[best].r << ' ' << cells[best].c << '\\n' << flush;\n    }\n\n    // ---------- Offline unloading ----------\n    auto accessible = [&](int c, uint64_t rlo, uint64_t rhi) -> bool {\n        if (adjEnt[c]) return true;\n        if ((neiLo[c] & rlo) != 0ULL) return true;\n        if ((neiHi[c] & rhi) != 0ULL) return true;\n        return false;\n    };\n\n    auto verify_order = [&](const vector<int>& ord) -> bool {\n        if ((int)ord.size() != M) return false;\n        vector<char> used(M, 0);\n        uint64_t rlo = 0, rhi = 0;\n        for (int c : ord) {\n            if (c < 0 || c >= M || used[c]) return false;\n            if (!accessible(c, rlo, rhi)) return false;\n            used[c] = 1;\n            bit_set(rlo, rhi, c);\n        }\n        return true;\n    };\n\n    auto inversion_count = [&](const vector<int>& ord) -> long long {\n        Fenwick fw(M);\n        long long inv = 0;\n        int seen = 0;\n        for (int c : ord) {\n            int lab = labelAt[c];\n            int leq = fw.sumPrefix(lab);\n            inv += (long long)seen - leq;\n            fw.add(lab, 1);\n            seen++;\n        }\n        return inv;\n    };\n\n    auto greedy_order = [&]() -> vector<int> {\n        vector<int> ord;\n        ord.reserve(M);\n\n        uint64_t rlo = 0, rhi = 0;\n        uint64_t flo = entLo, fhi = entHi;\n\n        for (int depth = 0; depth < M; depth++) {\n            int best = -1;\n            for_each_bit(flo, fhi, [&](int c) {\n                if (best == -1 ||\n                    labelAt[c] < labelAt[best] ||\n                    (labelAt[c] == labelAt[best] && prio[c] < prio[best])) {\n                    best = c;\n                }\n            });\n\n            if (best == -1) {\n                for (int c = 0; c < M; c++) {\n                    if (!bit_test(rlo, rhi, c)) { best = c; break; }\n                }\n            }\n\n            ord.push_back(best);\n            bit_set(rlo, rhi, best);\n\n            bit_clear(flo, fhi, best);\n            flo |= neiLo[best];\n            fhi |= neiHi[best];\n            flo |= entLo;\n            fhi |= entHi;\n            flo &= ~rlo;\n            fhi &= ~rhi;\n        }\n\n        return ord;\n    };\n\n    auto run_beam = [&](int BEAM_WIDTH, bool useCrossLB) -> vector<int> {\n        vector<BeamState> pool;\n        pool.reserve(1 + (size_t)BEAM_WIDTH * (M + 2));\n\n        pool.push_back({0ULL, 0ULL, entLo, entHi, 0ULL, 0ULL, 0, 0, -1, -1});\n        vector<int> beam = {0};\n\n        for (int depth = 0; depth < M; depth++) {\n            vector<BeamState> nxt;\n            nxt.reserve((size_t)beam.size() * 12);\n\n            for (int sid : beam) {\n                const BeamState& st = pool[sid];\n\n                for_each_bit(st.flo, st.fhi, [&](int c) {\n                    BeamState nx;\n                    nx.rlo = st.rlo; nx.rhi = st.rhi;\n                    bit_set(nx.rlo, nx.rhi, c);\n\n                    nx.flo = st.flo; nx.fhi = st.fhi;\n                    bit_clear(nx.flo, nx.fhi, c);\n                    nx.flo |= neiLo[c];\n                    nx.fhi |= neiHi[c];\n                    nx.flo |= entLo;\n                    nx.fhi |= entHi;\n                    nx.flo &= ~nx.rlo;\n                    nx.fhi &= ~nx.rhi;\n\n                    nx.llo = st.llo; nx.lhi = st.lhi;\n                    int lab = labelAt[c];\n                    int removedSmaller = pop_below(st.llo, st.lhi, lab);\n                    nx.cost = st.cost + (depth - removedSmaller);\n                    nx.cross = st.cross + (lab - depth); // exact unavoidable cross update\n                    bit_set(nx.llo, nx.lhi, lab);\n\n                    nx.parent = sid;\n                    nx.mv = c;\n                    nxt.push_back(nx);\n                });\n            }\n\n            if (nxt.empty()) return {};\n\n            sort(nxt.begin(), nxt.end(), [](const BeamState& a, const BeamState& b) {\n                if (a.rlo != b.rlo) return a.rlo < b.rlo;\n                if (a.rhi != b.rhi) return a.rhi < b.rhi;\n                return a.cost < b.cost;\n            });\n\n            vector<BeamState> uniq;\n            uniq.reserve(nxt.size());\n            for (const auto& nd : nxt) {\n                if (uniq.empty() || nd.rlo != uniq.back().rlo || nd.rhi != uniq.back().rhi) {\n                    uniq.push_back(nd); // first one has minimum cost for this removed-set\n                }\n            }\n\n            auto eval = [&](const BeamState& s) -> int {\n                return s.cost + (useCrossLB ? s.cross : 0);\n            };\n\n            auto cmpEval = [&](const BeamState& a, const BeamState& b) -> bool {\n                int ea = eval(a), eb = eval(b);\n                if (ea != eb) return ea < eb;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.rlo != b.rlo) return a.rlo < b.rlo;\n                return a.rhi < b.rhi;\n            };\n\n            if ((int)uniq.size() > BEAM_WIDTH) {\n                nth_element(uniq.begin(), uniq.begin() + BEAM_WIDTH, uniq.end(), cmpEval);\n                uniq.resize(BEAM_WIDTH);\n            }\n            sort(uniq.begin(), uniq.end(), cmpEval);\n\n            beam.clear();\n            beam.reserve(uniq.size());\n            for (const auto& nd : uniq) {\n                pool.push_back(nd);\n                beam.push_back((int)pool.size() - 1);\n            }\n        }\n\n        if (beam.empty()) return {};\n\n        int bestSid = beam[0];\n        for (int sid : beam) {\n            if (pool[sid].cost < pool[bestSid].cost) bestSid = sid;\n        }\n\n        vector<int> ord;\n        ord.reserve(M);\n        while (bestSid != -1 && pool[bestSid].parent != -1) {\n            ord.push_back(pool[bestSid].mv);\n            bestSid = pool[bestSid].parent;\n        }\n        reverse(ord.begin(), ord.end());\n\n        if ((int)ord.size() != M) return {};\n        return ord;\n    };\n\n    auto local_improve_adjacent = [&](vector<int>& ord) {\n        if (!verify_order(ord)) return;\n\n        for (int iter = 0; iter < 160; iter++) {\n            bool changed = false;\n            uint64_t rlo = 0, rhi = 0;\n\n            for (int i = 0; i + 1 < M; i++) {\n                int a = ord[i], b = ord[i + 1];\n\n                if (labelAt[a] > labelAt[b]) {\n                    if (accessible(b, rlo, rhi)) {\n                        uint64_t lo2 = rlo, hi2 = rhi;\n                        bit_set(lo2, hi2, b);\n                        if (accessible(a, lo2, hi2)) {\n                            swap(ord[i], ord[i + 1]);\n                            changed = true;\n                            bit_set(rlo, rhi, b);\n                            continue;\n                        }\n                    }\n                }\n\n                bit_set(rlo, rhi, ord[i]);\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    const int BEAM_WIDTH = 2200;\n    vector<int> ordBeam = run_beam(BEAM_WIDTH, true);\n    if (ordBeam.empty() || !verify_order(ordBeam)) ordBeam = greedy_order();\n    local_improve_adjacent(ordBeam);\n    if (!verify_order(ordBeam)) ordBeam = greedy_order();\n\n    vector<int> ordGreedy = greedy_order();\n    local_improve_adjacent(ordGreedy);\n\n    long long invBeam = inversion_count(ordBeam);\n    long long invGreedy = inversion_count(ordGreedy);\n\n    vector<int> finalOrd = (invGreedy < invBeam ? ordGreedy : ordBeam);\n    if (!verify_order(finalOrd)) finalOrd = ordGreedy;\n\n    for (int c : finalOrd) {\n        cout << cells[c].r << ' ' << cells[c].c << '\\n';\n    }\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nconstexpr int NMAX = 50;\nconstexpr int CMAX = 101;\nconstexpr int INF = 1e9;\n\nstruct Problem {\n    int n = 0, m = 0;\n    array<array<int, NMAX>, NMAX> initGrid{};\n    array<int, CMAX> initCnt{};\n    array<array<int, CMAX>, CMAX> initEdgeCnt{};\n    array<array<bool, CMAX>, CMAX> targetAdj{};\n    array<bool, CMAX> canZero{};\n    array<int, CMAX> depth{};\n    array<int, CMAX> deg{};\n};\n\nstruct State {\n    const Problem* pb = nullptr;\n\n    array<array<int, NMAX>, NMAX> g{};\n    array<int, CMAX> cnt{};\n    array<array<int, CMAX>, CMAX> edgeCnt{};\n    int zeroCount = 0;\n\n    array<array<int, NMAX>, NMAX> vis{};\n    int visToken = 1;\n\n    vector<int> order;\n\n    State() = default;\n    explicit State(const Problem* p) { init(p); }\n\n    void init(const Problem* p) {\n        pb = p;\n        g = pb->initGrid;\n        cnt = pb->initCnt;\n        edgeCnt = pb->initEdgeCnt;\n        zeroCount = cnt[0];\n\n        for (auto& row : vis) row.fill(0);\n        visToken = 1;\n\n        order.resize(pb->n * pb->n);\n        iota(order.begin(), order.end(), 0);\n    }\n\n    inline bool in(int x, int y) const {\n        return (0 <= x && x < pb->n && 0 <= y && y < pb->n);\n    }\n\n    bool connected_after_remove(int ri, int rj, int color, int si, int sj) {\n        int need = cnt[color] - 1;\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        vis[si][sj] = visToken;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        if (reached == need) return true;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != color) continue;\n                if (vis[nx][ny] == visToken) continue;\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n                if (reached == need) return true;\n            }\n        }\n        return reached == need;\n    }\n\n    // For color 0: every remaining 0-cell must be reachable from at least one boundary 0-cell.\n    bool zero_connected_after_remove(int ri, int rj) {\n        int need = cnt[0] - 1;\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        int reached = 0;\n\n        for (int i = 0; i < pb->n; i++) {\n            for (int j = 0; j < pb->n; j++) {\n                if (i != 0 && i != pb->n - 1 && j != 0 && j != pb->n - 1) continue;\n                if (i == ri && j == rj) continue;\n                if (g[i][j] != 0) continue;\n                if (vis[i][j] == visToken) continue;\n                vis[i][j] = visToken;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached == 0) return false;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != 0) continue;\n                if (vis[nx][ny] == visToken) continue;\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n\n        return reached == need;\n    }\n\n    // General legal recolor: a = g[i][j] -> b, supports a==0 (for kick phase).\n    bool try_change(int i, int j, int b) {\n        int a = g[i][j];\n        if (a == b) return false;\n\n        // Non-zero colors must remain non-empty.\n        if (a > 0 && cnt[a] <= 1) return false;\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // New color connectivity local condition.\n        if (b == 0) {\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary) {\n                bool adj0 = false;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == 0) {\n                        adj0 = true;\n                        break;\n                    }\n                }\n                if (!adj0) return false;\n            }\n        } else {\n            bool adjb = false;\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + dx[dir], nj = j + dy[dir];\n                if (in(ni, nj) && g[ni][nj] == b) {\n                    adjb = true;\n                    break;\n                }\n            }\n            if (!adjb) return false;\n        }\n\n        // Edge count delta around (i,j).\n        int pu[10], pv[10], pd[10], psz = 0;\n        auto add_delta = [&](int x, int y, int d) {\n            if (x == y) return;\n            if (x > y) swap(x, y);\n            for (int t = 0; t < psz; t++) {\n                if (pu[t] == x && pv[t] == y) {\n                    pd[t] += d;\n                    return;\n                }\n            }\n            pu[psz] = x;\n            pv[psz] = y;\n            pd[psz] = d;\n            ++psz;\n        };\n\n        for (int dir = 0; dir < 4; dir++) {\n            int ni = i + dx[dir], nj = j + dy[dir];\n            int x = in(ni, nj) ? g[ni][nj] : 0; // outside\n            add_delta(a, x, -1);\n            add_delta(b, x, +1);\n        }\n\n        // Adjacency graph must match target exactly.\n        for (int t = 0; t < psz; t++) {\n            int u = pu[t], v = pv[t];\n            int nc = edgeCnt[u][v] + pd[t];\n            if (nc < 0) return false;\n            bool present = (nc > 0);\n            if (present != pb->targetAdj[u][v]) return false;\n        }\n\n        // Old color connectivity after removal.\n        if (a > 0) {\n            int rem = cnt[a] - 1;\n            if (rem > 0) {\n                int same = 0, si = -1, sj = -1;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == a) {\n                        ++same;\n                        if (si == -1) {\n                            si = ni;\n                            sj = nj;\n                        }\n                    }\n                }\n                if (same == 0) return false;\n                if (same >= 2 && rem > 1) {\n                    if (!connected_after_remove(i, j, a, si, sj)) return false;\n                }\n            }\n        } else {\n            int rem0 = cnt[0] - 1;\n            if (rem0 > 0) {\n                bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n                bool needBFS = true;\n                if (!boundary) {\n                    int adj0 = 0;\n                    for (int dir = 0; dir < 4; dir++) {\n                        int ni = i + dx[dir], nj = j + dy[dir];\n                        if (in(ni, nj) && g[ni][nj] == 0) ++adj0;\n                    }\n                    // Interior leaf removal is always safe.\n                    if (adj0 <= 1) needBFS = false;\n                }\n                if (needBFS) {\n                    if (!zero_connected_after_remove(i, j)) return false;\n                }\n            }\n        }\n\n        // Apply.\n        g[i][j] = b;\n        --cnt[a];\n        ++cnt[b];\n        if (a == 0) --zeroCount;\n        if (b == 0) ++zeroCount;\n        for (int t = 0; t < psz; t++) edgeCnt[pu[t]][pv[t]] += pd[t];\n\n        return true;\n    }\n\n    bool try_swap(int i, int j, int ni, int nj) {\n        int a = g[i][j], b = g[ni][nj];\n        if (a <= 0 || b <= 0 || a == b) return false;\n\n        if (try_change(i, j, b)) {\n            if (try_change(ni, nj, a)) return true;\n            (void)try_change(i, j, a); // rollback\n        }\n        if (try_change(ni, nj, a)) {\n            if (try_change(i, j, b)) return true;\n            (void)try_change(ni, nj, b); // rollback\n        }\n        return false;\n    }\n\n    // Main local improver (monotone in score except deletions).\n    int improve(const vector<int>& value, mt19937& rng, Clock::time_point deadline,\n                int maxPass, bool allowRecolor, int eqProb = 0, int upProb = 0) {\n        int totalChanges = 0;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (Clock::now() >= deadline) break;\n            bool changed = false;\n\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int t = 0; t < (int)order.size(); t++) {\n                if ((t & 127) == 0 && Clock::now() >= deadline) return totalChanges;\n\n                int idx = order[t];\n                int i = idx / pb->n;\n                int j = idx % pb->n;\n                int a = g[i][j];\n                if (a == 0) continue;\n\n                // Priority 1: delete to 0.\n                if (pb->canZero[a]) {\n                    if (try_change(i, j, 0)) {\n                        changed = true;\n                        ++totalChanges;\n                        continue;\n                    }\n                }\n\n                if (!allowRecolor) continue;\n\n                // Priority 2: recolor among non-zero neighbors.\n                int cand[4], k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b <= 0 || b == a) continue;\n\n                    bool ok = false;\n                    if (value[b] < value[a]) ok = true;\n                    else if (value[b] == value[a] && eqProb > 0 && (int)(rng() % eqProb) == 0) ok = true;\n                    else if (value[b] > value[a] && upProb > 0 && (int)(rng() % upProb) == 0) ok = true;\n                    if (!ok) continue;\n\n                    bool dup = false;\n                    for (int q = 0; q < k; q++) {\n                        if (cand[q] == b) {\n                            dup = true;\n                            break;\n                        }\n                    }\n                    if (!dup) cand[k++] = b;\n                }\n                if (k == 0) continue;\n\n                // randomize, then try low value first.\n                for (int x = 0; x < k; x++) {\n                    int r = x + (int)(rng() % (k - x));\n                    swap(cand[x], cand[r]);\n                }\n                for (int x = 1; x < k; x++) {\n                    int key = cand[x], y = x - 1;\n                    while (y >= 0 && value[cand[y]] > value[key]) {\n                        cand[y + 1] = cand[y];\n                        --y;\n                    }\n                    cand[y + 1] = key;\n                }\n\n                for (int q = 0; q < k; q++) {\n                    if (try_change(i, j, cand[q])) {\n                        changed = true;\n                        ++totalChanges;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return totalChanges;\n    }\n\n    // Aggressive delete saturation.\n    int greedy_delete_queue(mt19937& rng, Clock::time_point deadline, int maxPop) {\n        int total = pb->n * pb->n;\n        vector<int> ids(total);\n        iota(ids.begin(), ids.end(), 0);\n        shuffle(ids.begin(), ids.end(), rng);\n\n        deque<int> dq;\n        vector<unsigned char> inq(total, 0);\n        for (int id : ids) {\n            dq.push_back(id);\n            inq[id] = 1;\n        }\n\n        int pops = 0, changes = 0;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        auto push_if_needed = [&](int x, int y) {\n            if (!in(x, y)) return;\n            int id = x * pb->n + y;\n            if (!inq[id]) {\n                inq[id] = 1;\n                dq.push_back(id);\n            }\n        };\n\n        while (!dq.empty() && pops < maxPop) {\n            if ((pops & 255) == 0 && Clock::now() >= deadline) break;\n            int id = dq.front();\n            dq.pop_front();\n            inq[id] = 0;\n            ++pops;\n\n            int i = id / pb->n;\n            int j = id % pb->n;\n            int a = g[i][j];\n            if (a == 0 || !pb->canZero[a]) continue;\n\n            bool near0 = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!near0) {\n                for (int dir = 0; dir < 4; dir++) {\n                    int ni = i + dx[dir], nj = j + dy[dir];\n                    if (in(ni, nj) && g[ni][nj] == 0) {\n                        near0 = true;\n                        break;\n                    }\n                }\n            }\n            if (!near0) continue;\n\n            if (try_change(i, j, 0)) {\n                ++changes;\n                push_if_needed(i, j);\n                for (int dir = 0; dir < 4; dir++) {\n                    push_if_needed(i + dx[dir], j + dy[dir]);\n                }\n            }\n        }\n        return changes;\n    }\n\n    // Score-neutral perturbation (mostly nonzero recolor/swap).\n    int random_neutral_moves(mt19937& rng, Clock::time_point deadline, int steps) {\n        int success = 0;\n        int total = pb->n * pb->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 s = 0; s < steps; s++) {\n            if ((s & 63) == 0 && Clock::now() >= deadline) break;\n\n            for (int rep = 0; rep < 8; rep++) {\n                int idx = (int)(rng() % total);\n                int i = idx / pb->n;\n                int j = idx % pb->n;\n                int a = g[i][j];\n                if (a <= 0) continue;\n\n                int dirs[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b <= 0 || b == a) continue;\n                    dirs[k++] = d;\n                }\n                if (k == 0) continue;\n\n                int d = dirs[(int)(rng() % k)];\n                int ni = i + dx[d], nj = j + dy[d];\n                int b = g[ni][nj];\n\n                int op = (int)(rng() % 100);\n                bool ok = false;\n                if (op < 28) ok = try_swap(i, j, ni, nj);\n                else if (op < 68) ok = try_change(i, j, b);\n                else ok = try_change(ni, nj, a);\n\n                if (ok) ++success;\n                break;\n            }\n        }\n\n        return success;\n    }\n\n    // Score-decreasing kick (0 -> nonzero), used only as perturbation.\n    int random_expand_moves(mt19937& rng, Clock::time_point deadline, int attempts) {\n        int success = 0;\n        int total = pb->n * pb->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 t = 0; t < attempts; t++) {\n            if ((t & 63) == 0 && Clock::now() >= deadline) break;\n\n            int idx = (int)(rng() % total);\n            int i = idx / pb->n;\n            int j = idx % pb->n;\n            if (g[i][j] != 0) continue;\n\n            int cand[4], k = 0;\n            for (int dir = 0; dir < 4; dir++) {\n                int ni = i + dx[dir], nj = j + dy[dir];\n                if (!in(ni, nj)) continue;\n                int b = g[ni][nj];\n                if (b <= 0) continue;\n\n                bool dup = false;\n                for (int q = 0; q < k; q++) {\n                    if (cand[q] == b) {\n                        dup = true;\n                        break;\n                    }\n                }\n                if (!dup) cand[k++] = b;\n            }\n            if (k == 0) continue;\n\n            for (int x = 0; x < k; x++) {\n                int r = x + (int)(rng() % (k - x));\n                swap(cand[x], cand[r]);\n            }\n\n            for (int q = 0; q < k; q++) {\n                if (try_change(i, j, cand[q])) {\n                    ++success;\n                    break;\n                }\n            }\n        }\n\n        return success;\n    }\n};\n\nstatic vector<int> build_value(const Problem& pb, const State& st, int mode, mt19937& rng, int maxDepth) {\n    vector<int> value(pb.m + 1, 0);\n    value[0] = -1;\n\n    vector<int> cols(pb.m);\n    for (int i = 0; i < pb.m; i++) cols[i] = i + 1;\n    shuffle(cols.begin(), cols.end(), rng);\n\n    vector<int> prio(pb.m + 1, 0);\n    for (int i = 0; i < pb.m; i++) prio[cols[i]] = i;\n\n    for (int c = 1; c <= pb.m; c++) {\n        switch (mode) {\n            case 0: // depth\n                value[c] = pb.depth[c] * 10000 + prio[c];\n                break;\n            case 1: // random\n                value[c] = prio[c];\n                break;\n            case 2: // reverse depth\n                value[c] = (maxDepth - pb.depth[c]) * 10000 + prio[c];\n                break;\n            case 3: // canZero-biased\n                value[c] = (pb.canZero[c] ? 0 : 250000) + pb.depth[c] * 1400 + prio[c];\n                break;\n            case 4: // degree-biased\n                value[c] = (pb.m - pb.deg[c]) * 5000 + pb.depth[c] * 60 + prio[c];\n                break;\n            case 5: // shrink large colors\n                value[c] = st.cnt[c] * 900 + pb.depth[c] * 40 + prio[c];\n                break;\n            case 6: // mixed\n                value[c] = (pb.canZero[c] ? st.cnt[c] * 300 : 120000 + st.cnt[c] * 250)\n                         + pb.depth[c] * 100 + prio[c];\n                break;\n            default: // grow large colors (opposite pressure)\n                value[c] = (2500 - st.cnt[c]) * 700 + pb.depth[c] * 20 + prio[c];\n                break;\n        }\n    }\n    return value;\n}\n\nbool validate_solution(const State& st) {\n    const Problem& pb = *st.pb;\n    int n = pb.n, m = pb.m;\n\n    array<int, CMAX> realCnt{};\n    realCnt.fill(0);\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (c < 0 || c > m) return false;\n            ++realCnt[c];\n        }\n    }\n    if (realCnt != st.cnt) return false;\n\n    array<array<bool, CMAX>, CMAX> adj{};\n    for (auto& row : adj) row.fill(false);\n\n    auto add_adj = [&](int a, int b) {\n        if (a == b) return;\n        adj[a][b] = adj[b][a] = true;\n    };\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (i + 1 < n) add_adj(c, st.g[i + 1][j]);\n            if (j + 1 < n) add_adj(c, st.g[i][j + 1]);\n            if (i == 0) add_adj(0, c);\n            if (i == n - 1) add_adj(0, c);\n            if (j == 0) add_adj(0, c);\n            if (j == n - 1) add_adj(0, c);\n        }\n    }\n\n    for (int u = 0; u <= m; u++) {\n        for (int v = u + 1; v <= m; v++) {\n            if (adj[u][v] != pb.targetAdj[u][v]) return false;\n        }\n    }\n\n    static const int dx[4] = {-1, 1, 0, 0};\n    static const int dy[4] = {0, 0, -1, 1};\n    auto in = [&](int x, int y) { return (0 <= x && x < n && 0 <= y && y < n); };\n\n    array<array<int, NMAX>, NMAX> vis{};\n    for (auto& row : vis) row.fill(0);\n    int token = 1;\n\n    // Non-zero connectivity.\n    for (int color = 1; color <= m; color++) {\n        int si = -1, sj = -1;\n        for (int i = 0; i < n && si == -1; i++) {\n            for (int j = 0; j < n; j++) {\n                if (st.g[i][j] == color) {\n                    si = i; sj = j;\n                    break;\n                }\n            }\n        }\n        if (si == -1) return false;\n\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        vis[si][sj] = token;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != color) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[color]) return false;\n    }\n\n    // Zero connectivity via outside: every 0-cell must reach some boundary 0-cell.\n    if (realCnt[0] > 0) {\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                if (i != 0 && i != n - 1 && j != 0 && j != n - 1) continue;\n                if (st.g[i][j] != 0) continue;\n                if (vis[i][j] == token) continue;\n                vis[i][j] = token;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n            }\n        }\n        if (tail == 0) return false;\n\n        int reached = tail;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != 0) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem pb;\n    cin >> pb.n >> pb.m;\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            cin >> pb.initGrid[i][j];\n        }\n    }\n\n    pb.initCnt.fill(0);\n    for (auto& row : pb.initEdgeCnt) row.fill(0);\n    for (auto& row : pb.targetAdj) row.fill(false);\n    pb.canZero.fill(false);\n    pb.depth.fill(INF);\n    pb.deg.fill(0);\n\n    auto add_edge_count = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        pb.initEdgeCnt[a][b]++;\n    };\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            int c = pb.initGrid[i][j];\n            ++pb.initCnt[c];\n\n            if (i + 1 < pb.n) add_edge_count(c, pb.initGrid[i + 1][j]);\n            if (j + 1 < pb.n) add_edge_count(c, pb.initGrid[i][j + 1]);\n\n            if (i == 0) add_edge_count(0, c);\n            if (i == pb.n - 1) add_edge_count(0, c);\n            if (j == 0) add_edge_count(0, c);\n            if (j == pb.n - 1) add_edge_count(0, c);\n        }\n    }\n\n    for (int u = 0; u <= pb.m; u++) {\n        for (int v = u + 1; v <= pb.m; v++) {\n            if (pb.initEdgeCnt[u][v] > 0) {\n                pb.targetAdj[u][v] = pb.targetAdj[v][u] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= pb.m; c++) pb.canZero[c] = pb.targetAdj[0][c];\n\n    for (int c = 0; c <= pb.m; c++) {\n        int d = 0;\n        for (int to = 0; to <= pb.m; to++) {\n            if (c != to && pb.targetAdj[c][to]) ++d;\n        }\n        pb.deg[c] = d;\n    }\n\n    // BFS depth from 0 in target adjacency graph.\n    queue<int> q;\n    pb.depth[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        for (int to = 0; to <= pb.m; to++) {\n            if (!pb.targetAdj[v][to]) continue;\n            if (pb.depth[to] != INF) continue;\n            pb.depth[to] = pb.depth[v] + 1;\n            q.push(to);\n        }\n    }\n    for (int c = 0; c <= pb.m; c++) {\n        if (pb.depth[c] == INF) pb.depth[c] = 50;\n    }\n    int maxDepth = 1;\n    for (int c = 1; c <= pb.m; c++) maxDepth = max(maxDepth, pb.depth[c]);\n\n    mt19937 rng((uint32_t)chrono::high_resolution_clock::now().time_since_epoch().count());\n    auto deadline = Clock::now() + chrono::milliseconds(1930);\n\n    State initState(&pb);\n\n    State best = initState, second = initState, third = initState;\n    int bestScore = initState.zeroCount;\n    int secondScore = -INF, thirdScore = -INF;\n\n    auto update_elite = [&](const State& s) {\n        int sc = s.zeroCount;\n        auto lucky = [&]() { return ((rng() & 3u) == 0u); }; // occasionally keep equal-score diversity\n\n        if (sc > bestScore || (sc == bestScore && lucky())) {\n            third = second;\n            thirdScore = secondScore;\n            second = best;\n            secondScore = bestScore;\n            best = s;\n            bestScore = sc;\n        } else if (sc > secondScore || (sc == secondScore && lucky())) {\n            third = second;\n            thirdScore = secondScore;\n            second = s;\n            secondScore = sc;\n        } else if (sc > thirdScore || (sc == thirdScore && lucky())) {\n            third = s;\n            thirdScore = sc;\n        }\n    };\n\n    vector<int> dummy(pb.m + 1, 0);\n\n    auto local_opt = [&](State& st, int rounds, int polishLevel) {\n        for (int r = 0; r < rounds; r++) {\n            if (Clock::now() >= deadline) return;\n\n            int roll = (int)(rng() % 100);\n            int mode = 0;\n            if (roll < 27) mode = 0;\n            else if (roll < 44) mode = 3;\n            else if (roll < 57) mode = 5;\n            else if (roll < 69) mode = 1;\n            else if (roll < 79) mode = 4;\n            else if (roll < 88) mode = 6;\n            else if (roll < 95) mode = 7;\n            else mode = 2;\n\n            auto value = build_value(pb, st, mode, rng, maxDepth);\n\n            int passes = 8, eqProb = 6, upProb = 0;\n            switch (mode) {\n                case 0: passes = 11; eqProb = 8; upProb = 0;  break;\n                case 1: passes = 7;  eqProb = 3; upProb = 18; break;\n                case 2: passes = 6;  eqProb = 4; upProb = 10; break;\n                case 3: passes = 10; eqProb = 8; upProb = 0;  break;\n                case 4: passes = 8;  eqProb = 6; upProb = 12; break;\n                case 5: passes = 8;  eqProb = 6; upProb = 8;  break;\n                case 6: passes = 8;  eqProb = 6; upProb = 8;  break;\n                case 7: passes = 7;  eqProb = 5; upProb = 10; break;\n            }\n\n            st.improve(value, rng, deadline, passes, true, eqProb, upProb);\n\n            if ((r & 1) == 0) {\n                st.random_neutral_moves(rng, deadline, 8 + (int)(rng() % 20));\n            }\n\n            st.greedy_delete_queue(rng, deadline, 6000 + polishLevel * 2000);\n        }\n\n        st.improve(dummy, rng, deadline, 3 + polishLevel, false, 0, 0);\n        st.greedy_delete_queue(rng, deadline, 10000 + polishLevel * 3000);\n        st.improve(dummy, rng, deadline, 3, false, 0, 0);\n    };\n\n    update_elite(initState);\n\n    // Initial diversified seeds\n    if (Clock::now() < deadline) {\n        State s = initState;\n        local_opt(s, 6, 2);\n        update_elite(s);\n    }\n    if (Clock::now() < deadline) {\n        State s = initState;\n        s.random_neutral_moves(rng, deadline, 70);\n        local_opt(s, 5, 1);\n        update_elite(s);\n    }\n    if (Clock::now() < deadline) {\n        State s = initState;\n        s.random_expand_moves(rng, deadline, 90);\n        s.random_neutral_moves(rng, deadline, 40);\n        local_opt(s, 5, 1);\n        update_elite(s);\n    }\n\n    int stagnation = 0;\n\n    while (Clock::now() < deadline) {\n        State cand;\n\n        int pick = (int)(rng() % 100);\n        if (pick < 55) cand = best;\n        else if (pick < 80 && secondScore > -INF / 2) cand = second;\n        else if (pick < 92 && thirdScore > -INF / 2) cand = third;\n        else cand = initState;\n\n        int kick = (int)(rng() % 100);\n        if (kick < 55) {\n            cand.random_neutral_moves(rng, deadline, 20 + (int)(rng() % 60));\n        } else if (kick < 88) {\n            int attempts = 35 + (int)(rng() % 70) + min(90, stagnation * 3);\n            cand.random_expand_moves(rng, deadline, attempts);\n            cand.random_neutral_moves(rng, deadline, 10 + (int)(rng() % 30));\n        } else {\n            int attempts = 80 + (int)(rng() % 120) + min(140, stagnation * 5);\n            cand.random_expand_moves(rng, deadline, attempts);\n            cand.random_neutral_moves(rng, deadline, 40 + (int)(rng() % 70));\n        }\n\n        int rounds = 2 + (int)(rng() % 3);\n        int polish = 1;\n        if (stagnation > 8) {\n            rounds++;\n            polish = 2;\n        }\n        if (stagnation > 16) rounds++;\n\n        local_opt(cand, rounds, polish);\n\n        int prevBest = bestScore;\n        update_elite(cand);\n\n        if (bestScore > prevBest) stagnation = 0;\n        else stagnation++;\n\n        if (stagnation >= 20 && Clock::now() < deadline) {\n            State alt = best;\n            alt.random_expand_moves(rng, deadline, 160 + (int)(rng() % 160));\n            alt.random_neutral_moves(rng, deadline, 80 + (int)(rng() % 100));\n            local_opt(alt, 5, 2);\n\n            prevBest = bestScore;\n            update_elite(alt);\n            if (bestScore > prevBest) {\n                stagnation = 0;\n            } else {\n                State rst = initState;\n                local_opt(rst, 4, 1);\n                prevBest = bestScore;\n                update_elite(rst);\n                if (bestScore > prevBest) stagnation = 0;\n                else stagnation = 10;\n            }\n        }\n    }\n\n    State ans = best;\n    if (!validate_solution(ans)) {\n        if (secondScore > -INF / 2 && validate_solution(second)) ans = second;\n        else if (thirdScore > -INF / 2 && validate_solution(third)) ans = third;\n        else ans = initState;\n    }\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            if (j) cout << ' ';\n            cout << ans.g[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 = 0, D = 0, Q = 0;\n    int used = 0;\n    mt19937 rng;\n\n    // item-item comparison cache:\n    // 2: unknown, -1: a<b, 0: a=b, 1: a>b\n    vector<vector<int8_t>> cmp_cache;\n    vector<int> score_item; // wins-losses from fresh singleton comparisons\n\n    vector<double> harm;    // harmonic numbers\n\n    // current partition state\n    vector<int> assign;              // item -> bin\n    vector<vector<int>> bins;        // bin -> items\n    vector<double> bin_sum_est;      // estimated sum per bin\n\n    // estimated item info\n    vector<double> w_est;\n    vector<int> rank_pos;            // 0 = heaviest\n    double total_est = 0.0;\n\n    struct State {\n        vector<int> assign;\n        vector<vector<int>> bins;\n        vector<double> sum;\n    };\n\n    static int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 1, c = 0;\n        while (p < x) p <<= 1, ++c;\n        return c;\n    }\n\n    static int insertion_cost(int n) {\n        int c = 0;\n        for (int m = 1; m < n; ++m) c += ceil_log2_int(m + 1);\n        return c;\n    }\n\n    char ask_set(const vector<int>& L, const vector<int>& R) {\n        // judge requires both non-empty and disjoint\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n';\n        cout.flush();\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        if (s == \"-1\") exit(0);\n\n        ++used;\n        return s[0];\n    }\n\n    char ask_single_raw(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask_set(L, R);\n    }\n\n    // returns 1 if a>b, -1 if a<b, 0 equal\n    int cmp_item(int a, int b, bool update_score = true) {\n        int8_t v = cmp_cache[a][b];\n        if (v != 2) return (int)v;\n\n        char c = ask_single_raw(a, b);\n        int s = (c == '>') ? 1 : (c == '<' ? -1 : 0);\n\n        cmp_cache[a][b] = (int8_t)s;\n        cmp_cache[b][a] = (int8_t)(-s);\n\n        if (update_score) {\n            if (s > 0) { score_item[a]++; score_item[b]--; }\n            else if (s < 0) { score_item[a]--; score_item[b]++; }\n        }\n        return s;\n    }\n\n    vector<int> full_sort_items() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        shuffle(items.begin(), items.end(), rng);\n\n        vector<int> ord;\n        ord.reserve(N);\n\n        for (int x : items) {\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                int s = cmp_item(x, ord[mid], true); // x ? ord[mid]\n                if (s > 0) hi = mid;          // x heavier\n                else if (s < 0) lo = mid + 1; // x lighter\n                else { lo = mid; hi = mid; break; }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    vector<int> sort_group_exact(const vector<int>& g) {\n        vector<int> ord;\n        ord.reserve(g.size());\n        for (int x : g) {\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                int s = cmp_item(x, ord[mid], true);\n                if (s > 0) hi = mid;\n                else if (s < 0) lo = mid + 1;\n                else { lo = mid; hi = mid; break; }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    // Low-Q ranking: impact-prioritized partitioning + partial polishing.\n    vector<int> partial_rank_focus(int budget_end) {\n        vector<int> all(N);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n\n        vector<vector<int>> groups(1, all);\n        vector<char> exact(1, 0);\n\n        // Stage 1: split groups by pivot where impact is high (heavy-rank + size).\n        while (used < budget_end) {\n            int rem = budget_end - used;\n            int best_idx = -1;\n            double best_key = -1.0;\n\n            int pref = 0; // start rank index of group\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m >= 2 && m - 1 <= rem) {\n                    double rank_weight = harm[N] - harm[pref];\n                    double key = m * (rank_weight + 0.05);\n                    if (key > best_key) {\n                        best_key = key;\n                        best_idx = g;\n                    }\n                }\n                pref += m;\n            }\n            if (best_idx == -1) break;\n\n            vector<int> cur = groups[best_idx];\n            int m = (int)cur.size();\n            int pv = cur[uniform_int_distribution<int>(0, m - 1)(rng)];\n\n            vector<int> heavy, equalv, light;\n            equalv.push_back(pv);\n\n            for (int v : cur) {\n                if (v == pv) continue;\n                int s = cmp_item(v, pv, true);\n                if (s > 0) heavy.push_back(v);\n                else if (s < 0) light.push_back(v);\n                else equalv.push_back(v);\n            }\n\n            vector<vector<int>> repl;\n            vector<char> repl_exact;\n            if (!heavy.empty()) { repl.push_back(move(heavy)); repl_exact.push_back(0); }\n            if (!equalv.empty()) { repl.push_back(move(equalv)); repl_exact.push_back(0); }\n            if (!light.empty()) { repl.push_back(move(light)); repl_exact.push_back(0); }\n\n            groups.erase(groups.begin() + best_idx);\n            exact.erase(exact.begin() + best_idx);\n\n            groups.insert(groups.begin() + best_idx, repl.begin(), repl.end());\n            exact.insert(exact.begin() + best_idx, repl_exact.begin(), repl_exact.end());\n        }\n\n        // Stage 2: fully sort groups when affordable.\n        for (int g = 0; g < (int)groups.size(); ++g) {\n            int m = (int)groups[g].size();\n            if (m <= 1) { exact[g] = 1; continue; }\n            int need = insertion_cost(m);\n            if (used + need <= budget_end) {\n                groups[g] = sort_group_exact(groups[g]);\n                exact[g] = 1;\n            }\n        }\n\n        // Stage 3: leftover budget on unsorted impactful groups.\n        int stale = 0;\n        while (used < budget_end && stale < 3000) {\n            int best_idx = -1;\n            double best_key = -1.0;\n\n            int pref = 0;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (!exact[g] && m >= 2) {\n                    double rank_weight = harm[N] - harm[pref];\n                    double key = m * (rank_weight + 0.05);\n                    if (key > best_key) {\n                        best_key = key;\n                        best_idx = g;\n                    }\n                }\n                pref += m;\n            }\n            if (best_idx == -1) break;\n\n            auto& grp = groups[best_idx];\n            int m = (int)grp.size();\n            int a = grp[uniform_int_distribution<int>(0, m - 1)(rng)];\n            int b = a;\n            for (int t = 0; t < 8 && b == a; ++t) {\n                b = grp[uniform_int_distribution<int>(0, m - 1)(rng)];\n            }\n            if (a == b) { ++stale; continue; }\n\n            int before = used;\n            cmp_item(a, b, true);\n            if (used == before) ++stale;\n            else stale = 0;\n        }\n\n        // Flatten\n        vector<int> ord;\n        ord.reserve(N);\n        for (int g = 0; g < (int)groups.size(); ++g) {\n            if (exact[g]) {\n                for (int x : groups[g]) ord.push_back(x);\n            } else {\n                auto tmp = groups[g];\n                stable_sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n                    if (score_item[a] != score_item[b]) return score_item[a] > score_item[b];\n                    return a < b;\n                });\n                for (int x : tmp) ord.push_back(x);\n            }\n        }\n        return ord;\n    }\n\n    void build_est_from_order(const vector<int>& order) {\n        w_est.assign(N, 1.0);\n        rank_pos.assign(N, N - 1);\n\n        total_est = 0.0;\n        for (int pos = 0; pos < N; ++pos) {\n            int id = order[pos];\n            rank_pos[id] = pos;\n            // Exponential order-stat shape\n            double w = harm[N] - harm[pos];\n            w_est[id] = w;\n            total_est += w;\n        }\n    }\n\n    void init_lpt(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        for (int id : order) {\n            int best = 0;\n            for (int b = 1; b < D; ++b) {\n                if (bin_sum_est[b] < bin_sum_est[best] - 1e-12) best = b;\n                else if (abs(bin_sum_est[b] - bin_sum_est[best]) <= 1e-12 &&\n                         bins[b].size() < bins[best].size()) best = b;\n            }\n            assign[id] = best;\n            bins[best].push_back(id);\n            bin_sum_est[best] += w_est[id];\n        }\n    }\n\n    void init_snake(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        int per = max(1, 2 * D - 2);\n        for (int i = 0; i < N; ++i) {\n            int t = i % per;\n            int b = (t < D ? t : per - t);\n\n            int id = order[i];\n            assign[id] = b;\n            bins[b].push_back(id);\n            bin_sum_est[b] += w_est[id];\n        }\n    }\n\n    void move_item_g(int item, int to) {\n        int from = assign[item];\n        if (from == to) return;\n\n        auto& vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); ++i) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n\n        bins[to].push_back(item);\n        assign[item] = to;\n\n        bin_sum_est[from] -= w_est[item];\n        bin_sum_est[to] += w_est[item];\n    }\n\n    void swap_item_g(int i, int j) {\n        int a = assign[i], b = assign[j];\n        if (a == b) return;\n\n        auto& va = bins[a];\n        auto& vb = bins[b];\n\n        for (int& x : va) if (x == i) { x = j; break; }\n        for (int& x : vb) if (x == j) { x = i; break; }\n\n        assign[i] = b;\n        assign[j] = a;\n\n        double wi = w_est[i], wj = w_est[j];\n        bin_sum_est[a] += wj - wi;\n        bin_sum_est[b] += wi - wj;\n    }\n\n    inline double sq(double x) const { return x * x; }\n\n    double obj_sse() const {\n        double mean = total_est / D;\n        double s = 0.0;\n        for (int b = 0; b < D; ++b) s += sq(bin_sum_est[b] - mean);\n        return s;\n    }\n\n    void local_search_est(int iter_limit, bool allow_swap) {\n        double mean = total_est / D;\n\n        for (int iter = 0; iter < iter_limit; ++iter) {\n            double best_delta = -1e-12;\n            int type = 0;\n            int bi = -1, bj = -1, bt = -1;\n\n            // move\n            for (int i = 0; i < N; ++i) {\n                int a = assign[i];\n                if ((int)bins[a].size() <= 1) continue;\n                double wi = w_est[i];\n\n                for (int b = 0; b < D; ++b) {\n                    if (b == a) continue;\n                    double delta =\n                        sq(bin_sum_est[a] - wi - mean) +\n                        sq(bin_sum_est[b] + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        type = 1;\n                        bi = i;\n                        bt = b;\n                    }\n                }\n            }\n\n            // swap\n            if (allow_swap) {\n                for (int i = 0; i < N; ++i) {\n                    for (int j = i + 1; j < N; ++j) {\n                        int a = assign[i], b = assign[j];\n                        if (a == b) continue;\n\n                        double wi = w_est[i], wj = w_est[j];\n                        double delta =\n                            sq(bin_sum_est[a] - wi + wj - mean) +\n                            sq(bin_sum_est[b] - wj + wi - mean) -\n                            sq(bin_sum_est[a] - mean) -\n                            sq(bin_sum_est[b] - mean);\n\n                        if (delta < best_delta) {\n                            best_delta = delta;\n                            type = 2;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n            }\n\n            if (type == 0) break;\n            if (type == 1) move_item_g(bi, bt);\n            else swap_item_g(bi, bj);\n        }\n    }\n\n    State capture() const {\n        return State{assign, bins, bin_sum_est};\n    }\n\n    void restore(const State& st) {\n        assign = st.assign;\n        bins = st.bins;\n        bin_sum_est = st.sum;\n    }\n\n    char cmp_bins(int a, int b) {\n        return ask_set(bins[a], bins[b]);\n    }\n\n    char cmp_after_move(int h, int l, int x) {\n        vector<int> L;\n        L.reserve((int)bins[h].size() - 1);\n        for (int v : bins[h]) if (v != x) L.push_back(v);\n\n        vector<int> R = bins[l];\n        R.push_back(x);\n\n        return ask_set(L, R);\n    }\n\n    void reinsert_bin(vector<int>& ord, int b) {\n        int lo = 0, hi = (int)ord.size();\n        while (lo < hi && used < Q) {\n            int mid = (lo + hi) / 2;\n            char c = cmp_bins(b, ord[mid]);\n            if (c == '>') hi = mid;   // b heavier\n            else lo = mid + 1;\n        }\n        ord.insert(ord.begin() + lo, b);\n    }\n\n    void refine_high() {\n        int rem = Q - used;\n        int need = insertion_cost(D) + 8;\n        if (rem < need) return;\n\n        vector<int> ord;\n        ord.reserve(D);\n        for (int b = 0; b < D; ++b) {\n            if (used >= Q) return;\n            reinsert_bin(ord, b);\n        }\n\n        int guard = 0;\n        while (used < Q && guard < 10000) {\n            ++guard;\n\n            int h = -1;\n            for (int id : ord) {\n                if ((int)bins[id].size() > 1) {\n                    h = id;\n                    break;\n                }\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int i = (int)ord.size() - 1; i >= 0; --i) {\n                if (ord[i] != h) { l = ord[i]; break; }\n            }\n            if (l == -1) break;\n\n            char base = cmp_bins(h, l);\n            if (base == '=') break;\n            if (base == '<') swap(h, l);\n\n            if ((int)bins[h].size() <= 1) break;\n\n            vector<int> cand = bins[h];\n            // light -> heavy for binary search\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (rank_pos[a] != rank_pos[b]) return rank_pos[a] > rank_pos[b];\n                return a < b;\n            });\n\n            int m = (int)cand.size();\n            int lo = -1, hi = m; // lo: too light ('>'), hi: heavy enough ('<'/'=')\n\n            while (hi - lo > 1 && used < Q) {\n                int mid = (lo + hi) / 2;\n                int x = cand[mid];\n                char c = cmp_after_move(h, l, x);\n                if (c == '>') lo = mid;\n                else hi = mid;\n            }\n\n            if (lo == -1 && hi == m) break;\n\n            int chosen;\n            if (lo == -1) chosen = cand[hi];\n            else if (hi == m) chosen = cand[lo];\n            else {\n                double diff = bin_sum_est[h] - bin_sum_est[l];\n                double e1 = fabs(diff - 2.0 * w_est[cand[lo]]);\n                double e2 = fabs(diff - 2.0 * w_est[cand[hi]]);\n                chosen = (e1 <= e2 ? cand[lo] : cand[hi]);\n            }\n\n            move_item_g(chosen, l);\n\n            auto it = find(ord.begin(), ord.end(), h);\n            if (it != ord.end()) ord.erase(it);\n            it = find(ord.begin(), ord.end(), l);\n            if (it != ord.end()) ord.erase(it);\n\n            if (used >= Q) break;\n            reinsert_bin(ord, h);\n            if (used >= Q) break;\n            reinsert_bin(ord, l);\n        }\n    }\n\n    void refine_simple(int max_steps) {\n        int stall = 0;\n        int last_item = -1, last_from = -1, last_to = -1;\n\n        for (int step = 0; step < max_steps && used < Q && stall < 2 * D + 6; ++step) {\n            int h = -1;\n            for (int b = 0; b < D; ++b) {\n                if ((int)bins[b].size() <= 1) continue;\n                if (h == -1 || bin_sum_est[b] > bin_sum_est[h]) h = b;\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int b = 0; b < D; ++b) {\n                if (b == h) continue;\n                if (l == -1 || bin_sum_est[b] < bin_sum_est[l]) l = b;\n            }\n            if (l == -1) break;\n\n            char c = cmp_bins(h, l);\n            if (c == '=') {\n                double avg = 0.5 * (bin_sum_est[h] + bin_sum_est[l]);\n                bin_sum_est[h] = avg;\n                bin_sum_est[l] = avg;\n                ++stall;\n                continue;\n            }\n            if (c == '<') {\n                swap(h, l);\n                if (bin_sum_est[h] < bin_sum_est[l]) {\n                    swap(bin_sum_est[h], bin_sum_est[l]);\n                }\n            }\n\n            if ((int)bins[h].size() <= 1) {\n                ++stall;\n                continue;\n            }\n\n            double diff = max(0.0, bin_sum_est[h] - bin_sum_est[l]);\n            int chosen = -1;\n            double best = 1e100;\n\n            for (int x : bins[h]) {\n                if (x == last_item && h == last_to && l == last_from) continue;\n                double v = fabs(diff - 2.0 * w_est[x]);\n                if (v < best) {\n                    best = v;\n                    chosen = x;\n                }\n            }\n            if (chosen == -1) {\n                for (int x : bins[h]) {\n                    if (chosen == -1 || w_est[x] < w_est[chosen]) chosen = x;\n                }\n            }\n            if (chosen == -1) {\n                ++stall;\n                continue;\n            }\n\n            move_item_g(chosen, l);\n            last_item = chosen;\n            last_from = h;\n            last_to = l;\n            stall = 0;\n        }\n    }\n\n    void fill_dummy() {\n        while (used < Q) {\n            ask_single_raw(0, 1);\n        }\n    }\n\n    void solve() {\n        if (!(cin >> N >> D >> Q)) return;\n\n        uint64_t seed = 0x9e3779b97f4a7c15ULL;\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)D * 9176ULL;\n        seed ^= (uint64_t)Q * 1315423911ULL;\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n\n        cmp_cache.assign(N, vector<int8_t>(N, 2));\n        for (int i = 0; i < N; ++i) cmp_cache[i][i] = 0;\n        score_item.assign(N, 0);\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        int full_cost = insertion_cost(N);\n        int rank_start = used;\n\n        vector<int> order;\n        if (Q >= full_cost) {\n            order = full_sort_items();\n        } else {\n            int reserve = min(max(4, D / 2), max(0, Q - (int)(1.7 * N)));\n            reserve = min(reserve, Q / 6);\n            int budget_end = Q - reserve;\n            if (budget_end < used) budget_end = used;\n\n            order = partial_rank_focus(budget_end);\n        }\n\n        int rank_used = used - rank_start;\n\n        // sanitize permutation\n        {\n            vector<int> seen(N, 0), clean;\n            clean.reserve(N);\n            for (int x : order) {\n                if (0 <= x && x < N && !seen[x]) {\n                    seen[x] = 1;\n                    clean.push_back(x);\n                }\n            }\n            for (int i = 0; i < N; ++i) if (!seen[i]) clean.push_back(i);\n            order.swap(clean);\n        }\n\n        build_est_from_order(order);\n        double conf = min(1.0, (double)rank_used / max(1, full_cost));\n\n        // Multi-start init: LPT vs snake\n        int iter = 170 + (int)(90.0 * conf);\n        bool allow_swap = true;\n\n        State best_state;\n        double best_obj = 1e100;\n\n        init_lpt(order);\n        local_search_est(iter, allow_swap);\n        best_state = capture();\n        best_obj = obj_sse();\n\n        init_snake(order);\n        local_search_est(iter, allow_swap);\n        double obj2 = obj_sse();\n        if (obj2 < best_obj) {\n            best_obj = obj2;\n            best_state = capture();\n        }\n\n        restore(best_state);\n\n        int rem = Q - used;\n        if (rem > 0) {\n            if (rem >= insertion_cost(D) + 10 && conf > 0.82) {\n                refine_high();\n                if (used < Q) refine_simple(min(D, Q - used));\n            } else {\n                refine_simple(min(Q - used, 3 * D + 10));\n            }\n        }\n\n        fill_dummy();\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << assign[i];\n        }\n        cout << '\\n';\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 200;\nconstexpr int MAXM = 10;\nconstexpr long long INF64 = (1LL << 60);\n\nint N, M;\n\nstruct Params {\n    int w_cross;\n    int w_near;\n    int near_th;\n    int w_height;\n    int w_top;\n    int w_empty;\n    int w_boundary;\n\n    bool operator==(const Params& o) const {\n        return w_cross == o.w_cross &&\n               w_near == o.w_near &&\n               near_th == o.near_th &&\n               w_height == o.w_height &&\n               w_top == o.w_top &&\n               w_empty == o.w_empty &&\n               w_boundary == o.w_boundary;\n    }\n};\n\nstruct State {\n    int len[MAXM];\n    int box[MAXM][MAXN]; // bottom -> top\n    int stk[MAXN + 1];   // box value -> stack id, -1 if removed\n    int pos[MAXN + 1];   // index in stack\n};\n\nstruct SegInfo {\n    int total;\n    int bottom;\n    int pref[MAXN + 1]; // # in segment <= v\n};\n\nstruct Result {\n    long long energy = INF64;\n    vector<pair<int, int>> ops;\n    Params param{};\n};\n\nstruct Trial {\n    long long e;\n    Params p;\n};\n\ninline void move_suffix(State& st, int src, int start, int dst) {\n    int k = st.len[src] - start;\n    int base = st.len[dst];\n    for (int i = 0; i < k; ++i) {\n        int v = st.box[src][start + i];\n        st.box[dst][base + i] = v;\n        st.stk[v] = dst;\n        st.pos[v] = base + i;\n    }\n    st.len[dst] += k;\n    st.len[src] = start;\n}\n\ninline void remove_target(State& st, int x) {\n    int s = st.stk[x];\n    st.len[s]--;\n    st.stk[x] = -1;\n    st.pos[x] = -1;\n}\n\ninline SegInfo build_seg_info(const State& st, int src, int start) {\n    SegInfo sg{};\n    sg.total = st.len[src] - start;\n    sg.bottom = st.box[src][start];\n\n    int freq[MAXN + 1];\n    memset(freq, 0, sizeof(freq));\n    for (int i = start; i < st.len[src]; ++i) {\n        ++freq[st.box[src][i]];\n    }\n\n    sg.pref[0] = 0;\n    for (int v = 1; v <= N; ++v) {\n        sg.pref[v] = sg.pref[v - 1] + freq[v];\n    }\n    return sg;\n}\n\ninline long long score_dest(\n    const State& st, int dst, int x, const Params& p, const SegInfo& sg\n) {\n    long long cross = 0;\n    long long nearv = 0;\n\n    for (int j = 0; j < st.len[dst]; ++j) {\n        int z = st.box[dst][j];\n        int cnt = sg.total - sg.pref[z]; // # moved boxes > z\n        if (cnt <= 0) continue;\n        cross += cnt;\n\n        int dz = z - x;\n        if (dz <= p.near_th) {\n            nearv += 1LL * cnt * (p.near_th + 1 - dz);\n        }\n    }\n\n    long long sc = 0;\n    sc += 1LL * p.w_cross * cross;\n    sc += 1LL * p.w_near * nearv;\n    sc += 1LL * p.w_height * st.len[dst];\n\n    if (st.len[dst] == 0) {\n        sc -= p.w_empty;\n    } else {\n        int top = st.box[dst][st.len[dst] - 1];\n        sc -= 1LL * p.w_top * top;\n        if (sg.bottom > top) {\n            sc += 1LL * p.w_boundary * (sg.bottom - top);\n        }\n    }\n    return sc;\n}\n\ninline int choose_best_dest(\n    const State& st, int src, int start, int x, const Params& p\n) {\n    SegInfo sg = build_seg_info(st, src, start);\n\n    long long bestSc = INF64;\n    int bestD = -1;\n\n    for (int d = 0; d < M; ++d) {\n        if (d == src) continue;\n        long long sc = score_dest(st, d, x, p, sg);\n\n        if (sc < bestSc ||\n            (sc == bestSc && (bestD == -1 ||\n                              st.len[d] < st.len[bestD] ||\n                              (st.len[d] == st.len[bestD] && d < bestD)))) {\n            bestSc = sc;\n            bestD = d;\n        }\n    }\n    return bestD;\n}\n\ninline int rank_destinations(\n    const State& st, int src, int start, int x, const Params& p,\n    array<pair<long long, int>, MAXM>& cand\n) {\n    SegInfo sg = build_seg_info(st, src, start);\n    int cnt = 0;\n    for (int d = 0; d < M; ++d) {\n        if (d == src) continue;\n        cand[cnt++] = {score_dest(st, d, x, p, sg), d};\n    }\n\n    sort(cand.begin(), cand.begin() + cnt,\n         [&](const auto& a, const auto& b) {\n             if (a.first != b.first) return a.first < b.first;\n             if (st.len[a.second] != st.len[b.second]) {\n                 return st.len[a.second] < st.len[b.second];\n             }\n             return a.second < b.second;\n         });\n    return cnt;\n}\n\nlong long simulate_base(State& st, int nextX, const Params& p, long long cutoff) {\n    long long energy = 0;\n    for (int x = nextX; x <= N; ++x) {\n        int s = st.stk[x];\n        int pos = st.pos[x];\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int d = choose_best_dest(st, s, start, x, p);\n            move_suffix(st, s, start, d);\n            energy += k + 1;\n            if (energy > cutoff) return energy;\n        }\n        remove_target(st, x);\n    }\n    return energy;\n}\n\nlong long solve_run(\n    const State& init, const Params& p, int candK,\n    vector<pair<int, int>>* outOps\n) {\n    State st = init;\n    long long energy = 0;\n\n    if (outOps) {\n        outOps->clear();\n        outOps->reserve(700);\n    }\n\n    array<pair<long long, int>, MAXM> cand{};\n\n    for (int x = 1; x <= N; ++x) {\n        int s = st.stk[x];\n        int pos = st.pos[x];\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int chosenD = -1;\n\n            if (candK <= 1) {\n                chosenD = choose_best_dest(st, s, start, x, p);\n            } else {\n                int cnt = rank_destinations(st, s, start, x, p, cand);\n                int K = min(candK, cnt);\n\n                long long bestEst = INF64;\n                long long bestCheap = INF64;\n                int bestD = cand[0].second;\n\n                for (int ci = 0; ci < K; ++ci) {\n                    int d = cand[ci].second;\n                    long long cheap = cand[ci].first;\n\n                    State tmp = st;\n                    move_suffix(tmp, s, start, d);\n                    remove_target(tmp, x);\n\n                    long long cutoff = (bestEst >= INF64 / 4) ? INF64 : (bestEst - (k + 1));\n                    if (cutoff < 0) cutoff = 0;\n\n                    long long fut = simulate_base(tmp, x + 1, p, cutoff);\n                    long long est = (k + 1) + fut;\n\n                    if (est < bestEst ||\n                        (est == bestEst && cheap < bestCheap) ||\n                        (est == bestEst && cheap == bestCheap && d < bestD)) {\n                        bestEst = est;\n                        bestCheap = cheap;\n                        bestD = d;\n                    }\n                }\n                chosenD = bestD;\n            }\n\n            int vmove = st.box[s][start];\n            move_suffix(st, s, start, chosenD);\n            energy += k + 1;\n            if (outOps) outOps->push_back({vmove, chosenD + 1});\n        }\n\n        remove_target(st, x);\n        if (outOps) outOps->push_back({x, 0});\n    }\n\n    return energy;\n}\n\nvoid add_pool(vector<Trial>& pool, long long e, const Params& p, int lim) {\n    bool found = false;\n    for (auto& t : pool) {\n        if (t.p == p) {\n            if (e < t.e) t.e = e;\n            found = true;\n            break;\n        }\n    }\n    if (!found) pool.push_back({e, p});\n\n    sort(pool.begin(), pool.end(),\n         [](const Trial& a, const Trial& b) { return a.e < b.e; });\n\n    if ((int)pool.size() > lim) pool.resize(lim);\n}\n\nParams random_param(mt19937& rng) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n    Params p{};\n    p.w_cross = rnd(600, 1800);\n    p.w_near = rnd(0, 100);\n    p.near_th = rnd(8, 65);\n    p.w_height = rnd(-5, 12);\n    p.w_top = rnd(0, 12);\n    p.w_empty = rnd(0, 3800);\n    p.w_boundary = rnd(0, 80);\n    return p;\n}\n\nParams mutate_param(const Params& base, mt19937& rng, int strength) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    if (rnd(0, 99) < 10) return random_param(rng);\n\n    int s = max(1, strength);\n    Params p = base;\n    p.w_cross = clamp(base.w_cross + rnd(-130 * s, 130 * s), 450, 2200);\n    p.w_near = clamp(base.w_near + rnd(-10 * s, 10 * s), 0, 130);\n    p.near_th = clamp(base.near_th + rnd(-4 * s, 4 * s), 5, 75);\n    p.w_height = clamp(base.w_height + rnd(-2 * s, 2 * s), -8, 16);\n    p.w_top = clamp(base.w_top + rnd(-2 * s, 2 * s), 0, 16);\n    p.w_empty = clamp(base.w_empty + rnd(-220 * s, 220 * s), 0, 5000);\n    p.w_boundary = clamp(base.w_boundary + rnd(-6 * s, 6 * s), 0, 100);\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    State init{};\n\n    for (int i = 0; i < MAXM; ++i) init.len[i] = 0;\n    for (int v = 1; v <= MAXN; ++v) {\n        init.stk[v] = -1;\n        init.pos[v] = -1;\n    }\n\n    int h = N / M;\n    uint64_t seed = 1469598103934665603ULL;\n\n    for (int i = 0; i < M; ++i) {\n        init.len[i] = h;\n        for (int j = 0; j < h; ++j) {\n            int v;\n            cin >> v;\n            init.box[i][j] = v;\n            init.stk[v] = i;\n            init.pos[v] = j;\n\n            seed ^= (uint64_t)v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    uint64_t clk = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32) ^ clk));\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    vector<Params> presets = {\n        {1000, 10, 20, 1, 1,  800, 10},\n        {1000, 20, 24, 2, 1, 1200, 15},\n        {1050, 30, 28, 2, 2, 1500, 20},\n        {1100, 35, 32, 3, 2, 1700, 25},\n        { 900, 45, 20, 1, 3, 1300, 15},\n        {1200, 25, 40, 4, 1, 2000, 30},\n        { 950, 15, 18, 1, 2,  900,  8},\n        {1300, 20, 45, 5, 1, 2200, 35},\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    // Time plan\n    const double HARD = 1.80;\n    const double T1 = 0.55;\n    const double T2 = 1.35;\n\n    const int K_FAST = 1;\n    const int K_MID = 4;\n    const int K_FINAL = 7;\n    const int POOL_SZ = 24;\n\n    vector<Trial> pool;\n    Params bestFastP = presets[0];\n    long long bestFastE = INF64;\n\n    // Stage 1: fast coarse search (greedy base)\n    for (const auto& p : presets) {\n        if (elapsed() + 0.01 > T1) break;\n        long long e = solve_run(init, p, K_FAST, nullptr);\n        if (e < bestFastE) {\n            bestFastE = e;\n            bestFastP = p;\n        }\n        add_pool(pool, e, p, POOL_SZ);\n    }\n\n    if (pool.empty()) {\n        long long e = solve_run(init, bestFastP, K_FAST, nullptr);\n        add_pool(pool, e, bestFastP, POOL_SZ);\n    }\n\n    while (elapsed() + 0.01 < T1) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 55) {\n            base = bestFastP;\n        } else if (r < 90 && !pool.empty()) {\n            int idx = rnd(0, min((int)pool.size() - 1, 7));\n            base = pool[idx].p;\n        } else {\n            base = presets[rnd(0, (int)presets.size() - 1)];\n        }\n\n        Params cand = mutate_param(base, rng, 2);\n        long long e = solve_run(init, cand, K_FAST, nullptr);\n        if (e < bestFastE) {\n            bestFastE = e;\n            bestFastP = cand;\n        }\n        add_pool(pool, e, cand, POOL_SZ);\n    }\n\n    Result bestRes;\n    bestRes.energy = INF64;\n\n    auto run_record = [&](const Params& p, int k) {\n        vector<pair<int, int>> ops;\n        long long e = solve_run(init, p, k, &ops);\n        if (e < bestRes.energy ||\n            (e == bestRes.energy && (bestRes.ops.empty() || ops.size() < bestRes.ops.size()))) {\n            bestRes.energy = e;\n            bestRes.ops = move(ops);\n            bestRes.param = p;\n        }\n    };\n\n    // Stage 2 init: evaluate top coarse candidates with medium rollout\n    int initTry = min((int)pool.size(), 8);\n    for (int i = 0; i < initTry && elapsed() + 0.06 < T2; ++i) {\n        run_record(pool[i].p, K_MID);\n    }\n    for (const auto& p : presets) {\n        if (elapsed() + 0.06 > T2) break;\n        run_record(p, K_MID);\n    }\n\n    if (bestRes.energy >= INF64 / 2) {\n        run_record(bestFastP, K_FAST);\n    }\n\n    auto eval_and_update = [&](const Params& p, int k, double est, bool addToPool) {\n        if (elapsed() + est * 1.5 > HARD) return;\n        long long e = solve_run(init, p, k, nullptr);\n        if (addToPool) add_pool(pool, e, p, POOL_SZ);\n        if (e < bestRes.energy && elapsed() + est < HARD) {\n            run_record(p, k);\n        }\n    };\n\n    // Stage 2: medium refinement\n    while (elapsed() + 0.06 * 1.5 < T2) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 60) {\n            base = bestRes.param;\n        } else if (r < 90 && !pool.empty()) {\n            int idx = rnd(0, min((int)pool.size() - 1, 9));\n            base = pool[idx].p;\n        } else {\n            base = presets[rnd(0, (int)presets.size() - 1)];\n        }\n\n        Params cand = mutate_param(base, rng, 1);\n        eval_and_update(cand, K_MID, 0.06, true);\n    }\n\n    // Stage 3: stronger rollout polish\n    eval_and_update(bestRes.param, K_FINAL, 0.10, false);\n    eval_and_update(bestRes.param, 9, 0.13, false);\n\n    for (int i = 0; i < min((int)pool.size(), 6) && elapsed() + 0.10 * 1.5 < HARD; ++i) {\n        eval_and_update(pool[i].p, K_FINAL, 0.10, false);\n    }\n\n    while (elapsed() + 0.10 * 1.5 < HARD) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 75 || pool.empty()) {\n            base = bestRes.param;\n        } else {\n            int idx = rnd(0, min((int)pool.size() - 1, 9));\n            base = pool[idx].p;\n        }\n        Params cand = mutate_param(base, rng, 1);\n        eval_and_update(cand, K_FINAL, 0.10, false);\n    }\n\n    if (bestRes.ops.empty()) {\n        run_record(bestFastP, K_FAST);\n    }\n\n    for (auto [v, i] : bestRes.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Metric {\n    long long total = 0;\n    int L = 0;\n    bool valid = false;\n};\n\nclass Solver {\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void read_input() {\n        cin >> N;\n        hWall.resize(N - 1);\n        for (int i = 0; i < N - 1; i++) cin >> hWall[i];\n        vWall.resize(N);\n        for (int i = 0; i < N; i++) cin >> vWall[i];\n\n        V = N * N;\n        dirt.resize(V);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                cin >> dirt[i * N + j];\n            }\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        build_graph();\n        precompute_apsp();\n\n        logd.resize(V);\n        for (int i = 0; i < V; i++) logd[i] = log(1.0 + (double)dirt[i]);\n\n        firstVisit.assign(V, -1);\n        prevVisit.assign(V, -1);\n        tri.assign(V, 0LL);\n\n        string dfsRoute = build_dfs_route();\n        Metric dfsM = evaluate(dfsRoute);\n\n        string bestRoute = dfsRoute;\n        Metric bestM = dfsM;\n\n        const double T_INIT = 0.30;\n        const double T_GAP  = 1.00;\n        const double T_RAND = 1.75;\n        const double T_END  = 1.88;\n\n        // Initial multi-start\n        int trial = 0;\n        while (elapsed() < T_INIT) {\n            string r;\n            if (trial % 3 == 0) {\n                double a = 0.2 + rnd01() * 1.8;\n                double b = 0.4 + rnd01() * 1.8;\n                double g = rnd01() * 0.6;\n                r = build_random_route(a, b, g);\n            } else {\n                double wD = rnd01() * 2.0;\n                double wR = rnd01() * 1.0;\n                double nz = 0.2 + rnd01() * 1.2;\n                r = build_weighted_dfs(wD, wR, nz);\n            }\n\n            if (!r.empty()) {\n                Metric m = evaluate(r);\n                if (better(m, bestM)) {\n                    bestM = m;\n                    bestRoute = std::move(r);\n                }\n            }\n            trial++;\n        }\n\n        string curRoute = bestRoute;\n        Metric curM = bestM;\n\n        long long sumd = 0;\n        int maxd = 0;\n        for (int x : dirt) {\n            sumd += x;\n            maxd = max(maxd, x);\n        }\n        double avgd = (double)sumd / max(1, V);\n        double skew = maxd / max(1.0, avgd);\n\n        int maxLen = 32000;\n        if (skew > 4.0) maxLen = 42000;\n        if (skew > 7.0) maxLen = 52000;\n        if (V < 900) maxLen += 6000;\n        maxLen = min(maxLen, 90000);\n\n        // Deterministic improve\n        while (elapsed() < T_GAP) {\n            bool improved = false;\n            if (improve_gap_best(curRoute, curM, T_GAP, maxLen)) improved = true;\n            if (elapsed() < T_GAP && improve_shorten_batch(curRoute, curM, T_GAP)) improved = true;\n\n            if (improved && better(curM, bestM)) {\n                bestM = curM;\n                bestRoute = curRoute;\n            }\n            if (!improved) break;\n        }\n\n        // High-d candidates and near lists\n        vector<int> highIds(V);\n        iota(highIds.begin(), highIds.end(), 0);\n        sort(highIds.begin(), highIds.end(), [&](int a, int b) {\n            if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n            return a < b;\n        });\n        if ((int)highIds.size() > 500) highIds.resize(500);\n\n        vector<vector<int>> nearTargets(V);\n        const int NEAR_DIST = 10;\n        for (int a = 0; a < V; a++) {\n            for (int x : highIds) {\n                int dd = (int)distMat[a][x];\n                if (dd > 0 && dd <= NEAR_DIST) nearTargets[a].push_back(x);\n            }\n        }\n\n        vector<int> pos = decode_positions(curRoute);\n        if (pos.empty()) {\n            curRoute = bestRoute;\n            curM = bestM;\n            pos = decode_positions(curRoute);\n        }\n        if (pos.empty()) {\n            curRoute = dfsRoute;\n            curM = dfsM;\n            pos = decode_positions(curRoute);\n        }\n        vector<int> cnt = build_counts(pos);\n\n        // Random hill-climb (improvement only)\n        int fail = 0;\n        while (elapsed() < T_RAND) {\n            string cand;\n            bool ok = false;\n\n            int op = (int)(rng() % 100);\n            if (op < 45) {\n                ok = make_random_loop_insert(curRoute, pos, nearTargets, highIds, cand, maxLen);\n            } else if (op < 65) {\n                ok = make_random_edge_insert(curRoute, pos, highIds, cand, maxLen);\n            } else if (op < 83) {\n                ok = make_random_shortcut(curRoute, pos, cnt, cand);\n            } else {\n                ok = make_random_loop_remove(curRoute, pos, cnt, cand);\n            }\n\n            if (!ok) {\n                fail++;\n                continue;\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, curM)) {\n                curRoute.swap(cand);\n                curM = m;\n                if (better(curM, bestM)) {\n                    bestM = curM;\n                    bestRoute = curRoute;\n                }\n                pos = decode_positions(curRoute);\n                if (pos.empty()) break;\n                cnt = build_counts(pos);\n                fail = 0;\n            } else {\n                fail++;\n            }\n\n            if (fail > 220 && elapsed() < T_RAND) {\n                bool improved = false;\n                if (improve_gap_best(curRoute, curM, T_RAND, maxLen)) improved = true;\n                if (elapsed() < T_RAND && improve_shorten_batch(curRoute, curM, T_RAND)) improved = true;\n\n                if (improved) {\n                    if (better(curM, bestM)) {\n                        bestM = curM;\n                        bestRoute = curRoute;\n                    }\n                    pos = decode_positions(curRoute);\n                    if (pos.empty()) break;\n                    cnt = build_counts(pos);\n                }\n                fail = 0;\n            }\n        }\n\n        // Final polish\n        curRoute = bestRoute;\n        curM = bestM;\n        while (elapsed() < T_END) {\n            bool improved = false;\n            if (improve_shorten_batch(curRoute, curM, T_END)) improved = true;\n            if (elapsed() < T_END && improve_gap_best(curRoute, curM, T_END, maxLen)) improved = true;\n\n            if (improved) {\n                if (better(curM, bestM)) {\n                    bestM = curM;\n                    bestRoute = curRoute;\n                }\n            } else {\n                break;\n            }\n        }\n\n        Metric fin = evaluate(bestRoute);\n        if (!fin.valid || (int)bestRoute.size() > 100000) {\n            bestRoute = dfsRoute;\n        }\n        cout << bestRoute << '\\n';\n    }\n\nprivate:\n    int N = 0, V = 0;\n    vector<string> hWall, vWall;\n    vector<int> dirt;\n    vector<double> logd;\n\n    vector<int> row, col;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> nxtMove; // U D L R\n\n    vector<vector<int16_t>> distMat, nextHop;\n    vector<int> dist0;\n\n    vector<int> firstVisit, prevVisit;\n    vector<long long> tri;\n\n    int dirMap[256]{};\n\n    mt19937_64 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    double rnd01() {\n        return (rng() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    void build_graph() {\n        fill(begin(dirMap), end(dirMap), -1);\n        dirMap[(unsigned char)'U'] = 0;\n        dirMap[(unsigned char)'D'] = 1;\n        dirMap[(unsigned char)'L'] = 2;\n        dirMap[(unsigned char)'R'] = 3;\n\n        row.resize(V);\n        col.resize(V);\n        adj.assign(V, {});\n        nxtMove.assign(V, array<int, 4>{-1, -1, -1, -1});\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                row[id] = i;\n                col[id] = j;\n\n                if (i > 0 && hWall[i - 1][j] == '0') {\n                    int to = (i - 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][0] = to;\n                }\n                if (i + 1 < N && hWall[i][j] == '0') {\n                    int to = (i + 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][1] = to;\n                }\n                if (j > 0 && vWall[i][j - 1] == '0') {\n                    int to = i * N + (j - 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][2] = to;\n                }\n                if (j + 1 < N && vWall[i][j] == '0') {\n                    int to = i * N + (j + 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][3] = to;\n                }\n            }\n        }\n    }\n\n    void precompute_apsp() {\n        const int16_t INF = 30000;\n        distMat.assign(V, vector<int16_t>(V, INF));\n        nextHop.assign(V, vector<int16_t>(V, -1));\n\n        vector<int> q(V);\n\n        for (int s = 0; s < V; s++) {\n            auto &ds = distMat[s];\n            auto &ns = nextHop[s];\n\n            fill(ds.begin(), ds.end(), INF);\n            fill(ns.begin(), ns.end(), -1);\n\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            ds[s] = 0;\n            ns[s] = s;\n\n            while (head < tail) {\n                int u = q[head++];\n                for (int v : adj[u]) {\n                    if (ds[v] != INF) continue;\n                    ds[v] = ds[u] + 1;\n                    ns[v] = (u == s ? v : ns[u]);\n                    q[tail++] = v;\n                }\n            }\n        }\n\n        dist0.resize(V);\n        for (int i = 0; i < V; i++) dist0[i] = (int)distMat[0][i];\n    }\n\n    char dir_between(int u, int v) const {\n        if (row[v] == row[u] - 1) return 'U';\n        if (row[v] == row[u] + 1) return 'D';\n        if (col[v] == col[u] - 1) return 'L';\n        return 'R';\n    }\n\n    char opposite(char c) const {\n        if (c == 'U') return 'D';\n        if (c == 'D') return 'U';\n        if (c == 'L') return 'R';\n        return 'L';\n    }\n\n    Metric evaluate(const string &route) {\n        int L = (int)route.size();\n        if (L <= 0 || L > 100000) return Metric{0, L, false};\n\n        fill(firstVisit.begin(), firstVisit.end(), -1);\n        fill(prevVisit.begin(), prevVisit.end(), -1);\n        fill(tri.begin(), tri.end(), 0LL);\n\n        int cur = 0;\n        for (int t = 1; t <= L; t++) {\n            int d = dirMap[(unsigned char)route[t - 1]];\n            if (d < 0) return Metric{0, L, false};\n\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return Metric{0, L, false};\n\n            cur = nx;\n            if (prevVisit[cur] != -1) {\n                long long delta = t - prevVisit[cur];\n                tri[cur] += delta * (delta - 1) / 2;\n            } else {\n                firstVisit[cur] = t;\n            }\n            prevVisit[cur] = t;\n        }\n\n        if (cur != 0) return Metric{0, L, false};\n\n        long long total = 0;\n        for (int v = 0; v < V; v++) {\n            if (prevVisit[v] == -1) return Metric{0, L, false};\n            long long delta = (long long)firstVisit[v] + L - prevVisit[v];\n            tri[v] += delta * (delta - 1) / 2;\n            total += tri[v] * (long long)dirt[v];\n        }\n\n        return Metric{total, L, true};\n    }\n\n    bool better(const Metric &a, const Metric &b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        __int128 lhs = (__int128)a.total * b.L;\n        __int128 rhs = (__int128)b.total * a.L;\n        if (lhs != rhs) return lhs < rhs;\n        return a.L < b.L;\n    }\n\n    vector<int> decode_positions(const string &route) const {\n        int L = (int)route.size();\n        vector<int> pos(L + 1);\n        int cur = 0;\n        pos[0] = 0;\n\n        for (int i = 0; i < L; i++) {\n            int d = dirMap[(unsigned char)route[i]];\n            if (d < 0) return {};\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return {};\n            cur = nx;\n            pos[i + 1] = cur;\n        }\n        return pos;\n    }\n\n    vector<int> build_counts(const vector<int> &pos) const {\n        vector<int> cnt(V, 0);\n        for (int i = 1; i < (int)pos.size(); i++) cnt[pos[i]]++;\n        return cnt;\n    }\n\n    string path_between(int a, int b) const {\n        if (a == b) return \"\";\n        string p;\n        int u = a;\n        int guard = 0;\n        while (u != b) {\n            int v = (int)nextHop[u][b];\n            if (v < 0 || v == u) return \"\";\n            p.push_back(dir_between(u, v));\n            u = v;\n            if (++guard > 500000) return \"\";\n        }\n        return p;\n    }\n\n    string roundtrip_detour(int a, int target) const {\n        if (a == target) return \"\";\n        string fwd = path_between(a, target);\n        if (fwd.empty()) return \"\";\n        string det = fwd;\n        for (int i = (int)fwd.size() - 1; i >= 0; i--) det.push_back(opposite(fwd[i]));\n        return det;\n    }\n\n    string insert_detour(const string &route, int t, const string &det) const {\n        string out;\n        out.reserve(route.size() + det.size());\n        out.append(route, 0, t);\n        out += det;\n        out.append(route, t, route.size() - t);\n        return out;\n    }\n\n    string remove_segment(const string &route, int l, int len) const {\n        string out;\n        out.reserve(route.size() - len);\n        out.append(route, 0, l);\n        out.append(route, l + len, route.size() - (l + len));\n        return out;\n    }\n\n    string replace_segment(const string &route, int l, int r, const string &rep) const {\n        string out;\n        out.reserve(route.size() - (r - l) + rep.size());\n        out.append(route, 0, l);\n        out += rep;\n        out.append(route, r, route.size() - r);\n        return out;\n    }\n\n    string build_dfs_route() {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            vector<int> nbs = adj[u];\n            sort(nbs.begin(), nbs.end(), [&](int a, int b) {\n                if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n                return a < b;\n            });\n\n            for (int v : nbs) {\n                if (vis[v]) continue;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_weighted_dfs(double wD, double wR, double noise) {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(adj[u].size());\n            for (int v : adj[u]) {\n                if (vis[v]) continue;\n                double s = wD * logd[v] - wR * dist0[v] + noise * rnd01();\n                cand.push_back({s, v});\n            }\n\n            sort(cand.begin(), cand.end(), [](const auto &x, const auto &y) {\n                return x.first > y.first;\n            });\n\n            for (auto &kv : cand) {\n                int v = kv.second;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_random_route(double alpha, double beta, double gamma) {\n        vector<char> vis(V, 0);\n        vis[0] = 1;\n        int rem = V - 1;\n\n        int cur = 0;\n        string route;\n        route.reserve(V * 3);\n\n        while (rem > 0) {\n            if ((int)route.size() > 90000) return \"\";\n\n            int bestN = -1;\n            double bestS = -1e100;\n\n            for (int nb : adj[cur]) {\n                if (vis[nb]) continue;\n                int onward = 0;\n                for (int z : adj[nb]) if (!vis[z]) onward++;\n                double s = alpha * logd[nb] - beta * onward + rnd01() * 0.02;\n                if (s > bestS) {\n                    bestS = s;\n                    bestN = nb;\n                }\n            }\n\n            if (bestN != -1) {\n                route.push_back(dir_between(cur, bestN));\n                cur = bestN;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                continue;\n            }\n\n            int target = -1;\n            double bestV = 1e100;\n            for (int v = 0; v < V; v++) {\n                if (vis[v]) continue;\n                int dd = (int)distMat[cur][v];\n                double val = (double)dd - gamma * logd[v] + rnd01() * 0.02;\n                if (val < bestV) {\n                    bestV = val;\n                    target = v;\n                }\n            }\n            if (target < 0) return \"\";\n\n            while (cur != target) {\n                int nx = (int)nextHop[cur][target];\n                if (nx < 0 || nx == cur) return \"\";\n                route.push_back(dir_between(cur, nx));\n                cur = nx;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                if ((int)route.size() > 90000) return \"\";\n            }\n        }\n\n        while (cur != 0) {\n            int nx = (int)nextHop[cur][0];\n            if (nx < 0 || nx == cur) return \"\";\n            route.push_back(dir_between(cur, nx));\n            cur = nx;\n            if ((int)route.size() > 90000) return \"\";\n        }\n\n        return route;\n    }\n\n    struct InsCand {\n        double est;\n        int type; // 0: loop insert, 1: edge replacement via target\n        int t;\n        int v;\n    };\n\n    bool improve_gap_best(string &route, Metric &curM, double timeLimit, int maxLen) {\n        int L = (int)route.size();\n        if (L <= 0 || L >= maxLen) return false;\n\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n\n        vector<int> first(V, -1), last(V, -1), maxGap(V, 0), gapStart(V, 0);\n\n        for (int t = 1; t <= L; t++) {\n            int v = pos[t];\n            if (first[v] == -1) {\n                first[v] = last[v] = t;\n            } else {\n                int g = t - last[v];\n                if (g > maxGap[v]) {\n                    maxGap[v] = g;\n                    gapStart[v] = last[v];\n                }\n                last[v] = t;\n            }\n        }\n        for (int v = 0; v < V; v++) {\n            int g = first[v] + L - last[v];\n            if (g > maxGap[v]) {\n                maxGap[v] = g;\n                gapStart[v] = last[v];\n            }\n        }\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(V);\n        for (int v = 0; v < V; v++) {\n            if (maxGap[v] <= 2) continue;\n            long long g = maxGap[v];\n            long long pot = 1LL * dirt[v] * g * g;\n            ord.push_back({pot, v});\n        }\n        if (ord.empty()) return false;\n\n        sort(ord.begin(), ord.end(), greater<pair<long long, int>>());\n        int M = min((int)ord.size(), 220);\n\n        vector<InsCand> cands;\n        cands.reserve(M * 16);\n\n        auto push_off = [&](vector<int> &offs, int g, int x) {\n            if (x > 0 && x < g) offs.push_back(x);\n        };\n\n        for (int i = 0; i < M; i++) {\n            if (elapsed() >= timeLimit) break;\n\n            int v = ord[i].second;\n            int g = maxGap[v];\n            int s = gapStart[v];\n            if (g <= 2) continue;\n\n            vector<int> offs;\n            offs.reserve(12);\n\n            push_off(offs, g, g / 4);\n            push_off(offs, g, g / 3);\n            push_off(offs, g, g / 2);\n            push_off(offs, g, (2 * g) / 3);\n            push_off(offs, g, (3 * g) / 4);\n\n            int step = max(1, g / 16);\n            int bestOff = -1;\n            int bestScore = INT_MAX;\n\n            for (int off = 1; off < g; off += step) {\n                int t = (s + off) % L;\n                int a = pos[t];\n                int dd = (int)distMat[a][v];\n                int bal = abs(2 * off - g);\n                int score = dd * 4 + bal / 8;\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestOff = off;\n                }\n            }\n            push_off(offs, g, bestOff);\n            push_off(offs, g, g / 2 - step);\n            push_off(offs, g, g / 2 + step);\n\n            sort(offs.begin(), offs.end());\n            offs.erase(unique(offs.begin(), offs.end()), offs.end());\n\n            long long oldTerm = 1LL * g * (g - 1) / 2;\n\n            for (int off : offs) {\n                int t = (s + off) % L;\n                int a = pos[t];\n\n                // Type 0: roundtrip loop insertion\n                int dd = (int)distMat[a][v];\n                if (dd > 0) {\n                    int add = 2 * dd;\n                    if (L + add <= maxLen) {\n                        long long g1 = (long long)off + dd;\n                        long long g2 = (long long)g - off + dd;\n                        long long newTerm = g1 * (g1 - 1) / 2 + g2 * (g2 - 1) / 2;\n                        long long gain = 1LL * dirt[v] * (oldTerm - newTerm);\n                        if (gain > 0) {\n                            double est = (double)gain / (add + 1.0);\n                            cands.push_back({est, 0, t, v});\n                        }\n                    }\n                }\n\n                // Type 1: replace edge (t->t+1) by path through v\n                int u = pos[t];\n                int w = pos[t + 1];\n                int d1 = (int)distMat[u][v];\n                int d2 = (int)distMat[v][w];\n                int via = d1 + d2;\n                int add = via - 1;\n\n                if (add > 0 && via <= 90 && L + add <= maxLen) {\n                    long long g1 = (long long)off + d1;\n                    long long g2 = (long long)g - off + d2 - 1;\n                    if (g1 > 0 && g2 > 0) {\n                        long long newTerm = g1 * (g1 - 1) / 2 + g2 * (g2 - 1) / 2;\n                        long long gain = 1LL * dirt[v] * (oldTerm - newTerm);\n                        if (gain > 0) {\n                            double est = 1.08 * (double)gain / (add + 1.0);\n                            cands.push_back({est, 1, t, v});\n                        }\n                    }\n                }\n            }\n        }\n\n        if (cands.empty()) return false;\n\n        sort(cands.begin(), cands.end(), [](const InsCand &a, const InsCand &b) {\n            return a.est > b.est;\n        });\n\n        int evalLim = (L < 8000 ? 100 : (L < 20000 ? 70 : 45));\n        if ((int)cands.size() > evalLim) cands.resize(evalLim);\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (const auto &c : cands) {\n            if (elapsed() >= timeLimit) break;\n\n            string cand;\n            if (c.type == 0) {\n                string det = roundtrip_detour(pos[c.t], c.v);\n                if (det.empty()) continue;\n                cand = insert_detour(route, c.t, det);\n            } else {\n                int u = pos[c.t];\n                int w = pos[c.t + 1];\n                string p1 = path_between(u, c.v);\n                string p2 = path_between(c.v, w);\n                if ((int)distMat[u][c.v] > 0 && p1.empty()) continue;\n                if ((int)distMat[c.v][w] > 0 && p2.empty()) continue;\n                string rep = p1 + p2;\n                if ((int)rep.size() <= 1) continue;\n                cand = replace_segment(route, c.t, c.t + 1, rep);\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\n    }\n\n    static void add_delta_small(vector<int> &ids, vector<int> &delta, int v, int add) {\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (ids[i] == v) {\n                delta[i] += add;\n                return;\n            }\n        }\n        ids.push_back(v);\n        delta.push_back(add);\n    }\n\n    bool can_remove_closed(const vector<int> &pos, const vector<int> &cnt, int l, int r) const {\n        vector<int> ids, delta;\n        ids.reserve(r - l + 2);\n        delta.reserve(r - l + 2);\n\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool can_replace_segment(const vector<int> &pos, const vector<int> &cnt, int l, int r, const string &rep) const {\n        vector<int> ids, delta;\n        ids.reserve((r - l) + (int)rep.size() + 4);\n        delta.reserve((r - l) + (int)rep.size() + 4);\n\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n\n        int cur = pos[l];\n        for (char c : rep) {\n            int d = dirMap[(unsigned char)c];\n            if (d < 0) return false;\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return false;\n            cur = nx;\n            add_delta_small(ids, delta, cur, +1);\n        }\n        if (cur != pos[r]) return false;\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool make_random_loop_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<vector<int>> &nearTargets,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L >= maxLen) return false;\n\n        int t = (int)(rng() % (L + 1));\n        int a = pos[t];\n\n        int chosen = -1;\n        double bestVal = -1e100;\n\n        const auto &lst = nearTargets[a];\n        if (!lst.empty()) {\n            int sample = min(12, (int)lst.size());\n            for (int i = 0; i < sample; i++) {\n                int x = lst[(int)(rng() % lst.size())];\n                int dd = (int)distMat[a][x];\n                if (dd <= 0) continue;\n                int add = 2 * dd;\n                if (L + add > maxLen) continue;\n                double val = (double)dirt[x] / add + rnd01() * 0.02;\n                if (val > bestVal) {\n                    bestVal = val;\n                    chosen = x;\n                }\n            }\n        }\n\n        if (chosen < 0 && !highIds.empty()) {\n            int H = (int)highIds.size();\n            for (int it = 0; it < 24; it++) {\n                int idx = (int)(pow(rnd01(), 1.7) * H);\n                if (idx >= H) idx = H - 1;\n                int x = highIds[idx];\n                int dd = (int)distMat[a][x];\n                if (dd <= 0 || dd > 20) continue;\n                int add = 2 * dd;\n                if (L + add > maxLen) continue;\n                double val = (double)dirt[x] / add + rnd01() * 0.02;\n                if (val > bestVal) {\n                    bestVal = val;\n                    chosen = x;\n                }\n            }\n        }\n\n        if (chosen < 0) return false;\n\n        string det = roundtrip_detour(a, chosen);\n        if (det.empty()) return false;\n        cand = insert_detour(route, t, det);\n        return true;\n    }\n\n    bool make_random_edge_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L <= 0 || L >= maxLen || highIds.empty()) return false;\n\n        int t = (int)(rng() % L);\n        int u = pos[t];\n        int w = pos[t + 1];\n\n        int chosen = -1;\n        double bestVal = -1e100;\n\n        int H = (int)highIds.size();\n        for (int it = 0; it < 30; it++) {\n            int idx = (int)(pow(rnd01(), 1.8) * H);\n            if (idx >= H) idx = H - 1;\n            int x = highIds[idx];\n\n            int d1 = (int)distMat[u][x];\n            int d2 = (int)distMat[x][w];\n            int add = d1 + d2 - 1;\n            if (add <= 0 || add > 35) continue;\n            if (L + add > maxLen) continue;\n\n            double val = (double)dirt[x] / add + rnd01() * 0.02;\n            if (val > bestVal) {\n                bestVal = val;\n                chosen = x;\n            }\n        }\n\n        if (chosen < 0) return false;\n\n        string p1 = path_between(u, chosen);\n        string p2 = path_between(chosen, w);\n        if ((int)distMat[u][chosen] > 0 && p1.empty()) return false;\n        if ((int)distMat[chosen][w] > 0 && p2.empty()) return false;\n\n        string rep = p1 + p2;\n        if ((int)rep.size() <= 1) return false;\n\n        cand = replace_segment(route, t, t + 1, rep);\n        return true;\n    }\n\n    bool make_random_loop_remove(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        if (L < 4) return false;\n\n        int maxLen = min(80, L);\n        int len = 2 + (int)(rng() % (maxLen - 1)); // [2, maxLen]\n        int l = (int)(rng() % (L - len + 1));\n        int r = l + len;\n\n        if (pos[l] != pos[r]) return false;\n        if (!can_remove_closed(pos, cnt, l, r)) return false;\n\n        cand = remove_segment(route, l, len);\n        return true;\n    }\n\n    bool make_random_shortcut(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        if (L < 6) return false;\n\n        int maxSpan = min(90, L);\n        int span = 3 + (int)(rng() % (maxSpan - 2)); // [3, maxSpan]\n        int l = (int)(rng() % (L - span + 1));\n        int r = l + span;\n\n        int u = pos[l];\n        int v = pos[r];\n        int p = (int)distMat[u][v];\n        if (p <= 0 || p >= span) return false;\n\n        string rep = path_between(u, v);\n        if ((int)rep.size() != p) return false;\n        if (!can_replace_segment(pos, cnt, l, r, rep)) return false;\n\n        cand = replace_segment(route, l, r, rep);\n        return true;\n    }\n\n    bool improve_shorten_batch(string &route, Metric &curM, double timeLimit) {\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n        vector<int> cnt = build_counts(pos);\n\n        int L = (int)route.size();\n        int attempts = (L < 8000 ? 120 : (L < 20000 ? 80 : 55));\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (int it = 0; it < attempts && elapsed() < timeLimit; it++) {\n            string cand;\n            bool ok;\n            if ((rng() % 100) < 58) {\n                ok = make_random_shortcut(route, pos, cnt, cand);\n            } else {\n                ok = make_random_loop_remove(route, pos, cnt, cand);\n            }\n            if (!ok) continue;\n\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\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}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % (uint64_t)n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct Solver {\n    static constexpr int INF = 1e9;\n\n    int N{}, M{}, V{};\n    int si{}, sj{}, startId{};\n    vector<string> board;\n    vector<string> words;\n\n    array<vector<int>, 26> occ{};\n    int distMat[225][225]{};\n\n    vector<vector<int>> ov; // overlap [0..4]\n\n    vector<int> lastChar;\n    vector<int> nEnd;\n\n    // exact evaluator precompute\n    vector<vector<int>> firstEndCost; // first word from start -> each end-index\n    vector<size_t> transOffset;       // offset for pair (a,b): transOffset[a*M+b]\n    vector<int> transData;            // flattened matrices: [nEnd[a] x nEnd[b]]\n\n    // approximate objective (from exact transition minima)\n    vector<int> startCostApprox;\n    vector<vector<int>> edgeApprox;\n\n    chrono::steady_clock::time_point t0;\n    XorShift64 rng{};\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n        words.resize(M);\n        for (int i = 0; i < M; i++) cin >> words[i];\n        V = N * N;\n        startId = si * N + sj;\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t h = 1469598103934665603ull;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto &r : board) for (char c : r) mix((uint64_t)c);\n        for (auto &w : words) for (char c : w) mix((uint64_t)c);\n        return h;\n    }\n\n    void computeOccAndDist() {\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 a = 0; a < V; a++) {\n            int ra = a / N, ca = a % N;\n            for (int b = 0; b < V; b++) {\n                int rb = b / N, cb = b % N;\n                distMat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n    }\n\n    void computeOverlap() {\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int best = 0;\n                for (int k = 4; k >= 0; k--) {\n                    bool ok = true;\n                    for (int x = 0; x < k; x++) {\n                        if (words[i][5 - k + x] != words[j][x]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (ok) {\n                        best = k;\n                        break;\n                    }\n                }\n                ov[i][j] = best;\n            }\n        }\n    }\n\n    // Type words[w][begin..4] from single startCell.\n    // Output costs for each end cell in occ[lastChar[w]] order.\n    void endCostsSingleStartRaw(int startCell, int w, int begin, int* out) const {\n        int prevId[225], nextId[225];\n        int prevCost[225], nextCost[225];\n\n        int ps = 1;\n        prevId[0] = startCell;\n        prevCost[0] = 0;\n\n        for (int pos = begin; pos < 5; pos++) {\n            const vector<int>& cells = occ[words[w][pos] - 'A'];\n            int ns = (int)cells.size();\n\n            for (int ni = 0; ni < ns; ni++) {\n                int q = cells[ni];\n                int best = INF;\n                for (int pi = 0; pi < ps; pi++) {\n                    int p = prevId[pi];\n                    int cand = prevCost[pi] + distMat[p][q] + 1;\n                    if (cand < best) best = cand;\n                }\n                nextId[ni] = q;\n                nextCost[ni] = best;\n            }\n\n            ps = ns;\n            for (int i = 0; i < ps; i++) {\n                prevId[i] = nextId[i];\n                prevCost[i] = nextCost[i];\n            }\n        }\n\n        for (int i = 0; i < ps; i++) out[i] = prevCost[i];\n    }\n\n    void preprocessTransitionsAndApprox() {\n        lastChar.resize(M);\n        nEnd.resize(M);\n        for (int w = 0; w < M; w++) {\n            lastChar[w] = words[w][4] - 'A';\n            nEnd[w] = (int)occ[lastChar[w]].size();\n        }\n\n        firstEndCost.assign(M, {});\n        startCostApprox.assign(M, INF);\n        edgeApprox.assign(M, vector<int>(M, INF));\n\n        // first-word exact costs from initial finger\n        for (int w = 0; w < M; w++) {\n            firstEndCost[w].resize(nEnd[w]);\n            endCostsSingleStartRaw(startId, w, 0, firstEndCost[w].data());\n            int mn = INF;\n            for (int v : firstEndCost[w]) mn = min(mn, v);\n            startCostApprox[w] = mn;\n        }\n\n        // offsets\n        transOffset.assign((size_t)M * M + 1, 0);\n        size_t total = 0;\n        for (int a = 0; a < M; a++) {\n            for (int b = 0; b < M; b++) {\n                size_t id = (size_t)a * M + b;\n                total += (size_t)nEnd[a] * nEnd[b];\n                transOffset[id + 1] = total;\n            }\n        }\n        transData.assign(total, INF);\n\n        // pair transitions + approximate edge minima\n        int row[225];\n        for (int a = 0; a < M; a++) {\n            const vector<int>& starts = occ[lastChar[a]];\n            int na = nEnd[a];\n\n            for (int b = 0; b < M; b++) {\n                int nb = nEnd[b];\n                size_t id = (size_t)a * M + b;\n                size_t off = transOffset[id];\n                int begin = ov[a][b];\n\n                int mn = INF;\n                for (int si = 0; si < na; si++) {\n                    endCostsSingleStartRaw(starts[si], b, begin, row);\n                    size_t base = off + (size_t)si * nb;\n                    for (int tj = 0; tj < nb; tj++) {\n                        int v = row[tj];\n                        transData[base + tj] = v;\n                        if (v < mn) mn = v;\n                    }\n                }\n                edgeApprox[a][b] = mn;\n            }\n        }\n    }\n\n    void preprocess() {\n        computeOccAndDist();\n        computeOverlap();\n        preprocessTransitionsAndApprox();\n    }\n\n    long long approxCost(const vector<int>& perm) const {\n        long long c = startCostApprox[perm[0]];\n        for (int i = 1; i < M; i++) c += edgeApprox[perm[i - 1]][perm[i]];\n        return c;\n    }\n\n    inline long long edgeContrib(int from, int to) const {\n        if (to < 0) return 0;\n        if (from < 0) return startCostApprox[to];\n        return edgeApprox[from][to];\n    }\n\n    long long deltaSwapApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int cand[4] = {i, i + 1, j, j + 1};\n        int pos[4];\n        int npos = 0;\n        for (int z = 0; z < 4; z++) {\n            int t = cand[z];\n            if (t < 0 || t >= M) continue;\n            bool ex = false;\n            for (int k = 0; k < npos; k++) if (pos[k] == t) { ex = true; break; }\n            if (!ex) pos[npos++] = t;\n        }\n\n        auto getNew = [&](int idx) -> int {\n            if (idx == i) return p[j];\n            if (idx == j) return p[i];\n            return p[idx];\n        };\n\n        long long oldc = 0, newc = 0;\n        for (int k = 0; k < npos; k++) {\n            int t = pos[k];\n\n            int toOld = p[t];\n            int fromOld = (t == 0 ? -1 : p[t - 1]);\n            oldc += edgeContrib(fromOld, toOld);\n\n            int toNew = getNew(t);\n            int fromNew = (t == 0 ? -1 : getNew(t - 1));\n            newc += edgeContrib(fromNew, toNew);\n        }\n        return newc - oldc;\n    }\n\n    long long deltaRelocateApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        int x = p[i];\n\n        if (i < j) {\n            int a = (i > 0 ? p[i - 1] : -1);\n            int b = p[i + 1]; // exists\n            int c = p[j];\n            int d = (j + 1 < M ? p[j + 1] : -1);\n\n            long long oldc = edgeContrib(a, x) + edgeContrib(x, b) + edgeContrib(c, d);\n            long long newc = edgeContrib(a, b) + edgeContrib(c, x) + edgeContrib(x, d);\n            return newc - oldc;\n        } else {\n            int a = p[i - 1];\n            int b = (i + 1 < M ? p[i + 1] : -1);\n            int c = (j > 0 ? p[j - 1] : -1);\n            int d = p[j];\n\n            long long oldc = edgeContrib(c, d) + edgeContrib(a, x) + edgeContrib(x, b);\n            long long newc = edgeContrib(c, x) + edgeContrib(x, d) + edgeContrib(a, b);\n            return newc - oldc;\n        }\n    }\n\n    static void relocateMove(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) p[k] = p[k + 1];\n            p[j] = v;\n        } else {\n            for (int k = i; k > j; k--) p[k] = p[k - 1];\n            p[j] = v;\n        }\n    }\n\n    vector<int> nearestAllStarts() const {\n        vector<int> bestPerm;\n        long long best = (1LL << 60);\n\n        vector<char> used(M);\n        vector<int> perm(M);\n\n        for (int s = 0; s < M; s++) {\n            fill(used.begin(), used.end(), 0);\n            perm[0] = s;\n            used[s] = 1;\n            long long c = startCostApprox[s];\n\n            for (int pos = 1; pos < M; pos++) {\n                int prev = perm[pos - 1];\n                int bestj = -1;\n                int bestv = INF;\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeApprox[prev][j];\n                    if (v < bestv) {\n                        bestv = v;\n                        bestj = j;\n                    }\n                }\n                perm[pos] = bestj;\n                used[bestj] = 1;\n                c += bestv;\n            }\n\n            if (c < best) {\n                best = c;\n                bestPerm = perm;\n            }\n        }\n        return bestPerm;\n    }\n\n    vector<int> cheapestInsertion(int seed) const {\n        vector<int> path;\n        path.reserve(M);\n        vector<char> used(M, 0);\n        path.push_back(seed);\n        used[seed] = 1;\n\n        for (int step = 1; step < M; step++) {\n            long long bestDelta = (1LL << 60);\n            int bestWord = -1;\n            int bestPos = -1;\n            int len = (int)path.size();\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                long long dFront = (long long)startCostApprox[x] + edgeApprox[x][path[0]] - startCostApprox[path[0]];\n                if (dFront < bestDelta) {\n                    bestDelta = dFront;\n                    bestWord = x;\n                    bestPos = 0;\n                }\n\n                for (int pos = 1; pos < len; pos++) {\n                    int u = path[pos - 1];\n                    int v = path[pos];\n                    long long d = (long long)edgeApprox[u][x] + edgeApprox[x][v] - edgeApprox[u][v];\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestWord = x;\n                        bestPos = pos;\n                    }\n                }\n\n                long long dEnd = edgeApprox[path[len - 1]][x];\n                if (dEnd < bestDelta) {\n                    bestDelta = dEnd;\n                    bestWord = x;\n                    bestPos = len;\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestWord);\n            used[bestWord] = 1;\n        }\n\n        return path;\n    }\n\n    void localSearchApprox(vector<int>& perm, long long& curCost, double endTime) {\n        while (elapsed() < endTime) {\n            long long bestD = 0;\n            int bestType = 0, bi = -1, bj = -1;\n\n            for (int i = 0; i < M; i++) {\n                for (int j = i + 1; j < M; j++) {\n                    long long d = deltaSwapApprox(perm, i, j);\n                    if (d < bestD) {\n                        bestD = d;\n                        bestType = 1;\n                        bi = i; bj = j;\n                    }\n                }\n                if ((i & 15) == 0 && elapsed() >= endTime) break;\n            }\n            if (elapsed() >= endTime) break;\n\n            for (int i = 0; i < M; i++) {\n                for (int j = 0; j < M; j++) if (i != j) {\n                    long long d = deltaRelocateApprox(perm, i, j);\n                    if (d < bestD) {\n                        bestD = d;\n                        bestType = 2;\n                        bi = i; bj = j;\n                    }\n                }\n                if ((i & 7) == 0 && elapsed() >= endTime) break;\n            }\n            if (elapsed() >= endTime) break;\n\n            if (bestD >= 0) break;\n\n            if (bestType == 1) swap(perm[bi], perm[bj]);\n            else relocateMove(perm, bi, bj);\n            curCost += bestD;\n        }\n    }\n\n    void SAApprox(vector<int>& perm, long long& curCost, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm;\n        vector<int> bestPerm = perm;\n        long long curC = curCost;\n        long long bestC = curC;\n\n        const double T0 = 20.0, T1 = 0.03;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            int i = rng.nextInt(M);\n            int j = rng.nextInt(M - 1);\n            if (j >= i) j++;\n            bool sw = (rng.nextInt(100) < 55);\n\n            long long d = sw ? deltaSwapApprox(cur, i, j) : deltaRelocateApprox(cur, i, j);\n            if (d == 0) continue;\n\n            bool ok = (d <= 0) || (rng.nextDouble() < exp(-double(d) / temp));\n            if (!ok) continue;\n\n            if (sw) swap(cur[i], cur[j]);\n            else relocateMove(cur, i, j);\n            curC += d;\n\n            if (curC < bestC) {\n                bestC = curC;\n                bestPerm = cur;\n            }\n        }\n\n        perm = bestPerm;\n        curCost = bestC;\n    }\n\n    // exact cost of permutation via word-boundary DP on precomputed pair matrices\n    int exactCost(const vector<int>& perm) const {\n        int dpA[225], dpB[225];\n\n        int w0 = perm[0];\n        int sz = nEnd[w0];\n        for (int i = 0; i < sz; i++) dpA[i] = firstEndCost[w0][i];\n\n        for (int idx = 1; idx < M; idx++) {\n            int a = perm[idx - 1];\n            int b = perm[idx];\n            int na = nEnd[a];\n            int nb = nEnd[b];\n\n            for (int j = 0; j < nb; j++) dpB[j] = INF;\n\n            size_t id = (size_t)a * M + b;\n            const int* mat = transData.data() + transOffset[id];\n\n            for (int i = 0; i < na; i++) {\n                int base = dpA[i];\n                const int* row = mat + (size_t)i * nb;\n                for (int j = 0; j < nb; j++) {\n                    int cand = base + row[j];\n                    if (cand < dpB[j]) dpB[j] = cand;\n                }\n            }\n\n            for (int j = 0; j < nb; j++) dpA[j] = dpB[j];\n            sz = nb;\n        }\n\n        int ans = INF;\n        for (int i = 0; i < sz; i++) ans = min(ans, dpA[i]);\n        return ans;\n    }\n\n    void SAExact(vector<int>& perm, long long& approxCur, int& exactCur, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm;\n        vector<int> best = perm;\n        long long curA = approxCur, bestA = approxCur;\n        int curE = exactCur, bestE = exactCur;\n\n        const double T0 = 14.0, T1 = 0.05;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        int stagn = 0;\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            int i = rng.nextInt(M);\n            int j = rng.nextInt(M - 1);\n            if (j >= i) j++;\n            bool sw = (rng.nextInt(100) < 55);\n\n            long long dA = sw ? deltaSwapApprox(cur, i, j) : deltaRelocateApprox(cur, i, j);\n\n            // cheap prefilter: avoid spending exact eval on obviously bad approximate moves\n            if (dA > 180 && rng.nextInt(100) < 95) continue;\n\n            if (sw) swap(cur[i], cur[j]);\n            else relocateMove(cur, i, j);\n\n            int nc = exactCost(cur);\n            int dE = nc - curE;\n\n            bool ok = (dE <= 0) || (rng.nextDouble() < exp(-double(dE) / temp));\n            if (ok) {\n                curE = nc;\n                curA += dA;\n\n                if (curE < bestE || (curE == bestE && curA < bestA)) {\n                    bestE = curE;\n                    bestA = curA;\n                    best = cur;\n                    stagn = 0;\n                } else {\n                    stagn++;\n                }\n            } else {\n                if (sw) swap(cur[i], cur[j]);\n                else relocateMove(cur, j, i); // inverse\n                stagn++;\n            }\n\n            // light restart/perturbation\n            if (stagn > 8000) {\n                cur = best;\n                curE = bestE;\n                curA = bestA;\n\n                for (int rep = 0; rep < 3; rep++) {\n                    int a = rng.nextInt(M);\n                    int b = rng.nextInt(M - 1);\n                    if (b >= a) b++;\n                    bool sw2 = (rng.nextInt(100) < 50);\n                    long long dA2 = sw2 ? deltaSwapApprox(cur, a, b) : deltaRelocateApprox(cur, a, b);\n                    if (sw2) swap(cur[a], cur[b]);\n                    else relocateMove(cur, a, b);\n                    curA += dA2;\n                }\n                curE = exactCost(cur);\n                stagn = 0;\n            }\n        }\n\n        perm = best;\n        approxCur = bestA;\n        exactCur = bestE;\n    }\n\n    void buildString(const vector<int>& perm, string& out) const {\n        out.clear();\n        out.reserve(5 * M);\n        out += words[perm[0]];\n        for (int i = 1; i < M; i++) {\n            int a = perm[i - 1];\n            int b = perm[i];\n            int k = ov[a][b];\n            for (int p = k; p < 5; p++) out.push_back(words[b][p]);\n        }\n    }\n\n    vector<int> bestPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<short>> parent(L, vector<short>(V, -1));\n\n        vector<int> prev(V, INF), cur(V, INF);\n        vector<int> prevCells = occ[s[0] - 'A'];\n\n        for (int q : prevCells) prev[q] = distMat[startId][q] + 1;\n\n        for (int idx = 1; idx < L; idx++) {\n            const vector<int>& nextCells = occ[s[idx] - 'A'];\n\n            for (int q : nextCells) {\n                int best = INF;\n                short bp = -1;\n                for (int p : prevCells) {\n                    int cand = prev[p] + distMat[p][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bp = (short)p;\n                    }\n                }\n                cur[q] = best;\n                parent[idx][q] = bp;\n            }\n\n            for (int p : prevCells) prev[p] = INF;\n            prevCells = nextCells;\n            for (int q : prevCells) {\n                prev[q] = cur[q];\n                cur[q] = INF;\n            }\n        }\n\n        int endCell = -1, best = INF;\n        for (int p : prevCells) {\n            if (prev[p] < best) {\n                best = prev[p];\n                endCell = p;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = endCell;\n        for (int i = L - 1; i >= 1; i--) {\n            path[i - 1] = parent[i][path[i]];\n        }\n        return path;\n    }\n\n    void solve() {\n        readInput();\n        rng = XorShift64(makeSeed());\n        t0 = chrono::steady_clock::now();\n\n        preprocess();\n\n        vector<vector<int>> candidates;\n        candidates.reserve(20);\n\n        vector<int> nn = nearestAllStarts();\n        candidates.push_back(nn);\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 (startCostApprox[a] != startCostApprox[b]) return startCostApprox[a] < startCostApprox[b];\n            return a < b;\n        });\n\n        vector<char> usedSeed(M, 0);\n        auto addSeed = [&](int s) {\n            if (usedSeed[s]) return;\n            usedSeed[s] = 1;\n            candidates.push_back(cheapestInsertion(s));\n        };\n\n        addSeed(nn[0]);\n        for (int i = 0; i < min(M, 8); i++) addSeed(ord[i]);\n        for (int t = 0; t < 6; t++) addSeed(rng.nextInt(M));\n\n        int bestAIdx = 0, bestEIdx = 0;\n        long long bestA = (1LL << 60);\n        int bestE = INF;\n\n        vector<long long> candA(candidates.size());\n        vector<int> candE(candidates.size());\n\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            candA[i] = approxCost(candidates[i]);\n            if (candA[i] < bestA) {\n                bestA = candA[i];\n                bestAIdx = i;\n            }\n        }\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            candE[i] = exactCost(candidates[i]);\n            if (candE[i] < bestE) {\n                bestE = candE[i];\n                bestEIdx = i;\n            }\n        }\n\n        vector<int> perm = candidates[bestAIdx];\n        long long curA = candA[bestAIdx];\n\n        double T_LIMIT = 1.92;\n        double approxEnd = min(1.00, elapsed() + 0.30);\n        if (elapsed() < approxEnd) {\n            double lsEnd = min(approxEnd, elapsed() + 0.10);\n            localSearchApprox(perm, curA, lsEnd);\n            SAApprox(perm, curA, approxEnd);\n        }\n\n        int curE = exactCost(perm);\n\n        if (bestE < curE) {\n            perm = candidates[bestEIdx];\n            curA = candA[bestEIdx];\n            curE = bestE;\n        }\n\n        double exactEnd = T_LIMIT - 0.03;\n        SAExact(perm, curA, curE, exactEnd);\n\n        string finalS;\n        buildString(perm, finalS);\n\n        vector<int> path = bestPathForString(finalS);\n\n        for (int id : path) {\n            cout << (id / N) << ' ' << (id % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Mask {\n    static constexpr int W = 7; // 7*64=448 >= 400\n    array<uint64_t, W> w{};\n    Mask() { w.fill(0ULL); }\n    inline void set(int idx) { w[idx >> 6] |= (1ULL << (idx & 63)); }\n    inline bool test(int idx) const { return (w[idx >> 6] >> (idx & 63)) & 1ULL; }\n};\n\nstruct Placement {\n    vector<int> cells;\n    Mask mask;\n    vector<uint8_t> qcov; // for drilled query cells\n};\n\nclass OilSolver {\n    struct ArrHash {\n        size_t operator()(array<uint64_t, Mask::W> const& a) const noexcept {\n            uint64_t h = 0x9e3779b97f4a7c15ULL;\n            for (uint64_t x : a) {\n                x ^= x >> 30;\n                x *= 0xbf58476d1ce4e5b9ULL;\n                x ^= x >> 27;\n                x *= 0x94d049bb133111ebULL;\n                x ^= x >> 31;\n                h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n            }\n            return (size_t)h;\n        }\n    };\n\n    struct UnionCand {\n        array<uint64_t, Mask::W> m{};\n        int cnt = 0;\n    };\n\n    int N = 0, M = 0, n2 = 0;\n    double eps = 0.0;\n\n    vector<vector<pair<int,int>>> shapes;\n    vector<vector<Placement>> fieldPls; // [field][placement]\n\n    vector<int> drilledVal; // -1 unknown, else exact v\n    vector<int> qidOfCell;  // cell -> drilled query id\n    vector<int> queryVals;\n    vector<int> queryCells;\n    vector<int> positiveDrilled;\n\n    vector<int> priorOrder;\n    int priorPtr = 0;\n\n    vector<array<uint64_t, Mask::W>> forbiddenMasks; // wrong guessed unions\n\n    mt19937 rng;\n    int ops = 0;\n    int wrongGuesses = 0;\n\n    chrono::steady_clock::time_point startTime;\n\n    static constexpr double HARD_LIMIT_MS = 2850.0;\n    static constexpr double EMERGENCY_MS = 2650.0;\n    static constexpr int MAX_WRONG_GUESSES = 10;\n    static constexpr int INFER_DRILL_LIMIT = 170;\n\npublic:\n    OilSolver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        n2 = N * N;\n        shapes.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int d; cin >> d;\n            shapes[k].resize(d);\n            for (int t = 0; t < d; t++) {\n                int i, j; cin >> i >> j;\n                shapes[k][t] = {i, j};\n            }\n        }\n        drilledVal.assign(n2, -1);\n        qidOfCell.assign(n2, -1);\n    }\n\n    void build_placements() {\n        fieldPls.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int maxr = 0, maxc = 0;\n            for (auto [r, c] : shapes[k]) {\n                maxr = max(maxr, r);\n                maxc = max(maxc, c);\n            }\n            for (int di = 0; di + maxr < N; di++) {\n                for (int dj = 0; dj + maxc < N; dj++) {\n                    Placement pl;\n                    pl.cells.reserve(shapes[k].size());\n                    pl.qcov.reserve(n2);\n                    for (auto [r, c] : shapes[k]) {\n                        int idx = (di + r) * N + (dj + c);\n                        pl.cells.push_back(idx);\n                        pl.mask.set(idx);\n                    }\n                    fieldPls[k].push_back(move(pl));\n                }\n            }\n        }\n    }\n\n    void build_prior_order() {\n        vector<vector<int>> coverCnt(M, vector<int>(n2, 0));\n        for (int k = 0; k < M; k++) {\n            for (const auto& pl : fieldPls[k]) {\n                for (int idx : pl.cells) coverCnt[k][idx]++;\n            }\n        }\n\n        vector<double> score(n2, 0.0);\n        for (int idx = 0; idx < n2; idx++) {\n            double p0 = 1.0;\n            for (int k = 0; k < M; k++) {\n                double pk = (double)coverCnt[k][idx] / (double)fieldPls[k].size();\n                p0 *= (1.0 - pk);\n            }\n            double p = 1.0 - p0;\n            score[idx] = p * (1.0 - p);\n        }\n\n        priorOrder.resize(n2);\n        iota(priorOrder.begin(), priorOrder.end(), 0);\n        sort(priorOrder.begin(), priorOrder.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return a < b;\n        });\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << \" \" << (idx % N) << '\\n' << flush;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    int ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int idx : cells) cout << \" \" << (idx / N) << \" \" << (idx % N);\n        cout << '\\n' << flush;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    void add_drill(int idx, int val) {\n        if (drilledVal[idx] != -1) return;\n        drilledVal[idx] = val;\n\n        int qid = (int)queryVals.size();\n        qidOfCell[idx] = qid;\n        queryVals.push_back(val);\n        queryCells.push_back(idx);\n        if (val > 0) positiveDrilled.push_back(idx);\n\n        for (int k = 0; k < M; k++) {\n            for (auto& pl : fieldPls[k]) {\n                pl.qcov.push_back(pl.mask.test(idx) ? 1 : 0);\n            }\n        }\n    }\n\n    int pick_prior_cell() {\n        while (priorPtr < (int)priorOrder.size() && drilledVal[priorOrder[priorPtr]] != -1) priorPtr++;\n        if (priorPtr < (int)priorOrder.size()) return priorOrder[priorPtr++];\n        return -1;\n    }\n\n    int first_unknown_cell() const {\n        for (int i = 0; i < n2; i++) if (drilledVal[i] == -1) return i;\n        return -1;\n    }\n\n    int pick_frontier_cell() const {\n        static const int di[4] = {-1, 1, 0, 0};\n        static const int dj[4] = {0, 0, -1, 1};\n        int best = -1, bestScore = -1;\n\n        for (int idx : positiveDrilled) {\n            int i = idx / N, j = idx % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nid = ni * N + nj;\n                if (drilledVal[nid] != -1) continue;\n\n                int sc = 0;\n                for (int d2 = 0; d2 < 4; d2++) {\n                    int xi = ni + di[d2], xj = nj + dj[d2];\n                    if (xi < 0 || xi >= N || xj < 0 || xj >= N) continue;\n                    int xid = xi * N + xj;\n                    if (drilledVal[xid] > 0) sc++;\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = nid;\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<int> exact_from_drilled() const {\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int i = 0; i < n2; i++) if (drilledVal[i] > 0) ans.push_back(i);\n        return ans;\n    }\n\n    static inline void set_bit(array<uint64_t, Mask::W>& m, int idx) {\n        m[idx >> 6] |= (1ULL << (idx & 63));\n    }\n\n    bool is_forbidden(const array<uint64_t, Mask::W>& m) const {\n        for (const auto& x : forbiddenMasks) if (x == m) return true;\n        return false;\n    }\n\n    void add_forbidden(const array<uint64_t, Mask::W>& m) {\n        if (!is_forbidden(m)) forbiddenMasks.push_back(m);\n    }\n\n    void normalize_mask(array<uint64_t, Mask::W>& m) const {\n        for (int idx : positiveDrilled) set_bit(m, idx);\n    }\n\n    array<uint64_t, Mask::W> build_union_mask(const vector<int>& asg) const {\n        array<uint64_t, Mask::W> m{};\n        m.fill(0ULL);\n        for (int k = 0; k < M; k++) {\n            int p = asg[k];\n            if (p < 0) continue;\n            for (int wi = 0; wi < Mask::W; wi++) m[wi] |= fieldPls[k][p].mask.w[wi];\n        }\n        return m;\n    }\n\n    vector<int> mask_to_cells(const array<uint64_t, Mask::W>& m) const {\n        vector<int> cells;\n        cells.reserve(n2);\n        for (int wi = 0; wi < Mask::W; wi++) {\n            uint64_t bits = m[wi];\n            while (bits) {\n                int b = __builtin_ctzll(bits);\n                int idx = wi * 64 + b;\n                if (idx < n2) cells.push_back(idx);\n                bits &= bits - 1;\n            }\n        }\n        return cells;\n    }\n\n    bool can_afford_guess(int safety = 3) const {\n        int maxOps = 2 * n2;\n        int unknown = n2 - (int)queryVals.size();\n        return (maxOps - ops) > (unknown + safety);\n    }\n\n    int submit_guess_mask(array<uint64_t, Mask::W> m) {\n        normalize_mask(m);\n        if (is_forbidden(m)) return -1;\n\n        vector<int> cells = mask_to_cells(m);\n        int res = ask_answer(cells);\n        ops++;\n\n        if (res == 1) return 1;\n\n        wrongGuesses++;\n        add_forbidden(m);\n        return 0;\n    }\n\n    void fill_all_domains(vector<vector<int>>& domains) const {\n        domains.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            domains[k].resize(fieldPls[k].size());\n            iota(domains[k].begin(), domains[k].end(), 0);\n        }\n    }\n\n    bool propagate_domains(vector<vector<int>>& domains) {\n        domains.assign(M, {});\n        int q = (int)queryVals.size();\n\n        if (q == 0) {\n            fill_all_domains(domains);\n            return true;\n        }\n\n        vector<vector<uint8_t>> active(M);\n        for (int k = 0; k < M; k++) active[k].assign(fieldPls[k].size(), 1);\n\n        int maxIt = 10;\n        if (q > 40) maxIt = 7;\n        if (q > 80) maxIt = 5;\n        if (q > 140) maxIt = 3;\n        if (elapsed_ms() > 2200.0) maxIt = min(maxIt, 2);\n\n        for (int it = 0; it < maxIt; it++) {\n            if (elapsed_ms() > 2720.0) break;\n\n            vector<int> domSize(M, 0);\n            vector<vector<int>> cnt1(M, vector<int>(q, 0));\n\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    domSize[k]++;\n                    const auto& qc = pls[p].qcov;\n                    for (int r = 0; r < q; r++) cnt1[k][r] += qc[r];\n                }\n            }\n\n            for (int k = 0; k < M; k++) if (domSize[k] == 0) return false;\n\n            vector<vector<int8_t>> minv(M, vector<int8_t>(q, 0));\n            vector<vector<int8_t>> maxv(M, vector<int8_t>(q, 0));\n            vector<int> totalMin(q, 0), totalMax(q, 0);\n\n            for (int r = 0; r < q; r++) {\n                int tmin = 0, tmax = 0;\n                for (int k = 0; k < M; k++) {\n                    bool has1 = cnt1[k][r] > 0;\n                    bool has0 = (domSize[k] - cnt1[k][r]) > 0;\n                    int mn = has0 ? 0 : 1;\n                    int mx = has1 ? 1 : 0;\n                    minv[k][r] = (int8_t)mn;\n                    maxv[k][r] = (int8_t)mx;\n                    tmin += mn;\n                    tmax += mx;\n                }\n                totalMin[r] = tmin;\n                totalMax[r] = tmax;\n                int y = queryVals[r];\n                if (y < tmin || y > tmax) return false;\n            }\n\n            bool changed = false;\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    const auto& qc = pls[p].qcov;\n                    bool ok = true;\n                    for (int r = 0; r < q; r++) {\n                        int need = queryVals[r] - (int)qc[r];\n                        int lo = totalMin[r] - (int)minv[k][r];\n                        int hi = totalMax[r] - (int)maxv[k][r];\n                        if (need < lo || need > hi) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) {\n                        active[k][p] = 0;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        for (int k = 0; k < M; k++) {\n            for (int p = 0; p < (int)fieldPls[k].size(); p++) if (active[k][p]) {\n                domains[k].push_back(p);\n            }\n            if (domains[k].empty()) return false;\n        }\n        return true;\n    }\n\n    vector<vector<int>> sample_solutions(\n        const vector<vector<int>>& domains,\n        int maxSol,\n        long long nodeLimit,\n        int baseTimeMs\n    ) {\n        vector<vector<int>> sols;\n        if (maxSol <= 0) return sols;\n\n        int q = (int)queryVals.size();\n        if (q == 0) {\n            int trials = maxSol * 4;\n            for (int t = 0; t < trials && (int)sols.size() < maxSol; t++) {\n                vector<int> asg(M, -1);\n                for (int k = 0; k < M; k++) {\n                    const auto& d = domains[k];\n                    asg[k] = d[rng() % d.size()];\n                }\n                auto m = build_union_mask(asg);\n                normalize_mask(m);\n                if (is_forbidden(m)) continue;\n                sols.push_back(move(asg));\n            }\n            return sols;\n        }\n\n        if (elapsed_ms() > 2500.0) return sols;\n        double rem = HARD_LIMIT_MS - elapsed_ms();\n        if (rem < 20.0) return sols;\n\n        int timeMs = min(baseTimeMs, (int)max(6.0, rem - 12.0));\n        auto deadline = chrono::steady_clock::now() + chrono::milliseconds(timeMs);\n\n        vector<vector<int8_t>> varMin(M, vector<int8_t>(q, 0));\n        vector<vector<int8_t>> varMax(M, vector<int8_t>(q, 0));\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            vector<int> c1(q, 0);\n            for (int p : domains[k]) {\n                const auto& qc = fieldPls[k][p].qcov;\n                for (int r = 0; r < q; r++) c1[r] += qc[r];\n            }\n            for (int r = 0; r < q; r++) {\n                bool has1 = c1[r] > 0;\n                bool has0 = (ds - c1[r]) > 0;\n                varMin[k][r] = has0 ? 0 : 1;\n                varMax[k][r] = has1 ? 1 : 0;\n            }\n        }\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (domains[a].size() != domains[b].size()) return domains[a].size() < domains[b].size();\n            return a < b;\n        });\n\n        vector<vector<int>> sufMin(M + 1, vector<int>(q, 0));\n        vector<vector<int>> sufMax(M + 1, vector<int>(q, 0));\n        for (int d = M - 1; d >= 0; d--) {\n            int k = order[d];\n            for (int r = 0; r < q; r++) {\n                sufMin[d][r] = sufMin[d + 1][r] + (int)varMin[k][r];\n                sufMax[d][r] = sufMax[d + 1][r] + (int)varMax[k][r];\n            }\n        }\n        for (int r = 0; r < q; r++) {\n            if (queryVals[r] < sufMin[0][r] || queryVals[r] > sufMax[0][r]) return sols;\n        }\n\n        vector<vector<int>> domOrd = domains;\n        vector<int> assign(M, -1), target = queryVals;\n        long long nodes = 0;\n        bool stop = false;\n\n        auto over = [&]() -> bool {\n            if (nodes > nodeLimit) return true;\n            if (chrono::steady_clock::now() >= deadline) return true;\n            if (elapsed_ms() > HARD_LIMIT_MS - 35.0) return true;\n            return false;\n        };\n\n        function<void(int)> dfs = [&](int depth) {\n            if (stop || (int)sols.size() >= maxSol) return;\n\n            if (depth == M) {\n                for (int r = 0; r < q; r++) if (target[r] != 0) return;\n                auto m = build_union_mask(assign);\n                normalize_mask(m);\n                if (!is_forbidden(m)) sols.push_back(assign);\n                return;\n            }\n\n            int k = order[depth];\n            auto& plist = domOrd[k];\n\n            for (int p : plist) {\n                nodes++;\n                if ((nodes & 1023LL) == 0 && over()) {\n                    stop = true;\n                    return;\n                }\n\n                const auto& qc = fieldPls[k][p].qcov;\n                bool ok = true;\n                for (int r = 0; r < q; r++) {\n                    int nt = target[r] - (int)qc[r];\n                    if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (!ok) continue;\n\n                assign[k] = p;\n                for (int r = 0; r < q; r++) target[r] -= (int)qc[r];\n                dfs(depth + 1);\n                for (int r = 0; r < q; r++) target[r] += (int)qc[r];\n\n                if (stop || (int)sols.size() >= maxSol) return;\n            }\n\n            assign[k] = -1;\n        };\n\n        int restarts = 0;\n        while (!stop && (int)sols.size() < maxSol && restarts < 3) {\n            for (int k = 0; k < M; k++) if (domOrd[k].size() > 1) shuffle(domOrd[k].begin(), domOrd[k].end(), rng);\n            fill(assign.begin(), assign.end(), -1);\n            target = queryVals;\n            dfs(0);\n            restarts++;\n        }\n\n        if ((int)sols.size() < max(4, maxSol / 4) && chrono::steady_clock::now() < deadline) {\n            int attempts = 80;\n            for (int at = 0; at < attempts && (int)sols.size() < maxSol; at++) {\n                if (chrono::steady_clock::now() >= deadline) break;\n                vector<int> t = queryVals;\n                vector<int> asg(M, -1);\n                bool fail = false;\n\n                for (int depth = 0; depth < M; depth++) {\n                    int k = order[depth];\n                    int chosen = -1;\n                    int feasCnt = 0;\n\n                    for (int p : domOrd[k]) {\n                        const auto& qc = fieldPls[k][p].qcov;\n                        bool ok = true;\n                        for (int r = 0; r < q; r++) {\n                            int nt = t[r] - (int)qc[r];\n                            if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                                ok = false;\n                                break;\n                            }\n                        }\n                        if (!ok) continue;\n\n                        feasCnt++;\n                        if ((int)(rng() % feasCnt) == 0) chosen = p;\n                    }\n\n                    if (chosen == -1) {\n                        fail = true;\n                        break;\n                    }\n\n                    asg[k] = chosen;\n                    const auto& qc = fieldPls[k][chosen].qcov;\n                    for (int r = 0; r < q; r++) t[r] -= (int)qc[r];\n                }\n\n                if (fail) continue;\n                bool exact = true;\n                for (int r = 0; r < q; r++) if (t[r] != 0) { exact = false; break; }\n                if (!exact) continue;\n\n                auto m = build_union_mask(asg);\n                normalize_mask(m);\n                if (is_forbidden(m)) continue;\n                sols.push_back(move(asg));\n            }\n        }\n\n        return sols;\n    }\n\n    vector<UnionCand> build_union_candidates(const vector<vector<int>>& sols, vector<int>& freq, int& totalCnt) {\n        unordered_map<array<uint64_t, Mask::W>, int, ArrHash> mp;\n        vector<UnionCand> cands;\n\n        for (const auto& asg : sols) {\n            auto m = build_union_mask(asg);\n            normalize_mask(m);\n            if (is_forbidden(m)) continue;\n\n            auto it = mp.find(m);\n            if (it == mp.end()) {\n                int id = (int)cands.size();\n                mp.emplace(m, id);\n                UnionCand uc;\n                uc.m = m;\n                uc.cnt = 1;\n                cands.push_back(move(uc));\n            } else {\n                cands[it->second].cnt++;\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [&](const UnionCand& a, const UnionCand& b) {\n            return a.cnt > b.cnt;\n        });\n\n        totalCnt = 0;\n        for (auto& c : cands) totalCnt += c.cnt;\n\n        freq.assign(n2, 0);\n        if (totalCnt == 0) return cands;\n\n        for (const auto& c : cands) {\n            int add = c.cnt;\n            for (int wi = 0; wi < Mask::W; wi++) {\n                uint64_t bits = c.m[wi];\n                while (bits) {\n                    int b = __builtin_ctzll(bits);\n                    int idx = wi * 64 + b;\n                    if (idx < n2) freq[idx] += add;\n                    bits &= bits - 1;\n                }\n            }\n        }\n\n        return cands;\n    }\n\n    int choose_uncertain_cell(const vector<int>& freq, int S) const {\n        if (S <= 0) return -1;\n        int best = -1;\n        double bestScore = -1.0;\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            int f = freq[idx];\n            if (f == 0 || f == S) continue;\n            double p = (double)f / (double)S;\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    int choose_entropy_cell(const vector<vector<int>>& domains) const {\n        vector<double> p0(n2, 1.0);\n        vector<int> cnt(n2, 0);\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            if (ds <= 0) continue;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            for (int p : domains[k]) {\n                for (int idx : fieldPls[k][p].cells) cnt[idx]++;\n            }\n\n            double inv = 1.0 / (double)ds;\n            for (int idx = 0; idx < n2; idx++) {\n                if (drilledVal[idx] != -1) continue;\n                if (cnt[idx] == 0) continue;\n                double pk = cnt[idx] * inv;\n                p0[idx] *= (1.0 - pk);\n            }\n        }\n\n        int best = -1;\n        double bestScore = -1.0;\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            double p = 1.0 - p0[idx];\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        const int maxOps = 2 * n2;\n        int turn = 0;\n\n        while (ops < maxOps) {\n            turn++;\n            int drilledCnt = (int)queryVals.size();\n            int unknown = n2 - drilledCnt;\n\n            if (unknown == 0) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    (void)res;\n                }\n                return;\n            }\n\n            double now = elapsed_ms();\n            bool emergency = (now > EMERGENCY_MS || now > HARD_LIMIT_MS - 80.0);\n\n            int next = -1;\n            vector<vector<int>> domains;\n            bool haveDomains = false;\n\n            bool allowInference = (!emergency && drilledCnt <= INFER_DRILL_LIMIT);\n\n            if (allowInference) {\n                haveDomains = propagate_domains(domains);\n            }\n\n            if (haveDomains) {\n                bool unique = true;\n                vector<int> asg(M, -1);\n                for (int k = 0; k < M; k++) {\n                    if (domains[k].size() != 1) { unique = false; break; }\n                    asg[k] = domains[k][0];\n                }\n                if (unique && can_afford_guess(2) && wrongGuesses < MAX_WRONG_GUESSES) {\n                    int r = submit_guess_mask(build_union_mask(asg));\n                    if (r == 1) return;\n                    if (r == 0) continue;\n                }\n\n                int interval = (drilledCnt < 25 ? 1 : (drilledCnt < 70 ? 2 : 3));\n                bool doSample = (drilledCnt >= 4 && (turn % interval == 0) && elapsed_ms() < 2450.0);\n\n                if (doSample) {\n                    double rem = HARD_LIMIT_MS - elapsed_ms();\n                    if (rem > 20.0) {\n                        int maxSol = 30;\n                        long long nodeLimit = 140000;\n                        int tMs = 10;\n\n                        if (drilledCnt >= 20 && drilledCnt < 60) {\n                            maxSol = 42;\n                            nodeLimit = 260000;\n                            tMs = 14;\n                        } else if (drilledCnt >= 60) {\n                            maxSol = 36;\n                            nodeLimit = 220000;\n                            tMs = 10;\n                        }\n\n                        tMs = min(tMs, (int)max(6.0, rem * 0.20));\n\n                        auto sols = sample_solutions(domains, maxSol, nodeLimit, tMs);\n\n                        if (!sols.empty()) {\n                            vector<int> freq;\n                            int total = 0;\n                            auto cands = build_union_candidates(sols, freq, total);\n\n                            if (total > 0) {\n                                double topProb = (double)cands[0].cnt / (double)total;\n\n                                bool shouldGuess = false;\n                                if (can_afford_guess(3) && wrongGuesses < MAX_WRONG_GUESSES) {\n                                    if ((int)cands.size() == 1 && total >= 4) shouldGuess = true;\n                                    else if (topProb >= 0.90 && total >= 8) shouldGuess = true;\n                                    else if (topProb >= 0.80 && total >= 12 && drilledCnt >= 10) shouldGuess = true;\n                                    else if (topProb >= 0.70 && total >= 18 && drilledCnt >= 24) shouldGuess = true;\n                                }\n\n                                if (shouldGuess) {\n                                    int r = submit_guess_mask(cands[0].m);\n                                    if (r == 1) return;\n                                    if (r == 0) continue;\n                                }\n\n                                next = choose_uncertain_cell(freq, total);\n\n                                if (next == -1 && can_afford_guess(2) && wrongGuesses < MAX_WRONG_GUESSES) {\n                                    if ((int)cands.size() == 1 && total >= 3) {\n                                        int r = submit_guess_mask(cands[0].m);\n                                        if (r == 1) return;\n                                        if (r == 0) continue;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                if (next == -1) {\n                    next = choose_entropy_cell(domains);\n                }\n            }\n\n            if (next == -1) {\n                int f = pick_frontier_cell();\n                if (f != -1) next = f;\n            }\n\n            if (next == -1) {\n                if (drilledCnt < min(8, N)) next = pick_prior_cell();\n                if (next == -1) next = pick_prior_cell();\n                if (next == -1) next = first_unknown_cell();\n            }\n\n            if (next == -1) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    if (res == 1) return;\n                }\n                return;\n            }\n\n            int v = ask_drill(next);\n            ops++;\n            add_drill(next, v);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    OilSolver solver;\n    solver.read_input();\n    solver.build_placements();\n    solver.build_prior_order();\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\nusing ll = long long;\n\nstruct Iseg {\n    int c, l, r; // coordinate c, interval [l, r)\n    bool operator==(const Iseg& o) const {\n        return c == o.c && l == o.l && r == o.r;\n    }\n};\n\nstruct Candidate {\n    vector<array<int, 4>> rects; // by request rank k\n    vector<Iseg> hsegs;          // y=c, x in [l, r)\n    vector<Iseg> vsegs;          // x=c, y in [l, r)\n    vector<int> areas;           // sorted cell areas\n    ll shortage = 0;\n    int boundaryLen = 0;\n    uint64_t hash = 0;\n    unsigned char src = 0;       // bit: 1 local, 2 global-proto, 4 path-proto\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 shape_hash(const vector<Iseg>& H, const vector<Iseg>& V) {\n    uint64_t h = 0x123456789abcdefULL;\n    auto add = [&](uint64_t v) {\n        h ^= splitmix64(v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));\n    };\n\n    add((uint64_t)H.size() + 0x11111111ULL);\n    for (auto& s : H) {\n        uint64_t p = ((uint64_t)s.c << 22) ^ ((uint64_t)s.l << 11) ^ (uint64_t)s.r;\n        add((p << 1) | 1ULL);\n    }\n    add(0xfedcba987654321ULL);\n    add((uint64_t)V.size() + 0x22222222ULL);\n    for (auto& s : V) {\n        uint64_t p = ((uint64_t)s.c << 22) ^ ((uint64_t)s.l << 11) ^ (uint64_t)s.r;\n        add((p << 1) | 0ULL);\n    }\n    return h;\n}\n\nstatic vector<Iseg> merge_segments(vector<Iseg> segs) {\n    sort(segs.begin(), segs.end(), [](const Iseg& a, const Iseg& b) {\n        if (a.c != b.c) return a.c < b.c;\n        if (a.l != b.l) return a.l < b.l;\n        return a.r < b.r;\n    });\n\n    vector<Iseg> out;\n    out.reserve(segs.size());\n    for (auto& s : segs) {\n        if (s.l >= s.r) continue;\n        if (out.empty() || out.back().c != s.c || s.l > out.back().r) {\n            out.push_back(s);\n        } else {\n            out.back().r = max(out.back().r, s.r);\n        }\n    }\n    return out;\n}\n\nstatic ll calc_shortage(const vector<int>& dayA, const vector<int>& areasSorted) {\n    ll sh = 0;\n    int N = (int)dayA.size();\n    for (int k = 0; k < N; k++) {\n        if (areasSorted[k] < dayA[k]) sh += 100LL * (dayA[k] - areasSorted[k]);\n    }\n    return sh;\n}\n\nstatic inline ll rect_area(const array<int, 4>& r) {\n    return 1LL * (r[2] - r[0]) * (r[3] - r[1]);\n}\n\n// Build candidate from arbitrary cell list (size N), with optimal (area-sorted) assignment to requests.\nstatic Candidate build_candidate_from_cells(\n    int W,\n    const vector<int>& dayA,\n    const vector<array<int, 4>>& cells,\n    unsigned char src = 1\n) {\n    int N = (int)dayA.size();\n    Candidate c;\n    c.src = src;\n    c.rects.resize(N);\n    c.areas.resize(N);\n\n    vector<pair<ll, int>> ord;\n    ord.reserve(N);\n    for (int i = 0; i < N; i++) ord.push_back({rect_area(cells[i]), i});\n    sort(ord.begin(), ord.end(), [](auto& a, auto& b) {\n        if (a.first != b.first) return a.first < b.first;\n        return a.second < b.second;\n    });\n\n    for (int k = 0; k < N; k++) {\n        c.rects[k] = cells[ord[k].second];\n        c.areas[k] = (int)ord[k].first;\n    }\n\n    c.shortage = calc_shortage(dayA, c.areas);\n\n    vector<Iseg> rawH, rawV;\n    rawH.reserve(2 * N);\n    rawV.reserve(2 * N);\n\n    for (auto& rc : cells) {\n        int y0 = rc[0], x0 = rc[1], y1 = rc[2], x1 = rc[3];\n        if (y0 > 0) rawH.push_back({y0, x0, x1});\n        if (y1 < W) rawH.push_back({y1, x0, x1});\n        if (x0 > 0) rawV.push_back({x0, y0, y1});\n        if (x1 < W) rawV.push_back({x1, y0, y1});\n    }\n\n    c.hsegs = merge_segments(move(rawH));\n    c.vsegs = merge_segments(move(rawV));\n\n    ll bl = 0;\n    for (auto& s : c.hsegs) bl += (s.r - s.l);\n    for (auto& s : c.vsegs) bl += (s.r - s.l);\n    c.boundaryLen = (int)bl;\n\n    c.hash = shape_hash(c.hsegs, c.vsegs);\n    return c;\n}\n\nstatic Candidate clone_for_day(const Candidate& proto, const vector<int>& dayA, unsigned char srcOverride = 0) {\n    Candidate c = proto;\n    c.shortage = calc_shortage(dayA, c.areas);\n    if (srcOverride) c.src = srcOverride;\n    return c;\n}\n\nstatic Candidate transpose_candidate(const Candidate& base, int W, const vector<int>& dayA, unsigned char srcOverride = 0) {\n    (void)W;\n    vector<array<int, 4>> cells = base.rects;\n    for (auto& r : cells) {\n        swap(r[0], r[1]);\n        swap(r[2], r[3]);\n    }\n    return build_candidate_from_cells(W, dayA, cells, srcOverride ? srcOverride : base.src);\n}\n\nstatic bool same_shape(const Candidate& a, const Candidate& b) {\n    if (a.hash != b.hash) return false;\n    return a.hsegs == b.hsegs && a.vsegs == b.vsegs;\n}\n\nstatic ll symdiff_len(const vector<Iseg>& A, const vector<Iseg>& B) {\n    ll cost = 0;\n    int i = 0, j = 0;\n\n    while (i < (int)A.size() || j < (int)B.size()) {\n        int c;\n        if (j == (int)B.size() || (i < (int)A.size() && A[i].c < B[j].c)) c = A[i].c;\n        else c = B[j].c;\n\n        int i0 = i, j0 = j;\n        while (i < (int)A.size() && A[i].c == c) i++;\n        while (j < (int)B.size() && B[j].c == c) j++;\n\n        ll lenA = 0, lenB = 0;\n        for (int p = i0; p < i; p++) lenA += (A[p].r - A[p].l);\n        for (int q = j0; q < j; q++) lenB += (B[q].r - B[q].l);\n\n        ll inter = 0;\n        int p = i0, q = j0;\n        while (p < i && q < j) {\n            int L = max(A[p].l, B[q].l);\n            int R = min(A[p].r, B[q].r);\n            if (R > L) inter += (R - L);\n            if (A[p].r < B[q].r) p++;\n            else q++;\n        }\n\n        cost += lenA + lenB - 2LL * inter;\n    }\n\n    return cost;\n}\n\nstatic inline ll transition_cost(const Candidate& A, const Candidate& B) {\n    return symdiff_len(A.hsegs, B.hsegs) + symdiff_len(A.vsegs, B.vsegs);\n}\n\nstatic int min_height_segment(const vector<int>& arr, int l, int r, int W) {\n    auto ok = [&](int h) -> bool {\n        ll sw = 0;\n        for (int i = l; i < r; i++) {\n            sw += (arr[i] + h - 1) / h;\n            if (sw > W) return false;\n        }\n        return true;\n    };\n    if (!ok(W)) return W + 1;\n\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (ok(mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nstatic int closest_feasible(const vector<int>& feasible, int t) {\n    auto it = lower_bound(feasible.begin(), feasible.end(), t);\n    if (it == feasible.begin()) return *it;\n    if (it == feasible.end()) return feasible.back();\n    int a = *it, b = *prev(it);\n    if (abs(a - t) < abs(b - t)) return a;\n    return b;\n}\n\nstatic vector<int> sample_rows(const vector<int>& feasible, int cap) {\n    if (feasible.empty()) return {};\n    if ((int)feasible.size() <= cap) return feasible;\n    cap = max(cap, 1);\n\n    set<int> S;\n    auto add_t = [&](int t) { S.insert(closest_feasible(feasible, t)); };\n\n    add_t(1); add_t(2); add_t(3); add_t(4); add_t(5); add_t(8); add_t(12);\n    add_t(feasible.back());\n\n    int m = (int)feasible.size();\n    for (int i = 0; i < cap; i++) {\n        int idx = (int)(1LL * i * (m - 1) / max(1, cap - 1));\n        S.insert(feasible[idx]);\n    }\n\n    vector<int> ret(S.begin(), S.end());\n    if ((int)ret.size() > cap) {\n        vector<int> tmp;\n        for (int i = 0; i < cap; i++) {\n            int idx = (int)(1LL * i * ((int)ret.size() - 1) / max(1, cap - 1));\n            tmp.push_back(ret[idx]);\n        }\n        sort(tmp.begin(), tmp.end());\n        tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());\n        ret.swap(tmp);\n    }\n\n    if ((int)ret.size() < cap) {\n        for (int v : feasible) {\n            if ((int)ret.size() >= cap) break;\n            if (!binary_search(ret.begin(), ret.end(), v)) {\n                ret.push_back(v);\n                sort(ret.begin(), ret.end());\n            }\n        }\n        if ((int)ret.size() > cap) ret.resize(cap);\n    }\n\n    return ret;\n}\n\nstatic vector<int> snapped_variant(const vector<int>& hmin, int slack, int W, int Q, int mode) {\n    int rr = (int)hmin.size();\n    vector<int> pref(rr + 1, 0);\n    for (int i = 0; i < rr; i++) pref[i + 1] = pref[i] + hmin[i];\n\n    vector<int> inc(rr + 1, 0); // prefix extra\n    inc[0] = 0;\n    inc[rr] = slack;\n\n    int prev = 0;\n    for (int t = 1; t < rr; t++) {\n        int p = pref[t];\n        int targetY = p;\n\n        if (mode == 0) {\n            targetY = ((p + Q - 1) / Q) * Q; // snap up\n        } else {\n            int ideal = (int)llround((double)W * t / rr);\n            int dn = (ideal / Q) * Q;\n            int up = ((ideal + Q - 1) / Q) * Q;\n            targetY = (abs(ideal - dn) <= abs(up - ideal) ? dn : up);\n            if (targetY < p) targetY = ((p + Q - 1) / Q) * Q;\n        }\n\n        int des = targetY - p;\n        des = max(des, prev);\n        des = min(des, slack);\n        inc[t] = des;\n        prev = des;\n    }\n\n    // stabilize monotonicity\n    for (int t = rr - 1; t >= 1; t--) inc[t] = min(inc[t], inc[t + 1]);\n    for (int t = 1; t <= rr; t++) inc[t] = max(inc[t], inc[t - 1]);\n    inc[rr] = slack;\n\n    vector<int> h(rr);\n    for (int g = 0; g < rr; g++) h[g] = hmin[g] + (inc[g + 1] - inc[g]);\n    return h;\n}\n\nstatic vector<int> random_variant(const vector<int>& hmin, int slack, uint64_t seed) {\n    int rr = (int)hmin.size();\n    mt19937_64 rng(seed);\n\n    vector<int> cuts(rr + 1, 0);\n    cuts[0] = 0;\n    cuts[rr] = slack;\n    uniform_int_distribution<int> dist(0, slack);\n    for (int i = 1; i < rr; i++) cuts[i] = dist(rng);\n    sort(cuts.begin(), cuts.end());\n\n    vector<int> h(rr);\n    for (int g = 0; g < rr; g++) h[g] = hmin[g] + (cuts[g + 1] - cuts[g]);\n    return h;\n}\n\nstatic void add_var_unique(vector<vector<int>>& vars, const vector<int>& v) {\n    for (auto& u : vars) if (u == v) return;\n    vars.push_back(v);\n}\n\nstatic vector<Candidate> generate_shelf_one_order(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    int capRows\n) {\n    int N = (int)dayA.size();\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    vector<vector<int>> htab(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            htab[l][r] = min_height_segment(arr, l, r, W);\n        }\n    }\n\n    const int INF = 1e9;\n    vector<vector<int>> dp(N + 1, vector<int>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int rr = 1; rr <= N; rr++) {\n        for (int i = 1; i <= N; i++) {\n            int best = INF, bestj = -1;\n            for (int j = 0; j < i; j++) {\n                if (dp[rr - 1][j] == INF) continue;\n                int h = htab[j][i];\n                if (h > W) continue;\n                int val = dp[rr - 1][j] + h;\n                if (val < best || (val == best && j > bestj)) {\n                    best = val;\n                    bestj = j;\n                }\n            }\n            dp[rr][i] = best;\n            par[rr][i] = bestj;\n        }\n    }\n\n    vector<int> feasibleRows;\n    for (int rr = 1; rr <= N; rr++) {\n        if (dp[rr][N] <= W) feasibleRows.push_back(rr);\n    }\n    vector<int> selRows = sample_rows(feasibleRows, capRows);\n\n    vector<Candidate> out;\n    out.reserve(selRows.size() * 6);\n\n    for (int rr : selRows) {\n        vector<int> split(rr + 1, 0);\n        split[rr] = N;\n\n        int cur = N;\n        bool ok = true;\n        for (int r = rr; r >= 1; r--) {\n            int j = par[r][cur];\n            if (j < 0) { ok = false; break; }\n            split[r - 1] = j;\n            cur = j;\n        }\n        if (!ok || split[0] != 0) continue;\n\n        vector<int> hmin(rr, 0);\n        int sumMin = 0;\n        for (int g = 0; g < rr; g++) {\n            int l = split[g], r = split[g + 1];\n            hmin[g] = htab[l][r];\n            sumMin += hmin[g];\n        }\n        if (sumMin > W) continue;\n        int slack = W - sumMin;\n\n        vector<vector<int>> vars;\n\n        // baseline variants\n        {\n            vector<int> v = hmin;\n            v.back() += slack;\n            add_var_unique(vars, v);\n        }\n        if (rr >= 2) {\n            vector<int> v = hmin;\n            v[0] += slack;\n            add_var_unique(vars, v);\n        }\n        if (rr >= 2) {\n            vector<int> v = hmin;\n            int q = slack / rr, rem = slack % rr;\n            for (int g = 0; g < rr; g++) v[g] += q + (g < rem ? 1 : 0);\n            add_var_unique(vars, v);\n        }\n        if (rr >= 3) {\n            vector<int> v = hmin;\n            v[rr / 2] += slack;\n            add_var_unique(vars, v);\n        }\n\n        // snapped variants (better cross-day alignment chance)\n        add_var_unique(vars, snapped_variant(hmin, slack, W, 50, 0));\n        add_var_unique(vars, snapped_variant(hmin, slack, W, 50, 1));\n        add_var_unique(vars, snapped_variant(hmin, slack, W, 100, 0));\n        add_var_unique(vars, snapped_variant(hmin, slack, W, 100, 1));\n\n        // random slack distribution variants\n        if (slack > 0 && rr >= 2) {\n            uint64_t seed = 1469598103934665603ULL ^ (uint64_t)rr;\n            for (int x : split) seed = splitmix64(seed ^ (uint64_t)(x + 0x9e37));\n            add_var_unique(vars, random_variant(hmin, slack, seed ^ 1ULL));\n            add_var_unique(vars, random_variant(hmin, slack, seed ^ 2ULL));\n        }\n\n        for (auto& hv : vars) {\n            vector<array<int, 4>> cells;\n            cells.reserve(N);\n\n            int y = 0;\n            bool good = true;\n            for (int g = 0; g < rr; g++) {\n                int l = split[g], r = split[g + 1];\n                int h = hv[g];\n                if (h <= 0) { good = false; break; }\n\n                int x = 0;\n                for (int t = l; t < r; t++) {\n                    int req = dayA[ord[t]];\n                    int w = (t < r - 1) ? ((req + h - 1) / h) : (W - x);\n                    if (w <= 0) { good = false; break; }\n                    cells.push_back({y, x, y + h, x + w});\n                    x += w;\n                }\n                if (!good || x != W) { good = false; break; }\n                y += h;\n            }\n\n            if (!good || y != W || (int)cells.size() != N) continue;\n            out.push_back(build_candidate_from_cells(W, dayA, cells, 1));\n        }\n    }\n\n    return out;\n}\n\nstatic Candidate fallback_horizontal(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int y0 = (int)(1LL * W * k / N);\n        int y1 = (int)(1LL * W * (k + 1) / N);\n        cells.push_back({y0, 0, y1, W});\n    }\n    return build_candidate_from_cells(W, dayA, cells, 1);\n}\n\nstatic Candidate fallback_vertical(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int x0 = (int)(1LL * W * k / N);\n        int x1 = (int)(1LL * W * (k + 1) / N);\n        cells.push_back({0, x0, W, x1});\n    }\n    return build_candidate_from_cells(W, dayA, cells, 1);\n}\n\n// mode: 0 deterministic, 1 mild random, 2 stronger random\nstatic bool generate_guillotine_candidate(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    Candidate& outCand,\n    uint64_t seed,\n    int mode,\n    unsigned char src = 1\n) {\n    int N = (int)dayA.size();\n    vector<int> vals(N);\n    for (int i = 0; i < N; i++) vals[i] = dayA[ord[i]];\n\n    vector<ll> ps(N + 1, 0);\n    for (int i = 0; i < N; i++) ps[i + 1] = ps[i] + vals[i];\n\n    mt19937_64 rng(seed);\n\n    struct Opt {\n        int orient; // 0 vertical split, 1 horizontal split\n        int m, cut;\n        ll score;\n    };\n\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n\n    function<bool(int, int, int, int, int, int)> dfs =\n        [&](int l, int r, int y0, int y1, int x0, int x1) -> bool {\n            if (r - l == 1) {\n                if (!(y0 < y1 && x0 < x1)) return false;\n                cells.push_back({y0, x0, y1, x1});\n                return true;\n            }\n\n            int h = y1 - y0;\n            int w = x1 - x0;\n            if (h <= 0 || w <= 0) return false;\n\n            ll S = ps[r] - ps[l];\n            if (S <= 0) return false;\n\n            int pref = (w >= h ? 0 : 1);\n            if (mode > 0 && (rng() & 1ULL)) pref ^= 1;\n\n            vector<Opt> opts;\n            opts.reserve((r - l - 1) * 4);\n\n            for (int pass = 0; pass < 2; pass++) {\n                int orient = (pass == 0 ? pref : (pref ^ 1));\n                for (int m = l + 1; m < r; m++) {\n                    ll s1 = ps[m] - ps[l];\n                    ll s2 = S - s1;\n\n                    auto add_cut = [&](int cut, int orientFlag) {\n                        ll score = 0;\n                        if (orientFlag == 0) {\n                            ll cap1 = 1LL * cut * h;\n                            ll cap2 = 1LL * (w - cut) * h;\n                            ll sl1 = cap1 - s1;\n                            ll sl2 = cap2 - s2;\n                            ll bal = llabs(2LL * (m - l) - (r - l));\n                            score = sl1 * sl1 + sl2 * sl2 + 4LL * bal;\n                        } else {\n                            ll cap1 = 1LL * cut * w;\n                            ll cap2 = 1LL * (h - cut) * w;\n                            ll sl1 = cap1 - s1;\n                            ll sl2 = cap2 - s2;\n                            ll bal = llabs(2LL * (m - l) - (r - l));\n                            score = sl1 * sl1 + sl2 * sl2 + 4LL * bal;\n                        }\n                        if (orientFlag != pref) score += 180;\n                        if (mode == 1) score += (ll)(rng() % 3000ULL);\n                        if (mode == 2) score += (ll)(rng() % 12000ULL);\n                        opts.push_back({orientFlag, m, cut, score});\n                    };\n\n                    if (orient == 0) {\n                        ll min1 = max(1LL, (s1 + h - 1) / h);\n                        ll min2 = max(1LL, (s2 + h - 1) / h);\n                        if (min1 + min2 > w) continue;\n                        int low = (int)min1;\n                        int high = w - (int)min2;\n                        int c0 = (int)llround((double)w * (double)s1 / (double)S);\n                        c0 = max(low, min(high, c0));\n\n                        vector<int> cuts;\n                        cuts.push_back(c0);\n                        if (mode >= 1) {\n                            int cm = (low + high) / 2;\n                            if (cm != c0) cuts.push_back(cm);\n                        }\n                        if (mode >= 2 && high - low >= 3) {\n                            int cr = low + (int)(rng() % (uint64_t)(high - low + 1));\n                            bool ex = false;\n                            for (int c : cuts) if (c == cr) { ex = true; break; }\n                            if (!ex) cuts.push_back(cr);\n                        }\n\n                        for (int cut : cuts) add_cut(cut, 0);\n                    } else {\n                        ll min1 = max(1LL, (s1 + w - 1) / w);\n                        ll min2 = max(1LL, (s2 + w - 1) / w);\n                        if (min1 + min2 > h) continue;\n                        int low = (int)min1;\n                        int high = h - (int)min2;\n                        int c0 = (int)llround((double)h * (double)s1 / (double)S);\n                        c0 = max(low, min(high, c0));\n\n                        vector<int> cuts;\n                        cuts.push_back(c0);\n                        if (mode >= 1) {\n                            int cm = (low + high) / 2;\n                            if (cm != c0) cuts.push_back(cm);\n                        }\n                        if (mode >= 2 && high - low >= 3) {\n                            int cr = low + (int)(rng() % (uint64_t)(high - low + 1));\n                            bool ex = false;\n                            for (int c : cuts) if (c == cr) { ex = true; break; }\n                            if (!ex) cuts.push_back(cr);\n                        }\n\n                        for (int cut : cuts) add_cut(cut, 1);\n                    }\n                }\n            }\n\n            if (opts.empty()) return false;\n            sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n                return a.score < b.score;\n            });\n\n            int top = min<int>((mode == 0 ? 5 : 8), opts.size());\n\n            vector<int> ordIdx(top);\n            iota(ordIdx.begin(), ordIdx.end(), 0);\n            if (mode > 0) shuffle(ordIdx.begin(), ordIdx.end(), rng);\n\n            int lim = min(top, 5);\n            for (int zz = 0; zz < lim; zz++) {\n                const auto& op = opts[ordIdx[zz]];\n                size_t old = cells.size();\n\n                bool ok = false;\n                if (op.orient == 0) {\n                    int xm = x0 + op.cut;\n                    ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                         dfs(op.m, r, y0, y1, xm, x1);\n                } else {\n                    int ym = y0 + op.cut;\n                    ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                         dfs(op.m, r, ym, y1, x0, x1);\n                }\n                if (ok) return true;\n                cells.resize(old);\n            }\n\n            if (mode > 0) {\n                int lim2 = min<int>(3, (int)opts.size());\n                for (int zz = 0; zz < lim2; zz++) {\n                    const auto& op = opts[zz];\n                    size_t old = cells.size();\n\n                    bool ok = false;\n                    if (op.orient == 0) {\n                        int xm = x0 + op.cut;\n                        ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                             dfs(op.m, r, y0, y1, xm, x1);\n                    } else {\n                        int ym = y0 + op.cut;\n                        ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                             dfs(op.m, r, ym, y1, x0, x1);\n                    }\n                    if (ok) return true;\n                    cells.resize(old);\n                }\n            }\n\n            return false;\n        };\n\n    bool ok = dfs(0, N, 0, W, 0, W);\n    if (!ok || (int)cells.size() != N) return false;\n\n    outCand = build_candidate_from_cells(W, dayA, cells, src);\n    return true;\n}\n\nstatic vector<Candidate> dedup_shape_only(vector<Candidate> pool) {\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n    unordered_map<uint64_t, vector<int>> mp;\n    mp.reserve(pool.size() * 2 + 1);\n\n    for (auto& c : pool) {\n        auto& vec = mp[c.hash];\n        bool merged = false;\n        for (int id : vec) {\n            if (same_shape(c, uniq[id])) {\n                unsigned char srcU = (unsigned char)(uniq[id].src | c.src);\n                bool better = false;\n                if (c.boundaryLen < uniq[id].boundaryLen) better = true;\n                else if (c.boundaryLen == uniq[id].boundaryLen && c.shortage < uniq[id].shortage) better = true;\n\n                if (better) {\n                    Candidate t = c;\n                    t.src = srcU;\n                    uniq[id] = move(t);\n                } else {\n                    uniq[id].src = srcU;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) {\n            vec.push_back((int)uniq.size());\n            uniq.push_back(move(c));\n        }\n    }\n\n    return uniq;\n}\n\nstatic void dedup_and_trim(vector<Candidate>& pool, int maxCand) {\n    if (pool.empty()) return;\n\n    // Dedup by shape\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n    unordered_map<uint64_t, vector<int>> mp;\n    mp.reserve(pool.size() * 2 + 1);\n\n    for (auto& c : pool) {\n        auto& vec = mp[c.hash];\n        bool merged = false;\n        for (int id : vec) {\n            if (same_shape(c, uniq[id])) {\n                unsigned char srcU = (unsigned char)(uniq[id].src | c.src);\n                bool better = false;\n                if (c.shortage < uniq[id].shortage) better = true;\n                else if (c.shortage == uniq[id].shortage && c.boundaryLen < uniq[id].boundaryLen) better = true;\n\n                if (better) {\n                    Candidate t = c;\n                    t.src = srcU;\n                    uniq[id] = move(t);\n                } else {\n                    uniq[id].src = srcU;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) {\n            vec.push_back((int)uniq.size());\n            uniq.push_back(move(c));\n        }\n    }\n\n    if ((int)uniq.size() <= maxCand) {\n        pool.swap(uniq);\n        return;\n    }\n\n    int M = (int)uniq.size();\n    vector<int> ids(M);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byShort = ids;\n    sort(byShort.begin(), byShort.end(), [&](int i, int j) {\n        if (uniq[i].shortage != uniq[j].shortage) return uniq[i].shortage < uniq[j].shortage;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    vector<int> byBound = ids;\n    sort(byBound.begin(), byBound.end(), [&](int i, int j) {\n        if (uniq[i].boundaryLen != uniq[j].boundaryLen) return uniq[i].boundaryLen < uniq[j].boundaryLen;\n        return uniq[i].shortage < uniq[j].shortage;\n    });\n\n    vector<int> byMix = ids;\n    sort(byMix.begin(), byMix.end(), [&](int i, int j) {\n        ll si = uniq[i].shortage + 18LL * uniq[i].boundaryLen;\n        ll sj = uniq[j].shortage + 18LL * uniq[j].boundaryLen;\n        if (si != sj) return si < sj;\n        if (uniq[i].shortage != uniq[j].shortage) return uniq[i].shortage < uniq[j].shortage;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    vector<int> proto;\n    proto.reserve(M);\n    for (int id : ids) if (uniq[id].src & (2 | 4)) proto.push_back(id);\n    sort(proto.begin(), proto.end(), [&](int i, int j) {\n        ll si = uniq[i].shortage + 10LL * uniq[i].boundaryLen;\n        ll sj = uniq[j].shortage + 10LL * uniq[j].boundaryLen;\n        if (si != sj) return si < sj;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    ll bestS = uniq[byShort[0]].shortage;\n    const ll MARGIN = 140000;\n    vector<int> near;\n    near.reserve(M);\n    for (int id : ids) {\n        if (uniq[id].shortage <= bestS + MARGIN) near.push_back(id);\n    }\n    sort(near.begin(), near.end(), [&](int i, int j) {\n        if (uniq[i].boundaryLen != uniq[j].boundaryLen) return uniq[i].boundaryLen < uniq[j].boundaryLen;\n        return uniq[i].shortage < uniq[j].shortage;\n    });\n\n    vector<char> used(M, 0);\n    vector<int> sel;\n    sel.reserve(maxCand);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxCand || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    int q1 = maxCand * 45 / 100; // raw shortage winners\n    int q2 = maxCand * 25 / 100; // proto-friendly\n    int q3 = maxCand * 15 / 100; // near-best shortage, low boundary\n    int q4 = maxCand - q1 - q2 - q3;\n\n    pick(byShort, q1);\n    pick(proto, q2);\n    pick(near, q3);\n    pick(byMix, q4);\n    pick(byBound, maxCand);\n    pick(byShort, maxCand);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) out.push_back(move(uniq[id]));\n    pool.swap(out);\n}\n\nstatic pair<ll, vector<int>> solve_dp(const vector<vector<Candidate>>& cands) {\n    int D = (int)cands.size();\n    const ll INF = (1LL << 62);\n\n    vector<vector<int>> parent(D);\n    vector<ll> dpPrev(cands[0].size(), INF), dpCur;\n\n    for (int i = 0; i < (int)cands[0].size(); i++) {\n        dpPrev[i] = cands[0][i].shortage; // L0=0\n    }\n\n    for (int d = 1; d < D; d++) {\n        int P = (int)cands[d - 1].size();\n        int C = (int)cands[d].size();\n\n        dpCur.assign(C, INF);\n        parent[d].assign(C, -1);\n\n        for (int i = 0; i < C; i++) {\n            ll add = cands[d][i].shortage;\n            ll best = INF;\n            int bestj = 0;\n\n            for (int j = 0; j < P; j++) {\n                ll tr = transition_cost(cands[d - 1][j], cands[d][i]);\n                ll v = dpPrev[j] + tr + add;\n                if (v < best) {\n                    best = v;\n                    bestj = j;\n                }\n            }\n            dpCur[i] = best;\n            parent[d][i] = bestj;\n        }\n\n        dpPrev.swap(dpCur);\n    }\n\n    int last = 0;\n    for (int i = 1; i < (int)dpPrev.size(); i++) {\n        if (dpPrev[i] < dpPrev[last]) last = i;\n    }\n\n    vector<int> choice(D, 0);\n    choice[D - 1] = last;\n    for (int d = D - 1; d >= 1; d--) {\n        choice[d - 1] = parent[d][choice[d]];\n    }\n\n    return {dpPrev[last], choice};\n}\n\nstatic void add_order_unique(vector<vector<int>>& orders, const vector<int>& ord) {\n    for (auto& v : orders) if (v == ord) return;\n    orders.push_back(ord);\n}\n\nstatic vector<Candidate> select_global_prototypes(\n    const vector<vector<Candidate>>& cands,\n    const vector<vector<int>>& a,\n    int maxProto\n) {\n    vector<Candidate> pool;\n    for (auto& day : cands) {\n        for (auto& c : day) pool.push_back(c);\n    }\n    pool = dedup_shape_only(move(pool));\n    if (pool.empty()) return {};\n\n    int P = (int)pool.size();\n    int D = (int)a.size();\n\n    if (P <= maxProto) {\n        for (auto& c : pool) c.src = 2;\n        sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n            if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n            return x.shortage < y.shortage;\n        });\n        return pool;\n    }\n\n    vector<ll> total(P, 0), gscore(P, 0);\n    vector<int> wins(P, 0);\n\n    int TOPK = min(4, P);\n    vector<pair<ll, int>> rank(P);\n\n    for (int d = 0; d < D; d++) {\n        for (int p = 0; p < P; p++) {\n            ll sh = calc_shortage(a[d], pool[p].areas);\n            total[p] += sh;\n            rank[p] = {sh + 6LL * pool[p].boundaryLen, p};\n        }\n\n        if (TOPK < P) nth_element(rank.begin(), rank.begin() + TOPK, rank.end());\n        sort(rank.begin(), rank.begin() + TOPK);\n\n        for (int t = 0; t < TOPK; t++) {\n            wins[rank[t].second] += (TOPK - t);\n        }\n    }\n\n    for (int p = 0; p < P; p++) {\n        gscore[p] = total[p] + 2LL * D * pool[p].boundaryLen;\n    }\n\n    vector<int> ids(P);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byGlobal = ids;\n    sort(byGlobal.begin(), byGlobal.end(), [&](int i, int j) {\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        if (pool[i].boundaryLen != pool[j].boundaryLen) return pool[i].boundaryLen < pool[j].boundaryLen;\n        return i < j;\n    });\n\n    vector<int> byWins = ids;\n    sort(byWins.begin(), byWins.end(), [&](int i, int j) {\n        if (wins[i] != wins[j]) return wins[i] > wins[j];\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        return i < j;\n    });\n\n    vector<int> byBound = ids;\n    sort(byBound.begin(), byBound.end(), [&](int i, int j) {\n        if (pool[i].boundaryLen != pool[j].boundaryLen) return pool[i].boundaryLen < pool[j].boundaryLen;\n        return gscore[i] < gscore[j];\n    });\n\n    vector<char> used(P, 0);\n    vector<int> sel;\n    sel.reserve(maxProto);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxProto || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    int q1 = maxProto * 50 / 100;\n    int q2 = maxProto * 30 / 100;\n    int q3 = maxProto - q1 - q2;\n\n    pick(byGlobal, q1);\n    pick(byWins, q2);\n    pick(byBound, q3);\n    pick(byGlobal, maxProto);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) {\n        pool[id].src = 2;\n        out.push_back(pool[id]);\n    }\n    return out;\n}\n\nstatic vector<Candidate> build_path_prototypes(\n    const vector<vector<Candidate>>& cands,\n    const vector<int>& choice,\n    const vector<vector<int>>& a,\n    int W,\n    int limit,\n    bool addTranspose\n) {\n    int D = (int)cands.size();\n    vector<Candidate> pool;\n    pool.reserve(D * 2);\n\n    for (int d = 0; d < D; d++) {\n        Candidate p = cands[d][choice[d]];\n        p.src = 4;\n        pool.push_back(move(p));\n        if (addTranspose && (d % 2 == 0)) {\n            Candidate t = transpose_candidate(cands[d][choice[d]], W, a[d], 4);\n            pool.push_back(move(t));\n        }\n    }\n\n    pool = dedup_shape_only(move(pool));\n    sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n        if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n        return x.shortage < y.shortage;\n    });\n    if ((int)pool.size() > limit) pool.resize(limit);\n\n    for (auto& p : pool) p.src = 4;\n    return pool;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) cin >> a[d][k];\n    }\n\n    int scale = D * N;\n    int CAP_ROWS = min(N, 9);\n    int INIT_MAX = 60;\n    int MAX_CAND = 95;\n    int GPROTO = 55;\n    int PATHPROTO = 60;\n    int GUILL_TRIES = 3;\n\n    if (scale > 1800) {\n        CAP_ROWS = min(N, 7);\n        INIT_MAX = 50;\n        MAX_CAND = 80;\n        GPROTO = 42;\n        PATHPROTO = 52;\n        GUILL_TRIES = 2;\n    }\n    if (scale > 2200) {\n        CAP_ROWS = min(N, 6);\n        INIT_MAX = 44;\n        MAX_CAND = 70;\n        GPROTO = 34;\n        PATHPROTO = 44;\n        GUILL_TRIES = 2;\n    }\n\n    vector<int> ordAsc(N), ordDesc(N), zig1, zig2;\n    iota(ordAsc.begin(), ordAsc.end(), 0);\n    for (int i = 0; i < N; i++) ordDesc[i] = N - 1 - i;\n\n    {\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            if (l == r) { zig1.push_back(l); break; }\n            zig1.push_back(l++);\n            zig1.push_back(r--);\n        }\n    }\n    {\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            if (l == r) { zig2.push_back(r); break; }\n            zig2.push_back(r--);\n            zig2.push_back(l++);\n        }\n    }\n\n    vector<vector<Candidate>> cands(D);\n\n    // Initial local generation\n    for (int d = 0; d < D; d++) {\n        mt19937 rng(71236721u + 911u * d + 31u * N);\n        vector<int> rnd = ordAsc;\n        shuffle(rnd.begin(), rnd.end(), rng);\n\n        vector<vector<int>> shelfOrders, guillOrders;\n        add_order_unique(shelfOrders, ordAsc);\n        add_order_unique(shelfOrders, ordDesc);\n        add_order_unique(shelfOrders, zig1);\n        add_order_unique(shelfOrders, zig2);\n        add_order_unique(shelfOrders, rnd);\n\n        add_order_unique(guillOrders, ordAsc);\n        add_order_unique(guillOrders, ordDesc);\n        add_order_unique(guillOrders, rnd);\n\n        vector<Candidate> pool;\n        pool.reserve(800);\n\n        // Shelf candidates + transpose\n        for (auto& ord : shelfOrders) {\n            auto v = generate_shelf_one_order(W, a[d], ord, CAP_ROWS);\n            for (auto& c : v) {\n                pool.push_back(c);\n                pool.push_back(transpose_candidate(c, W, a[d], 1));\n            }\n        }\n\n        // Guillotine candidates + transpose\n        for (auto& ord : guillOrders) {\n            for (int t = 0; t < GUILL_TRIES; t++) {\n                int mode = (t == 0 ? 0 : (t == 1 ? 1 : 2));\n                uint64_t seed = 0x9e3779b97f4a7c15ULL\n                              ^ (uint64_t)(d + 1) * 1000003ULL\n                              ^ (uint64_t)(t + 1) * 911382323ULL\n                              ^ (uint64_t)ord[0] * 972663749ULL;\n\n                Candidate g;\n                if (generate_guillotine_candidate(W, a[d], ord, g, seed, mode, 1)) {\n                    pool.push_back(g);\n                    pool.push_back(transpose_candidate(g, W, a[d], 1));\n                }\n            }\n        }\n\n        pool.push_back(fallback_horizontal(W, a[d]));\n        pool.push_back(fallback_vertical(W, a[d]));\n\n        dedup_and_trim(pool, INIT_MAX);\n        if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n        cands[d] = move(pool);\n    }\n\n    auto [cost0, choice] = solve_dp(cands);\n    ll bestCost = cost0;\n\n    vector<vector<array<int, 4>>> bestRects(D);\n    for (int d = 0; d < D; d++) bestRects[d] = cands[d][choice[d]].rects;\n\n    auto startTime = chrono::steady_clock::now();\n\n    vector<Candidate> globalProtos = select_global_prototypes(cands, a, GPROTO);\n\n    for (int iter = 0; iter < 2; iter++) {\n        auto now = chrono::steady_clock::now();\n        ll elapsed = chrono::duration_cast<chrono::milliseconds>(now - startTime).count();\n        if (elapsed > 2550) break;\n\n        vector<Candidate> pathProtos = build_path_prototypes(\n            cands, choice, a, W, PATHPROTO, (iter == 0)\n        );\n\n        vector<Candidate> pathShape(D);\n        for (int d = 0; d < D; d++) {\n            pathShape[d] = cands[d][choice[d]];\n            pathShape[d].src = 4;\n        }\n\n        for (int d = 0; d < D; d++) {\n            vector<Candidate> pool = cands[d];\n            pool.reserve(pool.size() + (int)globalProtos.size() + (int)pathProtos.size() + 8);\n\n            for (auto& p : globalProtos) pool.push_back(clone_for_day(p, a[d], 2));\n            for (auto& p : pathProtos)   pool.push_back(clone_for_day(p, a[d], 4));\n\n            if (d - 1 >= 0) pool.push_back(clone_for_day(pathShape[d - 1], a[d], 4));\n            if (d + 1 < D)  pool.push_back(clone_for_day(pathShape[d + 1], a[d], 4));\n            if (iter == 0) {\n                if (d - 2 >= 0) pool.push_back(clone_for_day(pathShape[d - 2], a[d], 4));\n                if (d + 2 < D)  pool.push_back(clone_for_day(pathShape[d + 2], a[d], 4));\n            }\n\n            dedup_and_trim(pool, MAX_CAND);\n            if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n            cands[d] = move(pool);\n        }\n\n        auto [newCost, newChoice] = solve_dp(cands);\n        choice = newChoice;\n\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            for (int d = 0; d < D; d++) bestRects[d] = cands[d][choice[d]].rects;\n        }\n\n        // refresh global prototypes once after first enrichment\n        if (iter == 0) {\n            int nextProto = max(28, GPROTO - 8);\n            globalProtos = select_global_prototypes(cands, a, nextProto);\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            auto& r = bestRects[d][k];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\nstatic constexpr int N = 9;\nstatic constexpr int K = 81;\nstatic constexpr int CELLS = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return static_cast<int>(next_u64() % static_cast<uint64_t>(n));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Action {\n    uint8_t cell[9];\n    uint32_t val[9];\n    uint32_t thr[9]; // MOD - val\n    long long raw = 0; // sum val\n    int m = 0, p = 0, q = 0;\n};\n\nstruct State {\n    array<uint32_t, CELLS> board{};\n    array<int, K> ops{};\n    long long score = 0;\n};\n\ninline long long gain_add(const uint32_t* b, const Action& a) {\n    int wraps = 0;\n    for (int k = 0; k < 9; k++) wraps += (b[a.cell[k]] >= a.thr[k]);\n    return a.raw - 1LL * MOD * wraps;\n}\n\ninline void apply_add(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        int idx = a.cell[k];\n        uint32_t ov = b[idx];\n        uint32_t nv = ov + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)ov;\n    }\n}\n\ninline void apply_remove(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        int idx = a.cell[k];\n        uint32_t ov = b[idx];\n        uint32_t v = a.val[k];\n        uint32_t nv = (ov >= v) ? (ov - v) : (ov + MOD - v);\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)ov;\n    }\n}\n\nState make_empty_state(const array<uint32_t, CELLS>& base, int dummy_id) {\n    State st;\n    st.board = base;\n    st.ops.fill(dummy_id);\n    st.score = 0;\n    for (uint32_t v : base) st.score += v;\n    return st;\n}\n\ninline void shuffle_order(array<int, K>& ord, XorShift64& rng) {\n    for (int i = K - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nbool one_sweep(State& st, const vector<Action>& actions, int dummy_id,\n               array<int, K>& order, XorShift64& rng) {\n    shuffle_order(order, rng);\n    bool changed = false;\n    const int A = dummy_id;\n\n    for (int t = 0; t < K; t++) {\n        int pos = order[t];\n        int old = st.ops[pos];\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int best = dummy_id;\n        long long best_gain = 0; // dummy gain\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain || (g == best_gain && id == old)) {\n                best_gain = g;\n                best = id;\n            }\n        }\n\n        if (best != dummy_id) apply_add(st, actions[best]);\n        st.ops[pos] = best;\n        if (best != old) changed = true;\n    }\n    return changed;\n}\n\nvoid local_opt(State& st, const vector<Action>& actions, int dummy_id,\n               Timer& timer, double tl, XorShift64& rng, int max_sweeps) {\n    array<int, K> ord;\n    iota(ord.begin(), ord.end(), 0);\n    for (int sw = 0; sw < max_sweeps; sw++) {\n        if (timer.elapsed() >= tl) break;\n        bool changed = one_sweep(st, actions, dummy_id, ord, rng);\n        if (!changed) break;\n    }\n}\n\nState construct_best_greedy(const array<uint32_t, CELLS>& base,\n                            const vector<Action>& actions, int dummy_id) {\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        int best = dummy_id;\n        long long best_gain = 0;\n        const uint32_t* b = st.board.data();\n\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain) {\n                best_gain = g;\n                best = id;\n            }\n        }\n        if (best == dummy_id) break;\n        st.ops[pos] = best;\n        apply_add(st, actions[best]);\n    }\n    return st;\n}\n\nState construct_random_greedy(const array<uint32_t, CELLS>& base,\n                              const vector<Action>& actions, int dummy_id,\n                              XorShift64& rng, int topR) {\n    constexpr int LIM = 8;\n    topR = max(1, min(topR, LIM));\n\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        array<long long, LIM> bestG;\n        array<int, LIM> bestId;\n        bestG.fill(LLONG_MIN);\n        bestId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g <= 0) continue;\n            if (g <= bestG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > bestG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                bestG[t] = bestG[t - 1];\n                bestId[t] = bestId[t - 1];\n            }\n            bestG[at] = g;\n            bestId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && bestId[cnt] != -1) cnt++;\n        if (cnt == 0) break;\n\n        int pick;\n        int r = rng.next_int(100);\n        if (r < 55) pick = bestId[0];\n        else if (r < 80) pick = bestId[rng.next_int(min(cnt, 2))];\n        else pick = bestId[rng.next_int(cnt)];\n\n        st.ops[pos] = pick;\n        apply_add(st, actions[pick]);\n    }\n    return st;\n}\n\nvoid compute_marginals(State& st, const vector<Action>& actions, int dummy_id,\n                       array<long long, K>& mg) {\n    static constexpr long long DUMMY_WEAK = -(1LL << 55);\n    for (int i = 0; i < K; i++) {\n        int id = st.ops[i];\n        if (id == dummy_id) {\n            mg[i] = DUMMY_WEAK;\n            continue;\n        }\n        apply_remove(st, actions[id]);\n        mg[i] = gain_add(st.board.data(), actions[id]); // reinsertion gain\n        apply_add(st, actions[id]);\n    }\n}\n\nvector<int> select_positions(State& st, const vector<Action>& actions, int dummy_id,\n                             XorShift64& rng, int cnt, double worst_ratio, bool focus_bad) {\n    cnt = max(0, min(cnt, K));\n    vector<int> res;\n    res.reserve(cnt);\n    array<unsigned char, K> used{};\n    used.fill(0);\n\n    if (focus_bad && cnt > 0) {\n        array<long long, K> mg;\n        compute_marginals(st, actions, dummy_id, mg);\n\n        array<int, K> idx;\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (mg[a] != mg[b]) return mg[a] < mg[b];\n            return a < b;\n        });\n\n        int bad = (int)llround(cnt * worst_ratio);\n        bad = max(1, min(bad, cnt));\n        int pool = min(K, max(bad + 4, bad * 3));\n\n        for (int t = 0; t < bad; t++) {\n            int chosen = -1;\n            for (int tr = 0; tr < 20; tr++) {\n                int cand = idx[rng.next_int(pool)];\n                if (!used[cand]) {\n                    chosen = cand;\n                    break;\n                }\n            }\n            if (chosen == -1) {\n                for (int j = 0; j < K; j++) {\n                    int cand = idx[j];\n                    if (!used[cand]) {\n                        chosen = cand;\n                        break;\n                    }\n                }\n            }\n            if (chosen == -1) break;\n            used[chosen] = 1;\n            res.push_back(chosen);\n        }\n    }\n\n    while ((int)res.size() < cnt) {\n        int p = rng.next_int(K);\n        if (used[p]) continue;\n        used[p] = 1;\n        res.push_back(p);\n    }\n\n    for (int i = (int)res.size() - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(res[i], res[j]);\n    }\n    return res;\n}\n\nvoid destroy_repair_guided(State& st, const vector<Action>& actions, int dummy_id,\n                           vector<int> positions, XorShift64& rng,\n                           int topR, bool allow_negative) {\n    constexpr int LIM = 8;\n    topR = max(1, min(topR, LIM));\n    const int A = dummy_id;\n\n    for (int pos : positions) {\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n        st.ops[pos] = dummy_id;\n    }\n\n    for (int i = (int)positions.size() - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(positions[i], positions[j]);\n    }\n\n    for (int pos : positions) {\n        array<long long, LIM> bestG;\n        array<int, LIM> bestId;\n        bestG.fill(LLONG_MIN);\n        bestId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (!allow_negative && g <= 0) continue;\n            if (g <= bestG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > bestG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                bestG[t] = bestG[t - 1];\n                bestId[t] = bestId[t - 1];\n            }\n            bestG[at] = g;\n            bestId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && bestId[cnt] != -1) cnt++;\n\n        int pick = dummy_id;\n        if (cnt > 0) {\n            int r = rng.next_int(100);\n            if (allow_negative && bestG[0] <= 0) {\n                if (r < 70) {\n                    pick = dummy_id;\n                } else if (r < 88) {\n                    pick = bestId[0];\n                } else {\n                    pick = bestId[rng.next_int(cnt)];\n                }\n            } else {\n                if (r < 58) pick = bestId[0];\n                else if (r < 83) pick = bestId[rng.next_int(min(cnt, 2))];\n                else pick = bestId[rng.next_int(cnt)];\n            }\n        }\n\n        st.ops[pos] = pick;\n        if (pick != dummy_id) apply_add(st, actions[pick]);\n    }\n}\n\nvoid random_perturb(State& st, const vector<Action>& actions, int dummy_id,\n                    XorShift64& rng, int cnt) {\n    const int A = dummy_id;\n    for (int t = 0; t < cnt; t++) {\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int nid = dummy_id;\n        int mode = rng.next_int(100);\n\n        if (mode < 12) {\n            nid = dummy_id;\n        } else if (mode < 70) {\n            long long bestg = LLONG_MIN;\n            int bestid = dummy_id;\n            for (int s = 0; s < 24; s++) {\n                int id = rng.next_int(A);\n                long long g = gain_add(st.board.data(), actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            if (bestg > 0 || rng.next_int(100) < 35) nid = bestid;\n        } else if (mode < 90) {\n            int id = rng.next_int(A);\n            long long g = gain_add(st.board.data(), actions[id]);\n            if (g > -(long long)MOD / 5 || rng.next_int(100) < 20) nid = id;\n        } else {\n            long long bestg = 0;\n            int bestid = dummy_id;\n            const uint32_t* b = st.board.data();\n            for (int id = 0; id < A; id++) {\n                long long g = gain_add(b, actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            nid = bestid;\n        }\n\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n    }\n}\n\nbool pair_improve_once(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, const vector<int>* pool,\n                       int top_first, bool allow_neg_first) {\n    constexpr int LIM = 8;\n    top_first = max(1, min(top_first, LIM));\n\n    int p1, p2;\n    if (pool && (int)pool->size() >= 2) {\n        p1 = (*pool)[rng.next_int((int)pool->size())];\n        do p2 = (*pool)[rng.next_int((int)pool->size())];\n        while (p2 == p1);\n        if (rng.next_int(100) < 25) {\n            int q = rng.next_int(K - 1);\n            if (q >= p1) q++;\n            p2 = q;\n        }\n    } else {\n        p1 = rng.next_int(K);\n        p2 = rng.next_int(K - 1);\n        if (p2 >= p1) p2++;\n    }\n\n    long long before = st.score;\n    int old1 = st.ops[p1];\n    int old2 = st.ops[p2];\n\n    if (old1 != dummy_id) apply_remove(st, actions[old1]);\n    if (old2 != dummy_id) apply_remove(st, actions[old2]);\n    st.ops[p1] = dummy_id;\n    st.ops[p2] = dummy_id;\n\n    array<long long, LIM> firstG;\n    array<int, LIM> firstId;\n    firstG.fill(LLONG_MIN);\n    firstId.fill(-1);\n\n    const int A = dummy_id;\n    const uint32_t* b = st.board.data();\n    for (int id = 0; id < A; id++) {\n        long long g = gain_add(b, actions[id]);\n        if (!allow_neg_first && g <= 0) continue;\n        if (g <= firstG[top_first - 1]) continue;\n\n        int at = top_first - 1;\n        while (at > 0 && g > firstG[at - 1]) --at;\n        for (int t = top_first - 1; t > at; --t) {\n            firstG[t] = firstG[t - 1];\n            firstId[t] = firstId[t - 1];\n        }\n        firstG[at] = g;\n        firstId[at] = id;\n    }\n\n    array<long long, LIM + 1> candG{};\n    array<int, LIM + 1> candId{};\n    int candCnt = 1;\n    candG[0] = 0;\n    candId[0] = dummy_id;\n    for (int i = 0; i < top_first; i++) {\n        if (firstId[i] == -1) break;\n        candG[candCnt] = firstG[i];\n        candId[candCnt] = firstId[i];\n        candCnt++;\n    }\n\n    long long bestTot = LLONG_MIN;\n    int best1 = dummy_id, best2 = dummy_id;\n\n    for (int c = 0; c < candCnt; c++) {\n        int id1 = candId[c];\n        long long g1 = candG[c];\n\n        if (id1 != dummy_id) apply_add(st, actions[id1]);\n\n        long long bestg2 = 0;\n        int bestid2 = dummy_id;\n        const uint32_t* b2 = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g2 = gain_add(b2, actions[id]);\n            if (g2 > bestg2) {\n                bestg2 = g2;\n                bestid2 = id;\n            }\n        }\n\n        long long tot = g1 + bestg2;\n        if (tot > bestTot) {\n            bestTot = tot;\n            best1 = id1;\n            best2 = bestid2;\n        }\n\n        if (id1 != dummy_id) apply_remove(st, actions[id1]);\n    }\n\n    if (best1 != dummy_id) apply_add(st, actions[best1]);\n    if (best2 != dummy_id) apply_add(st, actions[best2]);\n    st.ops[p1] = best1;\n    st.ops[p2] = best2;\n\n    if (st.score > before) return true;\n\n    // revert\n    if (best1 != dummy_id) apply_remove(st, actions[best1]);\n    if (best2 != dummy_id) apply_remove(st, actions[best2]);\n    if (old1 != dummy_id) apply_add(st, actions[old1]);\n    if (old2 != dummy_id) apply_add(st, actions[old2]);\n    st.ops[p1] = old1;\n    st.ops[p2] = old2;\n    return false;\n}\n\nbool pair_local_search(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, int trials, int top_first,\n                       bool targeted, bool allow_neg_first,\n                       Timer& timer, double tl) {\n    vector<int> pool;\n    if (targeted) {\n        int ps = min(30, K);\n        pool = select_positions(st, actions, dummy_id, rng, ps, 0.85, true);\n    }\n\n    bool improved = false;\n    for (int t = 0; t < trials; t++) {\n        if ((t & 3) == 0 && timer.elapsed() >= tl) break;\n        if (pair_improve_once(st, actions, dummy_id, rng,\n                              targeted ? &pool : nullptr,\n                              top_first, allow_neg_first)) {\n            improved = true;\n        }\n    }\n    return improved;\n}\n\nvoid anneal_kick(State& st, const vector<Action>& actions, int dummy_id,\n                 XorShift64& rng, int steps, int sample_n,\n                 double T0, double T1, Timer& timer, double tl) {\n    const int A = dummy_id;\n    for (int t = 0; t < steps; t++) {\n        if ((t & 15) == 0 && timer.elapsed() >= tl) break;\n\n        double T = T0 + (T1 - T0) * (double)t / (double)max(1, steps - 1);\n\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n        long long oldScore = st.score;\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int nid = dummy_id;\n        int mode = rng.next_int(100);\n        if (mode < 10) {\n            nid = dummy_id;\n        } else {\n            long long bestg = LLONG_MIN;\n            int bestid = dummy_id;\n            for (int s = 0; s < sample_n; s++) {\n                int id = rng.next_int(A);\n                long long g = gain_add(st.board.data(), actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            nid = bestid;\n\n            if (mode >= 85) { // occasional random candidate\n                int rid = rng.next_int(A);\n                long long rg = gain_add(st.board.data(), actions[rid]);\n                if (rg > bestg - (long long)MOD / 8) nid = rid;\n            }\n        }\n\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (!accept) {\n            if (nid != dummy_id) apply_remove(st, actions[nid]);\n            if (old != dummy_id) apply_add(st, actions[old]);\n            st.ops[pos] = old;\n        }\n    }\n}\n\nvoid insert_elite(vector<State>& elite, const State& cand, int cap) {\n    for (const auto& e : elite) {\n        if (cand.score == e.score && cand.ops == e.ops) return;\n    }\n    elite.push_back(cand);\n    sort(elite.begin(), elite.end(), [](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)elite.size() > cap) elite.resize(cap);\n}\n\nint pick_elite_index(const vector<State>& elite, XorShift64& rng) {\n    int sz = (int)elite.size();\n    if (sz == 1) return 0;\n    int r = rng.next_int(100);\n    if (r < 55) return 0;\n    if (r < 82) return rng.next_int(min(sz, 3));\n    if (r < 94) return rng.next_int(min(sz, 5));\n    return rng.next_int(sz);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, M, Kin;\n    cin >> Nin >> M >> Kin;\n\n    array<uint32_t, CELLS> base{};\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(Nin); mix(M); mix(Kin);\n\n    for (int i = 0; i < Nin; i++) {\n        for (int j = 0; j < Nin; j++) {\n            uint32_t v;\n            cin >> v;\n            base[i * N + j] = v;\n            mix(v);\n        }\n    }\n\n    vector<array<array<uint32_t, 3>, 3>> stamp(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                uint32_t v;\n                cin >> v;\n                stamp[m][i][j] = v;\n                mix(v);\n            }\n        }\n    }\n\n    vector<Action> actions;\n    actions.reserve(M * (N - 2) * (N - 2));\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                ac.raw = 0;\n\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        uint32_t v = stamp[m][i][j];\n                        ac.val[t] = v;\n                        ac.thr[t] = MOD - v;\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.raw += v;\n                        t++;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n\n    const int dummy_id = (int)actions.size(); // 980\n    XorShift64 rng(seed);\n    Timer timer;\n    const double TL = 1.90;\n    const double MAIN_END = TL * 0.90;\n\n    // Initial solution\n    State best = construct_best_greedy(base, actions, dummy_id);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 45);\n    pair_local_search(best, actions, dummy_id, rng, 14, 6, true, false, timer, TL);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 16);\n\n    const int ELITE_CAP = 8;\n    vector<State> elite;\n    elite.reserve(ELITE_CAP + 4);\n    insert_elite(elite, best, ELITE_CAP);\n\n    // Multi-start initialization\n    while (timer.elapsed() < TL * 0.24) {\n        int topR = 3 + rng.next_int(5); // 3..7\n        State cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 22);\n\n        if (rng.next_int(100) < 65 && timer.elapsed() < TL * 0.23) {\n            int R = 6 + rng.next_int(5); // 6..10\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.70, true);\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, 4 + rng.next_int(2), false);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 8);\n        }\n\n        if (rng.next_int(100) < 50) {\n            pair_local_search(cand, actions, dummy_id, rng, 8, 6, true, false, timer, TL);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 6);\n        }\n\n        if (cand.score > best.score) best = cand;\n        insert_elite(elite, cand, ELITE_CAP);\n    }\n\n    int stagnation = 0;\n\n    // Main search loop\n    while (timer.elapsed() < MAIN_END) {\n        int ei = pick_elite_index(elite, rng);\n        State cand = elite[ei];\n\n        int mode = rng.next_int(100);\n\n        if (mode < 46) {\n            int R = (stagnation < 20) ? (5 + rng.next_int(5)) : (8 + rng.next_int(6));\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.78, true);\n            bool allow_neg = (stagnation > 35 && rng.next_int(100) < 35);\n            int topR = 4 + rng.next_int(3); // 4..6\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, topR, allow_neg);\n        } else if (mode < 67) {\n            int cnt = 2 + rng.next_int((stagnation < 25) ? 10 : 20);\n            random_perturb(cand, actions, dummy_id, rng, cnt);\n        } else if (mode < 84) {\n            int steps = (stagnation < 25) ? 60 : 110;\n            int sample_n = (stagnation < 25) ? 22 : 30;\n            double T0 = (stagnation < 25) ? 3.0e8 : 5.0e8;\n            anneal_kick(cand, actions, dummy_id, rng, steps, sample_n, T0, 3.0e6, timer, MAIN_END);\n        } else {\n            int topR = 3 + rng.next_int(5);\n            cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, MAIN_END, rng, 9 + (stagnation > 30 ? 5 : 0));\n\n        if (rng.next_int(100) < 42) {\n            bool allow_neg_pair = (stagnation > 40 && rng.next_int(100) < 40);\n            pair_local_search(cand, actions, dummy_id, rng,\n                              6 + (stagnation > 25 ? 4 : 0),\n                              6, true, allow_neg_pair, timer, MAIN_END);\n            local_opt(cand, actions, dummy_id, timer, MAIN_END, rng, 4);\n        }\n\n        if (cand.score > best.score) {\n            best = cand;\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n        insert_elite(elite, cand, ELITE_CAP);\n\n        if (stagnation > 70 && timer.elapsed() < MAIN_END * 0.98) {\n            State kick = best;\n            auto pos = select_positions(kick, actions, dummy_id, rng, 12, 0.82, true);\n            destroy_repair_guided(kick, actions, dummy_id, pos, rng, 6, true);\n            local_opt(kick, actions, dummy_id, timer, MAIN_END, rng, 14);\n\n            if (kick.score > best.score) {\n                best = kick;\n                stagnation = 0;\n                insert_elite(elite, best, ELITE_CAP);\n            } else {\n                stagnation = 30;\n            }\n        }\n    }\n\n    // Final intensification\n    while (timer.elapsed() < TL) {\n        State cand = best;\n        int mode = rng.next_int(100);\n\n        if (mode < 68) {\n            int R = 7 + rng.next_int(5); // 7..11\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.85, true);\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, 6, true);\n        } else {\n            anneal_kick(cand, actions, dummy_id, rng, 90, 28, 2.5e8, 2.0e6, timer, TL);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 12);\n        pair_local_search(cand, actions, dummy_id, rng, 10, 6, true, true, timer, TL);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 8);\n\n        if (cand.score > best.score) {\n            best = cand;\n            insert_elite(elite, best, ELITE_CAP);\n        }\n\n        if (timer.elapsed() > TL - 0.018) break;\n    }\n\n    vector<tuple<int, int, int>> ans;\n    ans.reserve(K);\n    for (int i = 0; i < K; i++) {\n        int id = best.ops[i];\n        if (id == dummy_id) continue;\n        const auto& ac = actions[id];\n        ans.emplace_back(ac.m, ac.p, ac.q);\n    }\n\n    cout << ans.size() << '\\n';\n    for (auto [m, p, q] : ans) {\n        cout << m << ' ' << p << ' ' << q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct GreedySolver {\n    int N;\n    vector<vector<int>> A;\n\n    vector<int> nextIn;\n    vector<vector<int>> grid; // -1 or container id\n    int pr = 0, pc = 0;\n    int hold = -1;\n\n    vector<int> srcRow, srcIdx;\n    vector<char> dispatched;\n    vector<int> need;\n    int dispatchedCnt = 0;\n\n    int turn = 0;\n    int revealRow = -1;\n\n    vector<string> out;\n\n    GreedySolver(int n, const vector<vector<int>>& a) : N(n), A(a) {\n        nextIn.assign(N, 0);\n        grid.assign(N, vector<int>(N, -1));\n        srcRow.assign(N * N, -1);\n        srcIdx.assign(N * N, -1);\n        dispatched.assign(N * N, 0);\n        need.resize(N);\n        out.assign(N, \"\");\n\n        for (int r = 0; r < N; r++) need[r] = r * N;\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n    }\n\n    inline int md(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    void spawn_step() {\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] >= N) continue;\n            if (grid[r][0] != -1) continue;\n            if (pr == r && pc == 0 && hold != -1) continue; // holding crane blocks spawn\n            grid[r][0] = A[r][nextIn[r]];\n            nextIn[r]++;\n        }\n    }\n\n    void dispatch_step() {\n        int dc = N - 1;\n        for (int r = 0; r < N; r++) {\n            if (grid[r][dc] == -1) continue;\n            int v = grid[r][dc];\n            grid[r][dc] = -1;\n\n            if (!dispatched[v]) {\n                dispatched[v] = 1;\n                dispatchedCnt++;\n            }\n\n            int dr = v / N;\n            int hi = dr * N + (N - 1);\n            while (need[dr] <= hi && dispatched[need[dr]]) need[dr]++;\n        }\n    }\n\n    // One turn: spawn -> action -> dispatch\n    void apply(char act) {\n        if (turn >= 10000) return;\n\n        spawn_step();\n\n        char real = act;\n        if (act == 'P') {\n            if (!(hold == -1 && grid[pr][pc] != -1)) real = '.';\n        } else if (act == 'Q') {\n            if (!(hold != -1 && grid[pr][pc] == -1)) real = '.';\n        } else if (act == 'U') {\n            if (pr == 0) real = '.';\n        } else if (act == 'D') {\n            if (pr == N - 1) real = '.';\n        } else if (act == 'L') {\n            if (pc == 0) real = '.';\n        } else if (act == 'R') {\n            if (pc == N - 1) real = '.';\n        } else if (act != '.') {\n            real = '.';\n        }\n\n        switch (real) {\n            case 'P':\n                hold = grid[pr][pc];\n                grid[pr][pc] = -1;\n                break;\n            case 'Q':\n                grid[pr][pc] = hold;\n                hold = -1;\n                break;\n            case 'U': pr--; break;\n            case 'D': pr++; break;\n            case 'L': pc--; break;\n            case 'R': pc++; break;\n            case '.': break;\n        }\n\n        dispatch_step();\n\n        out[0].push_back(real);\n        if (turn == 0) {\n            for (int i = 1; i < N; i++) out[i].push_back('B');\n        } else {\n            for (int i = 1; i < N; i++) out[i].push_back('.');\n        }\n        turn++;\n    }\n\n    bool find_container(int v, int &rr, int &cc) const {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == v) {\n                    rr = r; cc = c;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool has_ready_container(int &bestV, int &bestR, int &bestC) const {\n        int bestScore = INT_MAX;\n        bestV = -1; bestR = -1; bestC = -1;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (!find_container(x, r, c)) continue;\n\n            int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestV = x; bestR = r; bestC = c;\n            }\n        }\n        return bestV != -1;\n    }\n\n    int choose_reveal_row() const {\n        int bestRow = -1;\n        int bestScore = INT_MAX;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (find_container(x, r, c)) continue;\n\n            int s = srcRow[x];\n            int frontIdx = (grid[s][0] != -1 ? nextIn[s] - 1 : nextIn[s]);\n            int depth = srcIdx[x] - frontIdx;\n            if (depth < 0) depth = 0;\n\n            int sc = depth * 90 + md(pr, pc, s, 0);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestRow = dr;\n            }\n        }\n        return bestRow;\n    }\n\n    pair<int,int> choose_storage_cell() const {\n        int bestR = -1, bestC = -1;\n        int bestScore = INT_MAX;\n        int dr = (hold == -1 ? 0 : hold / N);\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c <= N - 2; c++) {\n                if (grid[r][c] != -1) continue;\n                int penalty = (c == 0 && nextIn[r] < N) ? 40 : 0;\n                int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1) + penalty;\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestR = r;\n                    bestC = c;\n                }\n            }\n        }\n        return {bestR, bestC};\n    }\n\n    void move_to(int tr, int tc) {\n        while (turn < 10000 && (pr != tr || pc != tc)) {\n            char d;\n            if (pc < tc) d = 'R';\n            else if (pc > tc) d = 'L';\n            else if (pr < tr) d = 'D';\n            else d = 'U';\n            apply(d);\n        }\n    }\n\n    void dispatch_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        int dr = hold / N;\n        move_to(dr, N - 1);\n        if (turn < 10000) apply('Q');\n    }\n\n    void store_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        auto [sr, sc] = choose_storage_cell();\n        if (sr == -1) return;\n        move_to(sr, sc);\n        if (turn < 10000) apply('Q');\n    }\n\n    void solve() {\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                int dr = hold / N;\n                int hi = dr * N + (N - 1);\n                if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                else store_holding();\n                revealRow = -1;\n                continue;\n            }\n\n            int v, r, c;\n            if (has_ready_container(v, r, c)) {\n                revealRow = -1;\n                move_to(r, c);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) {\n                    int dr = hold / N;\n                    int hi = dr * N + (N - 1);\n                    if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                    else store_holding();\n                }\n                continue;\n            }\n\n            if (revealRow != -1) {\n                int hi = revealRow * N + (N - 1);\n                if (need[revealRow] > hi) revealRow = -1;\n                else {\n                    int rr, cc;\n                    if (find_container(need[revealRow], rr, cc)) revealRow = -1;\n                }\n            }\n            if (revealRow == -1) revealRow = choose_reveal_row();\n\n            if (revealRow == -1) {\n                // fallback: pick nearest container\n                int bestR = -1, bestC = -1, bestScore = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    for (int j = 0; j < N; j++) {\n                        int val = grid[i][j];\n                        if (val == -1) continue;\n                        int dr = val / N;\n                        int sc = md(pr, pc, i, j) + md(i, j, dr, N - 1);\n                        if (sc < bestScore) {\n                            bestScore = sc;\n                            bestR = i; bestC = j;\n                        }\n                    }\n                }\n\n                if (bestR == -1) {\n                    apply('.');\n                    continue;\n                }\n\n                move_to(bestR, bestC);\n                if (turn >= 10000) break;\n                apply('P');\n\n                if (hold != -1) {\n                    int dr = hold / N;\n                    int hi = dr * N + (N - 1);\n                    if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                    else store_holding();\n                }\n                revealRow = -1;\n                continue;\n            }\n\n            int x = need[revealRow];\n            int s = srcRow[x];\n\n            move_to(s, 0);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold == -1) {\n                revealRow = -1;\n                continue;\n            }\n\n            int y = hold;\n            int dr = y / N;\n            int hi = dr * N + (N - 1);\n\n            if (need[dr] <= hi && y == need[dr]) {\n                revealRow = -1;\n                dispatch_holding();\n            } else {\n                store_holding();\n            }\n        }\n\n        if (turn < 10000 && hold != -1) {\n            int dr = hold / N;\n            int hi = dr * N + (N - 1);\n            if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n            else store_holding();\n        }\n\n        // Safety cleanup\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                int dr = hold / N;\n                int hi = dr * N + (N - 1);\n                if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                else store_holding();\n                continue;\n            }\n\n            int bestR = -1, bestC = -1, bestScore = INT_MAX;\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    int val = grid[i][j];\n                    if (val == -1) continue;\n                    int dr = val / N;\n                    int sc = md(pr, pc, i, j) + md(i, j, dr, N - 1);\n                    if (sc < bestScore) {\n                        bestScore = sc;\n                        bestR = i; bestC = j;\n                    }\n                }\n            }\n\n            if (bestR == -1) {\n                bool anyQueue = false;\n                for (int r = 0; r < N; r++) if (nextIn[r] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(bestR, bestC);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) {\n                int dr = hold / N;\n                int hi = dr * N + (N - 1);\n                if (need[dr] <= hi && hold == need[dr]) dispatch_holding();\n                else store_holding();\n            }\n        }\n\n        if (out[0].empty()) apply('.');\n    }\n};\n\nstruct BeamSolver {\n    static constexpr int N = 5;\n    vector<vector<int>> A;\n    array<int, 25> srcRow{}, srcIdx{};\n    int dist[25][25]{};\n\n    struct State {\n        array<int8_t, 25> cell;   // -1 empty, 0..24 container\n        array<int8_t, 25> loc;    // -3 dispatched, -2 hold, -1 not yet on grid, 0..24 on grid\n        array<uint8_t, 5> nextIn; // 0..5\n        array<uint8_t, 5> need;   // row-wise required container\n        int8_t hold;              // -1 or 0..24\n        uint8_t pos;              // 0..24\n    };\n\n    struct Trace {\n        int parent;\n        char act;\n    };\n\n    struct BeamItem {\n        State st;\n        int trace;\n        int eval;\n    };\n\n    struct Cand {\n        State st;\n        int parentTrace;\n        char act;\n        int eval;\n        uint64_t h;\n    };\n\n    BeamSolver(const vector<vector<int>>& a) : A(a) {\n        srcRow.fill(-1);\n        srcIdx.fill(-1);\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n        for (int i = 0; i < 25; i++) {\n            for (int j = 0; j < 25; j++) {\n                dist[i][j] = abs(i / N - j / N) + abs(i % N - j % N);\n            }\n        }\n    }\n\n    State initial_state() const {\n        State s;\n        s.cell.fill(-1);\n        s.loc.fill(-1);\n        s.nextIn.fill(0);\n        for (int r = 0; r < N; r++) s.need[r] = (uint8_t)(r * N);\n        s.hold = -1;\n        s.pos = 0;\n        return s;\n    }\n\n    inline int dispatched_count(const State& s) const {\n        int d = 0;\n        for (int r = 0; r < N; r++) d += (int)s.need[r] - r * N;\n        return d;\n    }\n\n    inline bool is_goal(const State& s) const {\n        return dispatched_count(s) == 25 && s.hold == -1;\n    }\n\n    void spawn(State& s) const {\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] != -1) continue;\n            if (s.pos == g && s.hold != -1) continue;\n            int v = A[r][s.nextIn[r]];\n            s.nextIn[r]++;\n            s.cell[g] = (int8_t)v;\n            s.loc[v] = (int8_t)g;\n        }\n    }\n\n    bool apply_action_dispatch(const State& sp, char act, State& ns) const {\n        ns = sp;\n        int p = ns.pos;\n        int r = p / N, c = p % N;\n\n        switch (act) {\n            case '.':\n                break;\n            case 'P': {\n                if (ns.hold != -1) return false;\n                int v = ns.cell[p];\n                if (v < 0) return false;\n                ns.hold = (int8_t)v;\n                ns.cell[p] = -1;\n                ns.loc[v] = -2;\n                break;\n            }\n            case 'Q': {\n                if (ns.hold == -1) return false;\n                if (ns.cell[p] != -1) return false;\n                if (c == N - 1) {\n                    if (ns.hold != (int8_t)ns.need[r]) return false;\n                }\n                int v = ns.hold;\n                ns.hold = -1;\n                ns.cell[p] = (int8_t)v;\n                ns.loc[v] = (int8_t)p;\n                break;\n            }\n            case 'U':\n                if (r == 0) return false;\n                ns.pos = (uint8_t)(p - N);\n                break;\n            case 'D':\n                if (r == N - 1) return false;\n                ns.pos = (uint8_t)(p + N);\n                break;\n            case 'L':\n                if (c == 0) return false;\n                ns.pos = (uint8_t)(p - 1);\n                break;\n            case 'R':\n                if (c == N - 1) return false;\n                ns.pos = (uint8_t)(p + 1);\n                break;\n            default:\n                return false;\n        }\n\n        // Enforce perfect gate correctness & order\n        for (int rr = 0; rr < N; rr++) {\n            int idx = rr * N + (N - 1);\n            int v = ns.cell[idx];\n            if (v == -1) continue;\n            if (v != ns.need[rr]) return false;\n            ns.need[rr]++;\n            ns.cell[idx] = -1;\n            ns.loc[v] = -3;\n        }\n\n        return true;\n    }\n\n    int lower_bound(const State& s) const {\n        int lb = 0;\n        int pos = s.pos;\n\n        for (int v = 0; v < 25; v++) {\n            int dr = v / N;\n            if (v < (int)s.need[dr]) continue;\n\n            int gate = dr * N + (N - 1);\n            if (s.hold == v) {\n                lb += dist[pos][gate] + 1; // only drop needed\n                continue;\n            }\n\n            int lp = s.loc[v];\n            if (lp >= 0) {\n                lb += dist[lp][gate] + 2; // pick + carry + drop\n            } else if (lp == -1) {\n                int sr = srcRow[v];\n                lb += (abs(sr - dr) + (N - 1)) + 2;\n            } else if (lp == -2) {\n                lb += dist[pos][gate] + 1;\n            }\n        }\n        return lb;\n    }\n\n    int eval_state(const State& s, int lb) const {\n        int disp = dispatched_count(s);\n        int ready = 0;\n        for (int r = 0; r < N; r++) {\n            int x = s.need[r];\n            if (x >= r * N + N) continue;\n            if (s.hold == x || s.loc[x] >= 0) ready++;\n        }\n\n        int e = disp * 100000 - lb * 450 + ready * 2500;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            if (v == s.need[dr]) {\n                e += 6000 - dist[s.pos][dr * N + (N - 1)] * 180;\n            } else {\n                e -= 1200;\n            }\n        }\n\n        // Penalize putting unrelated container on active receiving gate\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] == -1) continue;\n            if (s.nextIn[r] == 0) continue;\n            int expected = A[r][s.nextIn[r] - 1];\n            if ((int)s.cell[g] != expected) e -= 5000;\n        }\n\n        return e;\n    }\n\n    uint64_t hash_state(const State& s) const {\n        uint64_t h = 1469598103934665603ULL;\n        auto add = [&](uint8_t x) {\n            h ^= x;\n            h *= 1099511628211ULL;\n        };\n\n        add((uint8_t)s.pos);\n        add((uint8_t)(s.hold + 1));\n        for (int r = 0; r < N; r++) {\n            add(s.nextIn[r]);\n            add((uint8_t)((int)s.need[r] - r * N));\n        }\n        for (int i = 0; i < 25; i++) {\n            add((uint8_t)(s.cell[i] + 1));\n        }\n        return h;\n    }\n\n    void gen_actions(const State& s, array<char, 8>& acts, int& acnt) const {\n        acnt = 0;\n        bool used[256] = {};\n        auto add = [&](char ch) {\n            unsigned u = (unsigned char)ch;\n            if (!used[u]) {\n                used[u] = true;\n                acts[acnt++] = ch;\n            }\n        };\n        auto add_toward = [&](int target) {\n            int p = s.pos;\n            int r = p / N, c = p % N;\n            int tr = target / N, tc = target % N;\n            if (r < tr) add('D');\n            if (r > tr) add('U');\n            if (c < tc) add('R');\n            if (c > tc) add('L');\n        };\n\n        int pos = s.pos;\n        int r = pos / N, c = pos % N;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            int gate = dr * N + (N - 1);\n\n            if (v == s.need[dr]) {\n                if (pos == gate && s.cell[pos] == -1) add('Q');\n                add_toward(gate);\n            } else {\n                if (s.cell[pos] == -1 && c != N - 1) add('Q');\n\n                pair<int,int> cand[25];\n                int m = 0;\n                for (int idx = 0; idx < 25; idx++) {\n                    int rr = idx / N, cc = idx % N;\n                    if (cc == N - 1) continue;\n                    if (s.cell[idx] != -1) continue;\n                    int pen = (cc == 0 && s.nextIn[rr] < N) ? 30 : 0;\n                    int sc = dist[pos][idx] + dist[idx][gate] + pen;\n                    cand[m++] = {sc, idx};\n                }\n                sort(cand, cand + m);\n                for (int i = 0; i < min(2, m); i++) add_toward(cand[i].second);\n            }\n        } else {\n            if (s.cell[pos] != -1) add('P');\n\n            pair<int,int> ready[5];\n            int rcnt = 0;\n            for (int rr = 0; rr < N; rr++) {\n                int x = s.need[rr];\n                if (x >= rr * N + N) continue;\n                int lp = s.loc[x];\n                if (lp >= 0) {\n                    int sc = dist[pos][lp] + dist[lp][rr * N + (N - 1)];\n                    ready[rcnt++] = {sc, lp};\n                }\n            }\n\n            if (rcnt > 0) {\n                sort(ready, ready + rcnt);\n                for (int i = 0; i < min(3, rcnt); i++) {\n                    add_toward(ready[i].second);\n                }\n            } else {\n                pair<int,int> rev[5];\n                int vcnt = 0;\n                for (int rr = 0; rr < N; rr++) {\n                    int x = s.need[rr];\n                    if (x >= rr * N + N) continue;\n                    int src = srcRow[x];\n                    int front = (int)s.nextIn[src] - (s.cell[src * N] == -1 ? 0 : 1);\n                    int depth = srcIdx[x] - front;\n                    if (depth < 0) depth = 0;\n                    int gp = src * N;\n                    int sc = depth * 10 + dist[pos][gp];\n                    rev[vcnt++] = {sc, gp};\n                }\n                sort(rev, rev + vcnt);\n                for (int i = 0; i < min(2, vcnt); i++) {\n                    add_toward(rev[i].second);\n                }\n            }\n        }\n\n        if (acnt < 2) {\n            if (r > 0) add('U');\n            if (r < N - 1) add('D');\n            if (c > 0) add('L');\n            if (c < N - 1) add('R');\n        }\n\n        if (acnt == 0) add('.');\n    }\n\n    vector<char> reconstruct(int traceId, const vector<Trace>& traces) const {\n        vector<char> rev;\n        while (traceId > 0) {\n            rev.push_back(traces[traceId].act);\n            traceId = traces[traceId].parent;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    bool validate(const vector<char>& actions) const {\n        State s = initial_state();\n        for (char a : actions) {\n            State sp = s, ns;\n            spawn(sp);\n            if (!apply_action_dispatch(sp, a, ns)) return false;\n            s = ns;\n        }\n        return is_goal(s);\n    }\n\n    bool search(int boundLen, int width, double timeLimitSec,\n                const chrono::steady_clock::time_point& start,\n                vector<char>& outActions) const {\n        if (boundLen <= 1) return false;\n        int maxDepth = min(boundLen - 1, 10000);\n\n        vector<Trace> traces;\n        traces.reserve((size_t)width * 400 + 16);\n        traces.push_back({-1, '?'});\n\n        vector<BeamItem> cur, nxt;\n        cur.reserve(width + 16);\n        nxt.reserve(width + 16);\n\n        State init = initial_state();\n        int lb0 = lower_bound(init);\n        if (lb0 >= boundLen) return false;\n        cur.push_back({init, 0, eval_state(init, lb0)});\n\n        vector<Cand> cands;\n        cands.reserve((size_t)width * 6 + 100);\n\n        auto time_over = [&]() -> bool {\n            double e = chrono::duration<double>(chrono::steady_clock::now() - start).count();\n            return e > timeLimitSec;\n        };\n\n        for (int depth = 0; depth < maxDepth; depth++) {\n            if (time_over()) return false;\n\n            cands.clear();\n\n            int it = 0;\n            for (const auto& bi : cur) {\n                if ((it++ & 127) == 0 && time_over()) return false;\n\n                State sp = bi.st;\n                spawn(sp);\n\n                array<char, 8> acts{};\n                int acnt = 0;\n                gen_actions(sp, acts, acnt);\n\n                for (int i = 0; i < acnt; i++) {\n                    State ns;\n                    char act = acts[i];\n                    if (!apply_action_dispatch(sp, act, ns)) continue;\n\n                    int nd = depth + 1;\n                    if (is_goal(ns)) {\n                        int tr = (int)traces.size();\n                        traces.push_back({bi.trace, act});\n                        outActions = reconstruct(tr, traces);\n                        return true;\n                    }\n\n                    int lb = lower_bound(ns);\n                    if (nd + lb >= boundLen) continue;\n\n                    int ev = eval_state(ns, lb);\n                    uint64_t h = hash_state(ns);\n\n                    cands.push_back({ns, bi.trace, act, ev, h});\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                if (a.h != b.h) return a.h < b.h;\n                return a.eval > b.eval;\n            });\n\n            vector<Cand> uniq;\n            uniq.reserve(cands.size());\n            for (size_t i = 0; i < cands.size();) {\n                size_t j = i + 1;\n                Cand best = cands[i];\n                while (j < cands.size() && cands[j].h == cands[i].h) {\n                    if (cands[j].eval > best.eval) best = cands[j];\n                    j++;\n                }\n                uniq.push_back(std::move(best));\n                i = j;\n            }\n\n            if ((int)uniq.size() > width) {\n                nth_element(uniq.begin(), uniq.begin() + width, uniq.end(),\n                            [](const Cand& a, const Cand& b) {\n                                return a.eval > b.eval;\n                            });\n                uniq.resize(width);\n            }\n\n            nxt.clear();\n            nxt.reserve(uniq.size());\n            for (const auto& cd : uniq) {\n                int tr = (int)traces.size();\n                traces.push_back({cd.parentTrace, cd.act});\n                nxt.push_back({cd.st, tr, cd.eval});\n            }\n\n            cur.swap(nxt);\n            if (cur.empty()) break;\n        }\n\n        return false;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> A(N, vector<int>(N));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> A[i][j];\n    }\n\n    auto start = chrono::steady_clock::now();\n\n    // Robust baseline\n    GreedySolver greedy(N, A);\n    greedy.solve();\n    int greedyLen = (int)greedy.out[0].size();\n\n    // Improvement phase: beam search under strict M1/M2=0 constraints\n    vector<char> beamActs;\n    bool useBeam = false;\n\n    if (greedyLen > 1) {\n        BeamSolver beam(A);\n        int width = 2200;\n        double timeLimitSec = 2.70; // leave margin for system-test slowdown\n        bool ok = beam.search(greedyLen, width, timeLimitSec, start, beamActs);\n        if (ok && !beamActs.empty() && (int)beamActs.size() < greedyLen && beam.validate(beamActs)) {\n            useBeam = true;\n        }\n    }\n\n    if (useBeam) {\n        int T = (int)beamActs.size();\n        string s0;\n        s0.reserve(T);\n        for (char c : beamActs) s0.push_back(c);\n        cout << s0 << '\\n';\n        for (int i = 1; i < N; i++) {\n            string si(T, '.');\n            if (T > 0) si[0] = 'B';\n            else si = \".\";\n            cout << si << '\\n';\n        }\n    } else {\n        for (int i = 0; i < N; i++) {\n            if (greedy.out[i].empty()) {\n                if (i == 0) cout << \".\\n\";\n                else cout << \"B\\n\";\n            } else {\n                cout << greedy.out[i] << '\\n';\n            }\n        }\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SimResult {\n    long long cost = (1LL << 62);\n    int turns = 0;\n    bool valid = false;\n    vector<string> ops;\n};\n\nclass Solver {\n    static constexpr int MAX_N = 20;\n    static constexpr int MAX_M = 400;\n    static constexpr int MAX_TURNS = 100000;\n    static constexpr long long INF64 = (1LL << 62);\n    static constexpr int INF_CAP = 1000000000;\n    inline static const array<int, 11> CAPS = {\n        160, 220, 300, 400, 550, 750, 1000, 1400, 2000, 3000, INF_CAP\n    };\n\n    int N = 0, M = 0;\n    int init_h[MAX_M]{};\n    int rr[MAX_M]{}, cc[MAX_M]{};\n    uint8_t distm[MAX_M][MAX_M]{};\n\n    int init_near_pos[MAX_M]{};\n    int init_near_neg[MAX_M]{};\n    long long total_positive = 0;\n\n    uint64_t input_hash = 0;\n\n    vector<vector<int>> cycles;\n    vector<vector<int>> paths;\n\n    struct GParam {\n        int cap = 800;\n        int mode = 0;               // 0: strict, 1: mixed, 2: trip-aware\n        int dist_scale = 256;\n        int link_scale = 80;        // mainly mode=2\n        int src_bias = 2;\n        int dst_bias = 2;\n        bool collect_when_loaded = false;\n        int force_sink_ratio = 70;\n        int src_loaded_pen = 1;\n        int sink_empty_pen = 1;\n        int axis_pref = 2;          // 0 vertical, 1 horizontal, 2 adaptive\n        int path_unload_bonus = 130;\n        int path_load_bonus = 70;\n        int back_penalty = 40;\n        bool retarget_on_change = true;\n    };\n\n    enum class BestType { NONE, CYCLE, PATH, GREEDY };\n\n    struct CycleSpec {\n        int ci = 0;\n        int dir = 1;\n        int shift = 0;\n    };\n    struct PathSpec {\n        int pi = 0;\n        int cleanup_type = 0;\n    };\n    struct GreedySpec {\n        GParam p{};\n        uint64_t seed = 1;\n    };\n    struct EliteItem {\n        GParam p{};\n        uint64_t seed = 1;\n        long long cost = INF64;\n    };\n\n    static uint64_t xorshift64(uint64_t &x) {\n        if (x == 0) x = 88172645463325252ULL;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n\n    static int randInt(uint64_t &x, int l, int r) {\n        return l + (int)(xorshift64(x) % (uint64_t)(r - l + 1));\n    }\n\n    int modM(int x) const {\n        x %= M;\n        if (x < 0) x += M;\n        return x;\n    }\n\n    vector<int> buildBaseCycle() const {\n        // Hamiltonian cycle for even N\n        vector<int> cyc;\n        cyc.reserve(M);\n\n        for (int c = 0; c < N; c++) cyc.push_back(c);\n        for (int r = 1; r < N; r++) {\n            if (r & 1) for (int c = N - 1; c >= 1; c--) cyc.push_back(r * N + c);\n            else for (int c = 1; c < N; c++) cyc.push_back(r * N + c);\n        }\n        for (int r = N - 1; r >= 1; r--) cyc.push_back(r * N);\n\n        return cyc;\n    }\n\n    pair<int, int> transformPoint(int r, int c, int t) const {\n        switch (t) {\n            case 0: return {r, c};\n            case 1: return {r, N - 1 - c};\n            case 2: return {N - 1 - r, c};\n            case 3: return {N - 1 - r, N - 1 - c};\n            case 4: return {c, r};\n            case 5: return {c, N - 1 - r};\n            case 6: return {N - 1 - c, r};\n            case 7: return {N - 1 - c, N - 1 - r};\n        }\n        return {r, c};\n    }\n\n    vector<int> transformCycle(const vector<int> &base, int t) const {\n        vector<int> out;\n        out.reserve(M);\n        for (int id : base) {\n            int r = id / N, c = id % N;\n            auto [nr, nc] = transformPoint(r, c, t);\n            out.push_back(nr * N + nc);\n        }\n        auto it = find(out.begin(), out.end(), 0);\n        if (it != out.end()) rotate(out.begin(), it, out.end());\n        return out;\n    }\n\n    vector<int> buildRowSnake() const {\n        vector<int> v;\n        v.reserve(M);\n        for (int r = 0; r < N; r++) {\n            if ((r & 1) == 0) for (int c = 0; c < N; c++) v.push_back(r * N + c);\n            else for (int c = N - 1; c >= 0; c--) v.push_back(r * N + c);\n        }\n        return v;\n    }\n\n    vector<int> buildColSnake() const {\n        vector<int> v;\n        v.reserve(M);\n        for (int c = 0; c < N; c++) {\n            if ((c & 1) == 0) for (int r = 0; r < N; r++) v.push_back(r * N + c);\n            else for (int r = N - 1; r >= 0; r--) v.push_back(r * N + c);\n        }\n        return v;\n    }\n\n    vector<int> buildSpiralCW() const {\n        vector<int> ord;\n        ord.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int c = left; c <= right; c++) ord.push_back(top * N + c);\n            top++;\n            for (int r = top; r <= bottom; r++) ord.push_back(r * N + right);\n            right--;\n            if (top <= bottom) {\n                for (int c = right; c >= left; c--) ord.push_back(bottom * N + c);\n                bottom--;\n            }\n            if (left <= right) {\n                for (int r = bottom; r >= top; r--) ord.push_back(r * N + left);\n                left++;\n            }\n        }\n        return ord;\n    }\n\n    vector<int> buildSpiralCCW() const {\n        vector<int> ord;\n        ord.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int r = top; r <= bottom; r++) ord.push_back(r * N + left);\n            left++;\n            for (int c = left; c <= right; c++) ord.push_back(bottom * N + c);\n            bottom--;\n            if (left <= right) {\n                for (int r = bottom; r >= top; r--) ord.push_back(r * N + right);\n                right--;\n            }\n            if (top <= bottom) {\n                for (int c = right; c >= left; c--) ord.push_back(top * N + c);\n                top++;\n            }\n        }\n        return ord;\n    }\n\n    bool isValidPath(const vector<int> &ord) const {\n        if ((int)ord.size() != M) return false;\n        if (ord[0] != 0) return false;\n\n        static int seen[MAX_M];\n        for (int i = 0; i < M; i++) seen[i] = 0;\n\n        for (int i = 0; i < M; i++) {\n            int id = ord[i];\n            if (id < 0 || id >= M || seen[id]) return false;\n            seen[id] = 1;\n            if (i > 0 && distm[ord[i - 1]][id] != 1) return false;\n        }\n        return true;\n    }\n\n    void addPathIfValid(const vector<int> &ord) {\n        if (!isValidPath(ord)) return;\n        for (auto &p : paths) if (p == ord) return;\n        paths.push_back(ord);\n    }\n\n    void addPathTransforms(const vector<int> &base) {\n        for (int t = 0; t < 8; t++) {\n            vector<int> p;\n            p.reserve(M);\n            for (int id : base) {\n                int r = id / N, c = id % N;\n                auto [nr, nc] = transformPoint(r, c, t);\n                p.push_back(nr * N + nc);\n            }\n            addPathIfValid(p);\n            reverse(p.begin(), p.end());\n            addPathIfValid(p);\n        }\n    }\n\n    template <bool RECORD>\n    SimResult simulateCycle(const vector<int> &cyc, int dir, int shift, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0, idx = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(30000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        // initial shift\n        for (int t = 0; t < shift; t++) {\n            idx = modM(idx + dir);\n            if (!doMove(cyc[idx])) return fail();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n        }\n\n        // one-pass processing\n        for (int t = 0; t < M; t++) {\n            int cell = cyc[idx];\n            if (h[cell] > 0) {\n                doLoad(h[cell]);\n                h[cell] = 0;\n            } else if (h[cell] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[cell]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                idx = modM(idx + dir);\n                if (!doMove(cyc[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // cleanup remaining deficits if load > 0\n        while (load > 0) {\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (load == 0) break;\n\n            int best = -1, bestDist = INT_MAX, bestDef = -1;\n            for (int id = 0; id < M; id++) if (h[id] < 0) {\n                int d = distm[pos][id];\n                int def = -h[id];\n                if (d < bestDist || (d == bestDist && def > bestDef)) {\n                    bestDist = d;\n                    bestDef = def;\n                    best = id;\n                }\n            }\n            if (best < 0) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (nxt < 0) return fail();\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!doMove(nxt)) return fail();\n\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (turns <= MAX_TURNS && load == 0 && posRemain == 0 && negRemain == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    template <bool RECORD>\n    SimResult simulatePath(const vector<int> &ord, int cleanup_type, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(35000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        for (int t = 0; t < M; t++) {\n            int cell = ord[t];\n            if (cell != pos) return fail();\n\n            if (h[cell] > 0) {\n                doLoad(h[cell]);\n                h[cell] = 0;\n            } else if (h[cell] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[cell]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                if (!doMove(ord[t + 1])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // optional reverse backtrack before nearest cleanup\n        if (cleanup_type == 1) {\n            int idx = M - 1;\n            while (load > 0 && idx > 0) {\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n                if (load == 0) break;\n\n                idx--;\n                if (!doMove(ord[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        while (load > 0) {\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (load == 0) break;\n\n            int best = -1, bestDist = INT_MAX, bestDef = -1;\n            for (int id = 0; id < M; id++) if (h[id] < 0) {\n                int d = distm[pos][id];\n                int def = -h[id];\n                if (d < bestDist || (d == bestDist && def > bestDef)) {\n                    bestDist = d;\n                    bestDef = def;\n                    best = id;\n                }\n            }\n            if (best < 0) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (nxt < 0) return fail();\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!doMove(nxt)) return fail();\n\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (turns <= MAX_TURNS && load == 0 && posRemain == 0 && negRemain == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    template <bool RECORD>\n    SimResult simulateGreedy(const GParam &p, uint64_t seed, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0, prevPos = -1;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(100000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        auto canLoadPolicy = [&](long long curLoad) -> bool {\n            if (curLoad >= p.cap) return false;\n            if (curLoad == 0) return true;\n            return p.collect_when_loaded;\n        };\n\n        auto processHere = [&]() {\n            if (load > 0 && h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (h[pos] > 0 && canLoadPolicy(load)) {\n                long long room = (long long)p.cap - load;\n                if (room > 0) {\n                    int d = (int)min<long long>(room, (long long)h[pos]);\n                    if (d > 0) {\n                        doLoad(d);\n                        h[pos] -= d;\n                    }\n                }\n            }\n        };\n\n        struct TargetInfo {\n            int id = -1;\n            long long val = INF64;\n            int gain = -1;\n        };\n\n        auto bestSource = [&](int from, long long curLoad) -> TargetInfo {\n            TargetInfo best;\n            if (!canLoadPolicy(curLoad)) return best;\n            long long room = (long long)p.cap - curLoad;\n            if (room <= 0) return best;\n\n            for (int id = 0; id < M; id++) {\n                int amt = h[id];\n                if (amt <= 0) continue;\n\n                int gain = (int)min<long long>((long long)amt, room);\n                int d = distm[from][id];\n\n                long long val = 1LL * p.dist_scale * d - 1LL * p.src_bias * gain;\n                if (p.mode == 2) val += 1LL * p.link_scale * init_near_neg[id];\n\n                if (val < best.val ||\n                    (val == best.val && gain > best.gain) ||\n                    (val == best.val && gain == best.gain && (xorshift64(seed) & 1ULL))) {\n                    best.id = id;\n                    best.val = val;\n                    best.gain = gain;\n                }\n            }\n            return best;\n        };\n\n        auto bestSink = [&](int from, long long curLoad) -> TargetInfo {\n            TargetInfo best;\n            if (curLoad <= 0) return best;\n\n            for (int id = 0; id < M; id++) {\n                int amt = -h[id];\n                if (amt <= 0) continue;\n\n                int gain = (int)min<long long>((long long)amt, curLoad);\n                int d = distm[from][id];\n\n                long long val = 1LL * p.dist_scale * d - 1LL * p.dst_bias * gain;\n                if (p.mode == 2) val += 1LL * p.link_scale * init_near_pos[id];\n\n                if (val < best.val ||\n                    (val == best.val && gain > best.gain) ||\n                    (val == best.val && gain == best.gain && (xorshift64(seed) & 1ULL))) {\n                    best.id = id;\n                    best.val = val;\n                    best.gain = gain;\n                }\n            }\n            return best;\n        };\n\n        auto chooseNext = [&](int target, int prevCell) -> int {\n            int r = rr[pos], c = cc[pos];\n            int tr = rr[target], tc = cc[target];\n\n            int cand[2];\n            int sz = 0;\n            if (r < tr) cand[sz++] = pos + N;\n            else if (r > tr) cand[sz++] = pos - N;\n            if (c < tc) cand[sz++] = pos + 1;\n            else if (c > tc) cand[sz++] = pos - 1;\n\n            if (sz == 0) return -1;\n            if (sz == 1) return cand[0];\n\n            auto scoreCell = [&](int id) -> long long {\n                long long s = 0;\n                if (load > 0 && h[id] < 0) {\n                    s += 1LL * p.path_unload_bonus * min<long long>(load, -1LL * h[id]);\n                }\n                if (canLoadPolicy(load) && h[id] > 0) {\n                    long long room = (long long)p.cap - load;\n                    if (room > 0) {\n                        s += 1LL * p.path_load_bonus * min<long long>(room, (long long)h[id]);\n                    }\n                }\n                if (id == prevCell) s -= p.back_penalty;\n                return s;\n            };\n\n            long long s0 = scoreCell(cand[0]);\n            long long s1 = scoreCell(cand[1]);\n            if (s1 > s0) return cand[1];\n            if (s1 < s0) return cand[0];\n\n            bool v0 = (rr[cand[0]] != r);\n            bool v1 = (rr[cand[1]] != r);\n\n            if (p.axis_pref == 0) {\n                if (v0 != v1) return v0 ? cand[0] : cand[1];\n            } else if (p.axis_pref == 1) {\n                if (v0 != v1) return v0 ? cand[1] : cand[0];\n            } else {\n                int dr = abs(tr - r), dc = abs(tc - c);\n                if (dr != dc && v0 != v1) {\n                    if (dr > dc) return v0 ? cand[0] : cand[1];\n                    else return v0 ? cand[1] : cand[0];\n                }\n            }\n\n            return (xorshift64(seed) & 1ULL) ? cand[0] : cand[1];\n        };\n\n        int stagnation = 0;\n\n        for (int outer = 0; outer < 180000; outer++) {\n            long long beforePos = posRemain;\n            long long beforeNeg = negRemain;\n            long long beforeLoad = load;\n            int beforeCell = pos;\n\n            processHere();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n            TargetInfo src = bestSource(pos, load);\n            TargetInfo sink = bestSink(pos, load);\n\n            bool seekSource = false;\n            if (p.mode == 0) {\n                seekSource = (load == 0);\n            } else {\n                if (load == 0) {\n                    seekSource = true;\n                } else {\n                    long long refCap = (p.cap >= INF_CAP / 2)\n                        ? min<long long>(max<long long>(400, total_positive / 3), 4000)\n                        : p.cap;\n\n                    if (load * 100 >= 1LL * p.force_sink_ratio * refCap) {\n                        seekSource = false;\n                    } else {\n                        long long srcEval = (src.id == -1 ? INF64 : src.val + 1LL * p.src_loaded_pen * load);\n                        long long sinkEval = (sink.id == -1 ? INF64 : sink.val + 1LL * p.sink_empty_pen * max<long long>(0, refCap - load));\n\n                        if (p.mode == 2) {\n                            sinkEval -= load / 5;\n                            if (load > refCap / 2) srcEval += load / 8;\n                        }\n                        seekSource = (srcEval < sinkEval);\n                    }\n                }\n            }\n\n            if (seekSource && src.id == -1) seekSource = false;\n            if (!seekSource && sink.id == -1) seekSource = true;\n\n            int target = seekSource ? src.id : sink.id;\n            if (target < 0) return fail();\n\n            long long startLoad = load;\n            int guard = 0;\n\n            while (pos != target) {\n                int nxt = chooseNext(target, prevPos);\n                if (nxt < 0) return fail();\n\n                int old = pos;\n                if (!doMove(nxt)) return fail();\n                prevPos = old;\n\n                processHere();\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n                if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n                if (seekSource) {\n                    if (load >= p.cap) break;\n                    if (!p.collect_when_loaded && load > 0) break;\n                    if (p.retarget_on_change && load > startLoad) break;\n                } else {\n                    if (load == 0) break;\n                    if (p.retarget_on_change && load < startLoad) break;\n                }\n\n                if (++guard > 3000) break;\n            }\n\n            if (beforePos == posRemain && beforeNeg == negRemain &&\n                beforeLoad == load && beforeCell == pos) stagnation++;\n            else stagnation = 0;\n\n            if (stagnation > 3200) return fail();\n        }\n\n        bool valid = (turns <= MAX_TURNS && posRemain == 0 && negRemain == 0 && load == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    int capIndex(int cap) const {\n        int best = 0;\n        long long bestDiff = llabs((long long)CAPS[0] - cap);\n        for (int i = 1; i < (int)CAPS.size(); i++) {\n            long long d = llabs((long long)CAPS[i] - cap);\n            if (d < bestDiff) {\n                bestDiff = d;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    GParam randomParam(uint64_t &rng) const {\n        GParam p;\n        p.cap = CAPS[randInt(rng, 0, (int)CAPS.size() - 1)];\n        p.mode = randInt(rng, 0, 2);\n        p.dist_scale = randInt(rng, 150, 430);\n        p.link_scale = randInt(rng, 0, 260);\n        p.src_bias = randInt(rng, 0, 12);\n        p.dst_bias = randInt(rng, 0, 12);\n\n        int collectProb = (p.mode == 0 ? 25 : 45);\n        p.collect_when_loaded = (randInt(rng, 0, 99) < collectProb);\n\n        p.force_sink_ratio = randInt(rng, 40, 95);\n        p.src_loaded_pen = randInt(rng, 0, 8);\n        p.sink_empty_pen = randInt(rng, 0, 8);\n        p.axis_pref = randInt(rng, 0, 2);\n        p.path_unload_bonus = randInt(rng, 60, 260);\n        p.path_load_bonus = randInt(rng, 10, 190);\n        p.back_penalty = randInt(rng, 0, 180);\n        p.retarget_on_change = (randInt(rng, 0, 1) == 1);\n        return p;\n    }\n\n    GParam mutateParam(const GParam &base, uint64_t &rng) const {\n        GParam p = base;\n\n        auto clampi = [&](int &x, int l, int r) {\n            if (x < l) x = l;\n            if (x > r) x = r;\n        };\n\n        int changes = randInt(rng, 1, 5);\n        for (int it = 0; it < changes; it++) {\n            int sw = randInt(rng, 0, 14);\n            int delta = (int)(xorshift64(rng) % 5ULL) - 2; // [-2,2]\n\n            switch (sw) {\n                case 0: {\n                    int idx = capIndex(p.cap);\n                    idx += delta;\n                    idx = max(0, min((int)CAPS.size() - 1, idx));\n                    p.cap = CAPS[idx];\n                    break;\n                }\n                case 1:\n                    p.mode = randInt(rng, 0, 2);\n                    break;\n                case 2:\n                    p.dist_scale += delta * 20;\n                    clampi(p.dist_scale, 130, 520);\n                    break;\n                case 3:\n                    p.link_scale += delta * 20;\n                    clampi(p.link_scale, 0, 340);\n                    break;\n                case 4:\n                    p.src_bias += delta;\n                    clampi(p.src_bias, 0, 16);\n                    break;\n                case 5:\n                    p.dst_bias += delta;\n                    clampi(p.dst_bias, 0, 16);\n                    break;\n                case 6:\n                    p.collect_when_loaded = !p.collect_when_loaded;\n                    break;\n                case 7:\n                    p.force_sink_ratio += delta * 5;\n                    clampi(p.force_sink_ratio, 30, 99);\n                    break;\n                case 8:\n                    p.src_loaded_pen += delta;\n                    clampi(p.src_loaded_pen, 0, 12);\n                    break;\n                case 9:\n                    p.sink_empty_pen += delta;\n                    clampi(p.sink_empty_pen, 0, 12);\n                    break;\n                case 10:\n                    p.axis_pref = randInt(rng, 0, 2);\n                    break;\n                case 11:\n                    p.path_unload_bonus += delta * 20;\n                    clampi(p.path_unload_bonus, 30, 340);\n                    break;\n                case 12:\n                    p.path_load_bonus += delta * 20;\n                    clampi(p.path_load_bonus, 0, 260);\n                    break;\n                case 13:\n                    p.back_penalty += delta * 20;\n                    clampi(p.back_penalty, 0, 240);\n                    break;\n                case 14:\n                    p.retarget_on_change = !p.retarget_on_change;\n                    break;\n            }\n        }\n        return p;\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        M = N * N;\n\n        bool allZero = true;\n        input_hash = 1469598103934665603ULL;\n        total_positive = 0;\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int x;\n                cin >> x;\n                int id = r * N + c;\n                init_h[id] = x;\n                rr[id] = r;\n                cc[id] = c;\n                if (x != 0) allZero = false;\n                if (x > 0) total_positive += x;\n\n                input_hash ^= (uint64_t)(x + 1000);\n                input_hash *= 1099511628211ULL;\n            }\n        }\n\n        if (allZero) return;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                distm[i][j] = (uint8_t)(abs(rr[i] - rr[j]) + abs(cc[i] - cc[j]));\n            }\n        }\n\n        vector<int> posIds, negIds;\n        posIds.reserve(M);\n        negIds.reserve(M);\n        for (int i = 0; i < M; i++) {\n            if (init_h[i] > 0) posIds.push_back(i);\n            else if (init_h[i] < 0) negIds.push_back(i);\n        }\n\n        for (int i = 0; i < M; i++) {\n            int bp = INT_MAX, bn = INT_MAX;\n            for (int id : posIds) bp = min(bp, (int)distm[i][id]);\n            for (int id : negIds) bn = min(bn, (int)distm[i][id]);\n            init_near_pos[i] = (bp == INT_MAX ? 0 : bp);\n            init_near_neg[i] = (bn == INT_MAX ? 0 : bn);\n        }\n\n        // Build cycle candidates\n        cycles.clear();\n        vector<int> baseCycle = buildBaseCycle();\n        for (int t = 0; t < 8; t++) {\n            auto cyc = transformCycle(baseCycle, t);\n            if ((int)cyc.size() != M || cyc[0] != 0) continue;\n            bool dup = false;\n            for (auto &v : cycles) if (v == cyc) { dup = true; break; }\n            if (!dup) cycles.push_back(move(cyc));\n        }\n        if (cycles.empty()) cycles.push_back(baseCycle);\n\n        // Build path candidates (with transforms/reverse)\n        paths.clear();\n        addPathTransforms(buildRowSnake());\n        addPathTransforms(buildColSnake());\n        addPathTransforms(buildSpiralCW());\n        addPathTransforms(buildSpiralCCW());\n        if (paths.empty()) addPathIfValid(buildRowSnake());\n\n        auto tStart = chrono::steady_clock::now();\n        auto elapsed = [&]() -> double {\n            return chrono::duration<double>(chrono::steady_clock::now() - tStart).count();\n        };\n        const double TIME_LIMIT = 1.90;\n\n        long long bestCost = INF64;\n        BestType bestType = BestType::NONE;\n        CycleSpec bestCycle;\n        PathSpec bestPath;\n        GreedySpec bestGreedy;\n\n        // quick baseline\n        if (!paths.empty()) {\n            auto b = simulatePath<false>(paths[0], 1, INF64);\n            if (b.valid && b.cost < bestCost) {\n                bestCost = b.cost;\n                bestType = BestType::PATH;\n                bestPath = {0, 1};\n            }\n        }\n\n        // cycle search\n        for (int ci = 0; ci < (int)cycles.size(); ci++) {\n            for (int dir : {1, -1}) {\n                for (int shift = 0; shift < M; shift++) {\n                    auto cur = simulateCycle<false>(cycles[ci], dir, shift, bestCost);\n                    if (cur.valid && cur.cost < bestCost) {\n                        bestCost = cur.cost;\n                        bestType = BestType::CYCLE;\n                        bestCycle = {ci, dir, shift};\n                    }\n                }\n            }\n        }\n\n        // path search\n        for (int pi = 0; pi < (int)paths.size(); pi++) {\n            for (int ct = 0; ct <= 1; ct++) {\n                auto cur = simulatePath<false>(paths[pi], ct, bestCost);\n                if (cur.valid && cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::PATH;\n                    bestPath = {pi, ct};\n                }\n            }\n        }\n\n        vector<EliteItem> elite;\n        auto addElite = [&](const GParam &p, uint64_t sd, long long c) {\n            if (c >= INF64 / 2) return;\n            elite.push_back({p, sd, c});\n            sort(elite.begin(), elite.end(), [](const EliteItem &a, const EliteItem &b) {\n                return a.cost < b.cost;\n            });\n            const int EL = 12;\n            if ((int)elite.size() > EL) elite.resize(EL);\n        };\n\n        // deterministic greedy seeds\n        vector<GParam> seedParams;\n        auto makeP = [&](int cap, int mode, int dist, int link, int sb, int db, bool collect,\n                         int force, int slp, int sep, int axis, int ub, int lb, int back, bool ret) {\n            GParam p;\n            p.cap = cap;\n            p.mode = mode;\n            p.dist_scale = dist;\n            p.link_scale = link;\n            p.src_bias = sb;\n            p.dst_bias = db;\n            p.collect_when_loaded = collect;\n            p.force_sink_ratio = force;\n            p.src_loaded_pen = slp;\n            p.sink_empty_pen = sep;\n            p.axis_pref = axis;\n            p.path_unload_bonus = ub;\n            p.path_load_bonus = lb;\n            p.back_penalty = back;\n            p.retarget_on_change = ret;\n            return p;\n        };\n\n        vector<int> capList = {220, 400, 750, 1400, 3000, INF_CAP};\n        for (int cap : capList) {\n            seedParams.push_back(makeP(cap, 0, 250, 60, 2, 2, false, 70, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 1, 240, 70, 2, 2, false, 68, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 1, 230, 80, 2, 2, true,  65, 1, 1, 2, 120, 90, 45, true));\n            seedParams.push_back(makeP(cap, 2, 230, 100, 2, 2, false, 70, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 2, 220, 120, 2, 2, true,  65, 1, 1, 2, 120, 95, 45, true));\n        }\n        seedParams.push_back(makeP(INF_CAP, 2, 250, 140, 1, 3, false, 75, 2, 1, 0, 110, 70, 60, true));\n        seedParams.push_back(makeP(INF_CAP, 2, 250, 140, 1, 3, false, 75, 2, 1, 1, 110, 70, 60, true));\n\n        const uint64_t MUL = 0x9e3779b97f4a7c15ULL;\n\n        bool stopSeed = false;\n        for (int i = 0; i < (int)seedParams.size() && !stopSeed; i++) {\n            for (int rep = 0; rep < 2; rep++) {\n                if (elapsed() > 1.20) { stopSeed = true; break; }\n\n                uint64_t sd = input_hash ^ (MUL * (uint64_t)(i * 2 + rep + 1));\n                if (sd == 0) sd = 88172645463325252ULL;\n\n                auto cur = simulateGreedy<false>(seedParams[i], sd, INF64);\n                if (!cur.valid) continue;\n\n                addElite(seedParams[i], sd, cur.cost);\n\n                if (cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::GREEDY;\n                    bestGreedy = {seedParams[i], sd};\n                }\n            }\n        }\n\n        // randomized elite local search\n        uint64_t rng = input_hash ^ 0xd1b54a32d192ed03ULL;\n        if (rng == 0) rng = 88172645463325252ULL;\n\n        int iter = 0;\n        while (elapsed() < TIME_LIMIT) {\n            GParam p;\n            if (!elite.empty() && randInt(rng, 0, 99) < 85) {\n                int top = min<int>((int)elite.size(), 6);\n                int idx = randInt(rng, 0, top - 1);\n                p = mutateParam(elite[idx].p, rng);\n                if (randInt(rng, 0, 99) < 8) p = randomParam(rng);\n            } else {\n                p = randomParam(rng);\n            }\n\n            uint64_t sd = xorshift64(rng) ^ (MUL * (uint64_t)(iter + 10007));\n            if (sd == 0) sd = 88172645463325252ULL;\n\n            long long cutoff = INF64;\n            if (bestCost < INF64 / 2) {\n                if ((iter & 3) != 0) cutoff = bestCost;\n                else cutoff = min(INF64, bestCost + 20000);\n            }\n\n            auto cur = simulateGreedy<false>(p, sd, cutoff);\n            if (cur.valid) {\n                addElite(p, sd, cur.cost);\n\n                if (cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::GREEDY;\n                    bestGreedy = {p, sd};\n                }\n            }\n            iter++;\n        }\n\n        SimResult ans;\n        if (bestType == BestType::CYCLE) {\n            ans = simulateCycle<true>(cycles[bestCycle.ci], bestCycle.dir, bestCycle.shift, INF64);\n        } else if (bestType == BestType::PATH) {\n            ans = simulatePath<true>(paths[bestPath.pi], bestPath.cleanup_type, INF64);\n        } else if (bestType == BestType::GREEDY) {\n            ans = simulateGreedy<true>(bestGreedy.p, bestGreedy.seed, INF64);\n        }\n\n        // safety fallback\n        if (!ans.valid) {\n            bool ok = false;\n\n            if (!elite.empty()) {\n                auto r = simulateGreedy<true>(elite[0].p, elite[0].seed, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            for (int pi = 0; pi < (int)paths.size() && !ok; pi++) {\n                auto r = simulatePath<true>(paths[pi], 1, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            for (int ci = 0; ci < (int)cycles.size() && !ok; ci++) {\n                auto r = simulateCycle<true>(cycles[ci], 1, 0, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            if (!ok) {\n                // legal fallback: do nothing\n                ans.valid = true;\n            }\n        }\n\n        for (const auto &s : ans.ops) {\n            cout << s << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nclass Solver {\n    static constexpr int MAXS = 60;\n    static constexpr int MAXM = 15;\n\n    struct Params {\n        double progress = 0.0; // 0..1\n\n        // pair score = mu + cSigma * sigma + cGain * gain\n        double cSigma = 1.0;\n        double cGain = 0.5;\n\n        // layout objective\n        double wSum = 1.0;\n        double wBest1 = 0.0;   // best edge\n        double wBest24 = 0.0;  // 2nd+3rd+4th edge\n        double beta1 = 0.0;    // coverage top1 per dimension\n        double beta2 = 0.0;    // coverage top2\n        double beta3 = 0.0;    // coverage top3\n\n        // base seed score\n        double rareExact = 0.0; // count of coords == initial max\n        double rareNear = 0.0;  // count of coords >= initial max-2\n        double rareCur2 = 0.0;  // count of coords >= current 2nd-best\n\n        int topV = 20;          // bonus to top-V seeds\n        double bonusV = 8.0;\n        bool preserveInitial = false;\n\n        // SA\n        int restarts = 2;\n        int iters = 8000;\n        double swapProb = 0.4;\n        double temp0 = 70.0;\n        double temp1 = 0.35;\n    };\n\n    int N = 0, M = 0, T = 0;\n    int S = 0, P = 0;\n\n    int X[MAXS][MAXM]{};\n    int V[MAXS]{};\n\n    int initMax[MAXM]{};\n    int curMax[MAXM]{}, cur2[MAXM]{}, cur3[MAXM]{};\n\n    double pairSc[MAXS][MAXS]{};\n    double baseSc[MAXS]{};\n\n    vector<pair<int, int>> edges; // size 2N(N-1)\n    vector<vector<int>> nbr;\n    vector<int> posOrder;\n    vector<int> baseOrder;\n    vector<int> ordV;\n\n    XorShift64 rng;\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> T)) return;\n        S = 2 * N * (N - 1);\n        P = N * N;\n\n        build_field();\n\n        if (!read_seeds()) return;\n\n        // initial per-dimension maxima from initial seeds\n        for (int l = 0; l < M; ++l) {\n            int mx = 0;\n            for (int i = 0; i < S; ++i) mx = max(mx, X[i][l]);\n            initMax[l] = mx;\n        }\n\n        for (int turn = 0; turn < T; ++turn) {\n            vector<int> layout = decide_layout(turn);\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = 0; j < N; ++j) {\n                    if (j) cout << ' ';\n                    cout << layout[i * N + j];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (turn + 1 == T) break; // no need to read after final output\n            if (!read_seeds()) return;\n        }\n    }\n\nprivate:\n    bool read_seeds() {\n        for (int i = 0; i < S; ++i) {\n            for (int l = 0; l < M; ++l) {\n                if (!(cin >> X[i][l])) return false;\n                if (X[i][l] < 0) return false; // interactive error signal\n            }\n            for (int l = M; l < MAXM; ++l) X[i][l] = 0;\n        }\n        return true;\n    }\n\n    void build_field() {\n        edges.clear();\n        nbr.assign(P, {});\n\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p = i * N + j;\n                if (j + 1 < N) {\n                    int q = p + 1;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n                if (i + 1 < N) {\n                    int q = p + N;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n            }\n        }\n\n        posOrder.resize(P);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        const double c = (N - 1) * 0.5;\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            int da = (int)nbr[a].size();\n            int db = (int)nbr[b].size();\n            if (da != db) return da > db;\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n            double ra = fabs(ai - c) + fabs(aj - c);\n            double rb = fabs(bi - c) + fabs(bj - c);\n            if (ra != rb) return ra < rb;\n            return a < b;\n        });\n    }\n\n    Params make_params(int turn) const {\n        Params prm;\n        double p = (T <= 1 ? 1.0 : (double)turn / (double)(T - 1));\n        double q = 1.0 - p;\n        prm.progress = p;\n\n        prm.cSigma = 0.75 + 0.95 * p;\n        prm.cGain  = 0.25 + 0.55 * p;\n\n        prm.wSum    = 1.0 - 0.15 * p;\n        prm.wBest1  = 0.4 + 8.0 * p;\n        prm.wBest24 = 0.15 + 3.0 * p;\n\n        prm.beta1 = 12.0 * q * q + 1.0;\n        prm.beta2 = 4.5 * q * q;\n        prm.beta3 = 1.4 * q * q;\n\n        prm.rareExact = 10.0 * q + 3.0;\n        prm.rareNear  = 3.0 * q + 1.0;\n        prm.rareCur2  = 1.2 * q + 0.2;\n\n        prm.topV = 20 + (int)llround(8.0 * p);\n        prm.bonusV = 7.0 + 2.0 * p;\n\n        prm.preserveInitial = (turn <= 3);\n\n        prm.swapProb = 0.30 + 0.25 * p;\n        prm.temp0 = 75.0 - 18.0 * p;\n        prm.temp1 = 0.35;\n\n        if (turn <= 1) {\n            prm.restarts = 3;\n            prm.iters = 6200 + 500 * turn;\n        } else {\n            prm.restarts = 2;\n            prm.iters = 7000 + 500 * turn;\n        }\n        return prm;\n    }\n\n    void compute_turn_tables(const Params& prm) {\n        // V\n        for (int i = 0; i < S; ++i) {\n            int s = 0;\n            for (int l = 0; l < M; ++l) s += X[i][l];\n            V[i] = s;\n        }\n\n        // ordV\n        ordV.resize(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        // current per-dimension top1/2/3\n        for (int l = 0; l < M; ++l) {\n            int m1 = -1, m2 = -1, m3 = -1;\n            for (int i = 0; i < S; ++i) {\n                int v = X[i][l];\n                if (v > m1) {\n                    m3 = m2;\n                    m2 = m1;\n                    m1 = v;\n                } else if (v > m2) {\n                    m3 = m2;\n                    m2 = v;\n                } else if (v > m3) {\n                    m3 = v;\n                }\n            }\n            if (m2 < 0) m2 = 0;\n            if (m3 < 0) m3 = 0;\n            curMax[l] = m1;\n            cur2[l] = m2;\n            cur3[l] = m3;\n        }\n\n        // base seed score\n        for (int i = 0; i < S; ++i) {\n            int cExact = 0, cNear = 0, cCur2 = 0;\n            for (int l = 0; l < M; ++l) {\n                if (X[i][l] == initMax[l]) ++cExact;\n                if (X[i][l] >= max(0, initMax[l] - 2)) ++cNear;\n                if (X[i][l] >= cur2[l]) ++cCur2;\n            }\n            baseSc[i] = (double)V[i]\n                      + prm.rareExact * cExact\n                      + prm.rareNear  * cNear\n                      + prm.rareCur2  * cCur2;\n        }\n\n        // pair scores\n        for (int i = 0; i < S; ++i) {\n            pairSc[i][i] = (double)V[i];\n            for (int j = i + 1; j < S; ++j) {\n                long long d2 = 0;\n                int sumMax = 0;\n                for (int l = 0; l < M; ++l) {\n                    int a = X[i][l], b = X[j][l];\n                    int d = a - b;\n                    d2 += 1LL * d * d;\n                    sumMax += max(a, b);\n                }\n                double mu = 0.5 * (V[i] + V[j]);\n                double sigma = 0.5 * sqrt((double)d2);\n                double gain = (double)sumMax - mu;\n                double sc = mu + prm.cSigma * sigma + prm.cGain * gain;\n                pairSc[i][j] = pairSc[j][i] = sc;\n            }\n        }\n\n        // base order\n        baseOrder.resize(S);\n        iota(baseOrder.begin(), baseOrder.end(), 0);\n        sort(baseOrder.begin(), baseOrder.end(), [&](int a, int b) {\n            if (baseSc[a] != baseSc[b]) return baseSc[a] > baseSc[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n    }\n\n    vector<int> select_seeds(const Params& prm, int mode) {\n        vector<double> pri(S);\n        for (int i = 0; i < S; ++i) pri[i] = baseSc[i];\n\n        // Top-V bonus\n        int tv = min(prm.topV, S);\n        for (int k = 0; k < tv; ++k) {\n            int id = ordV[k];\n            pri[id] += prm.bonusV * (double)(tv - k) / (double)tv;\n        }\n\n        // Small diversification for alternate restarts\n        if (mode > 0) {\n            double amp = 1.8 * mode;\n            for (int i = 0; i < S; ++i) {\n                pri[i] += (rng.next_double() - 0.5) * amp;\n            }\n        }\n\n        vector<int> selected;\n        vector<char> inSel(S, 0);\n\n        auto add_seed = [&](int id) {\n            if (!inSel[id]) {\n                inSel[id] = 1;\n                selected.push_back(id);\n            }\n        };\n\n        // Preserve initial maxima in early turns\n        if (prm.preserveInitial) {\n            for (int l = 0; l < M; ++l) {\n                int best = -1;\n                double bs = -1e100;\n                for (int i = 0; i < S; ++i) {\n                    if (X[i][l] == initMax[l]) {\n                        double s = pri[i] + 0.05 * V[i];\n                        if (s > bs) {\n                            bs = s;\n                            best = i;\n                        }\n                    }\n                }\n                if (best != -1) add_seed(best);\n            }\n        }\n\n        // Very early: also preserve current maxima\n        if (prm.progress < 0.25) {\n            for (int l = 0; l < M; ++l) {\n                int best = -1;\n                double bs = -1e100;\n                for (int i = 0; i < S; ++i) {\n                    if (X[i][l] == curMax[l]) {\n                        if (pri[i] > bs) {\n                            bs = pri[i];\n                            best = i;\n                        }\n                    }\n                }\n                if (best != -1) add_seed(best);\n            }\n        }\n\n        // If too many by mandatory, keep strongest\n        if ((int)selected.size() > P) {\n            sort(selected.begin(), selected.end(), [&](int a, int b) {\n                if (pri[a] != pri[b]) return pri[a] > pri[b];\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            selected.resize(P);\n            fill(inSel.begin(), inSel.end(), 0);\n            for (int id : selected) inSel[id] = 1;\n        }\n\n        // Fill by priority\n        vector<int> ord(S);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (pri[a] != pri[b]) return pri[a] > pri[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        for (int id : ord) {\n            if ((int)selected.size() >= P) break;\n            if (!inSel[id]) add_seed(id);\n        }\n\n        return selected;\n    }\n\n    vector<int> construct_layout(const vector<int>& selected, const Params& prm, int mode) {\n        vector<int> rem = selected;\n        // good seeds first\n        sort(rem.begin(), rem.end(), [&](int a, int b) {\n            if (baseSc[a] != baseSc[b]) return baseSc[a] > baseSc[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<int> order = posOrder;\n        if (mode > 0) {\n            // randomize within same degree tendency\n            for (int i = P - 1; i > 0; --i) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n            stable_sort(order.begin(), order.end(), [&](int a, int b) {\n                return (int)nbr[a].size() > (int)nbr[b].size();\n            });\n        }\n\n        vector<int> a(P, -1);\n        double neighCoef = 1.25 + 0.25 * prm.progress;\n\n        for (int t = 0; t < P; ++t) {\n            int pos = order[t];\n            int bestIdx = -1;\n            double bestSc = -1e100;\n\n            for (int idx = 0; idx < (int)rem.size(); ++idx) {\n                int s = rem[idx];\n                double sc = baseSc[s];\n\n                double nb = 0.0;\n                for (int q : nbr[pos]) {\n                    int sq = a[q];\n                    if (sq != -1) nb += pairSc[s][sq];\n                }\n                sc += neighCoef * nb;\n\n                if (mode > 0) sc += (rng.next_double() - 0.5) * 0.8;\n\n                if (sc > bestSc) {\n                    bestSc = sc;\n                    bestIdx = idx;\n                }\n            }\n\n            int pick = rem[bestIdx];\n            a[pos] = pick;\n            rem[bestIdx] = rem.back();\n            rem.pop_back();\n        }\n\n        return a;\n    }\n\n    double evaluate_layout(const vector<int>& a, const Params& prm) const {\n        double sumE = 0.0;\n        double b1 = -1e100, b2 = -1e100, b3 = -1e100, b4 = -1e100;\n\n        for (const auto& e : edges) {\n            double s = pairSc[a[e.first]][a[e.second]];\n            sumE += s;\n\n            if (s > b1) {\n                b4 = b3; b3 = b2; b2 = b1; b1 = s;\n            } else if (s > b2) {\n                b4 = b3; b3 = b2; b2 = s;\n            } else if (s > b3) {\n                b4 = b3; b3 = s;\n            } else if (s > b4) {\n                b4 = s;\n            }\n        }\n\n        double cov1 = 0.0, cov2 = 0.0, cov3 = 0.0;\n        for (int l = 0; l < M; ++l) {\n            int m1 = -1, m2 = -1, m3 = -1;\n            for (int p = 0; p < P; ++p) {\n                int v = X[a[p]][l];\n                if (v > m1) {\n                    m3 = m2; m2 = m1; m1 = v;\n                } else if (v > m2) {\n                    m3 = m2; m2 = v;\n                } else if (v > m3) {\n                    m3 = v;\n                }\n            }\n            if (m2 < 0) m2 = 0;\n            if (m3 < 0) m3 = 0;\n            cov1 += m1;\n            cov2 += m2;\n            cov3 += m3;\n        }\n\n        return prm.wSum * sumE\n             + prm.wBest1 * b1\n             + prm.wBest24 * (b2 + b3 + b4)\n             + prm.beta1 * cov1\n             + prm.beta2 * cov2\n             + prm.beta3 * cov3;\n    }\n\n    int pick_unused_good_seed(const vector<int>& seedPos) {\n        int k1 = min(S, 24);\n        int k2 = min(S, 42);\n\n        for (int t = 0; t < 22; ++t) {\n            int id = baseOrder[rng.next_int(k1)];\n            if (seedPos[id] == -1) return id;\n        }\n        for (int t = 0; t < 22; ++t) {\n            int id = baseOrder[rng.next_int(k2)];\n            if (seedPos[id] == -1) return id;\n        }\n        for (int t = 0; t < 80; ++t) {\n            int id = rng.next_int(S);\n            if (seedPos[id] == -1) return id;\n        }\n        return rng.next_int(S); // fallback (possibly used)\n    }\n\n    pair<vector<int>, double> sa_optimize(const vector<int>& init, const Params& prm, int iters) {\n        vector<int> a = init;\n        vector<int> bestA = a;\n\n        vector<int> seedPos(S, -1);\n        for (int p = 0; p < P; ++p) seedPos[a[p]] = p;\n\n        double cur = evaluate_layout(a, prm);\n        double best = cur;\n\n        for (int it = 0; it < iters; ++it) {\n            double temp = prm.temp0 + (prm.temp1 - prm.temp0) * (double)it / (double)iters;\n\n            bool moved = false;\n            double nxt = cur;\n\n            if (rng.next_double() < prm.swapProb) {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                seedPos[sp] = q;\n                seedPos[sq] = p;\n\n                nxt = evaluate_layout(a, prm);\n                moved = true;\n\n                double d = nxt - cur;\n                bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestA = a;\n                    }\n                } else {\n                    swap(a[p], a[q]);\n                    seedPos[sp] = p;\n                    seedPos[sq] = q;\n                }\n            } else {\n                int p = rng.next_int(P);\n                int s = pick_unused_good_seed(seedPos);\n                int q = seedPos[s];\n                if (q == p) continue;\n\n                int old = a[p];\n                if (q == -1) {\n                    a[p] = s;\n                    seedPos[s] = p;\n                    seedPos[old] = -1;\n\n                    nxt = evaluate_layout(a, prm);\n                    moved = true;\n\n                    double d = nxt - cur;\n                    bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n                    if (ok) {\n                        cur = nxt;\n                        if (cur > best) {\n                            best = cur;\n                            bestA = a;\n                        }\n                    } else {\n                        a[p] = old;\n                        seedPos[old] = p;\n                        seedPos[s] = -1;\n                    }\n                } else {\n                    // swap with existing seed\n                    swap(a[p], a[q]); // s moves to p\n                    seedPos[s] = p;\n                    seedPos[old] = q;\n\n                    nxt = evaluate_layout(a, prm);\n                    moved = true;\n\n                    double d = nxt - cur;\n                    bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n                    if (ok) {\n                        cur = nxt;\n                        if (cur > best) {\n                            best = cur;\n                            bestA = a;\n                        }\n                    } else {\n                        swap(a[p], a[q]);\n                        seedPos[s] = q;\n                        seedPos[old] = p;\n                    }\n                }\n            }\n\n            (void)moved;\n        }\n\n        return {bestA, best};\n    }\n\n    double greedy_polish(vector<int>& a, const Params& prm) {\n        vector<int> seedPos(S, -1);\n        for (int p = 0; p < P; ++p) seedPos[a[p]] = p;\n\n        double cur = evaluate_layout(a, prm);\n\n        vector<int> plist(P);\n        iota(plist.begin(), plist.end(), 0);\n        for (int i = P - 1; i > 0; --i) {\n            int j = rng.next_int(i + 1);\n            swap(plist[i], plist[j]);\n        }\n\n        for (int p : plist) {\n            int old = a[p];\n\n            double bestSc = cur;\n            int bestS = -1;\n            int bestQ = -2; // -1 replacement, >=0 swap target pos\n\n            for (int s = 0; s < S; ++s) {\n                int q = seedPos[s];\n                if (q == p) continue;\n\n                double candSc;\n                if (q == -1) {\n                    a[p] = s;\n                    seedPos[s] = p;\n                    seedPos[old] = -1;\n\n                    candSc = evaluate_layout(a, prm);\n\n                    a[p] = old;\n                    seedPos[old] = p;\n                    seedPos[s] = -1;\n                } else {\n                    swap(a[p], a[q]); // s -> p\n                    seedPos[s] = p;\n                    seedPos[old] = q;\n\n                    candSc = evaluate_layout(a, prm);\n\n                    swap(a[p], a[q]);\n                    seedPos[s] = q;\n                    seedPos[old] = p;\n                }\n\n                if (candSc > bestSc + 1e-9) {\n                    bestSc = candSc;\n                    bestS = s;\n                    bestQ = q;\n                }\n            }\n\n            if (bestS != -1) {\n                if (bestQ == -1) {\n                    int out = a[p];\n                    a[p] = bestS;\n                    seedPos[bestS] = p;\n                    seedPos[out] = -1;\n                } else {\n                    int q = bestQ;\n                    int out = a[p];\n                    swap(a[p], a[q]);\n                    seedPos[bestS] = p;\n                    seedPos[out] = q;\n                }\n                cur = bestSc;\n            }\n        }\n\n        return cur;\n    }\n\n    void perturb_layout(vector<int>& a, int steps) {\n        vector<int> pos(S, -1);\n        for (int p = 0; p < P; ++p) pos[a[p]] = p;\n\n        for (int st = 0; st < steps; ++st) {\n            if (rng.next_double() < 0.55) {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                pos[sp] = q;\n                pos[sq] = p;\n            } else {\n                int p = rng.next_int(P);\n                int s = -1;\n                for (int t = 0; t < 40; ++t) {\n                    int c = rng.next_int(S);\n                    if (pos[c] == -1) {\n                        s = c;\n                        break;\n                    }\n                }\n                if (s == -1) continue;\n                int old = a[p];\n                a[p] = s;\n                pos[s] = p;\n                pos[old] = -1;\n            }\n        }\n    }\n\n    double mc_eval_layout(const vector<int>& a, const vector<uint16_t>& masks, int samples) const {\n        const int E = (int)edges.size();\n        double acc = 0.0;\n\n        for (int t = 0; t < samples; ++t) {\n            int best = 0;\n            int base = t * E;\n\n            for (int e = 0; e < E; ++e) {\n                int p = edges[e].first;\n                int q = edges[e].second;\n                int s1 = a[p], s2 = a[q];\n                uint16_t mask = masks[base + e];\n\n                int v = 0;\n                for (int l = 0; l < M; ++l) {\n                    if ((mask >> l) & 1) v += X[s1][l];\n                    else v += X[s2][l];\n                }\n                if (v > best) best = v;\n            }\n            acc += (double)best;\n        }\n\n        return acc / (double)samples;\n    }\n\n    vector<int> choose_by_mc(const vector<vector<int>>& cands) {\n        vector<vector<int>> uniq;\n        uniq.reserve(cands.size());\n\n        for (const auto& c : cands) {\n            bool dup = false;\n            for (const auto& u : uniq) {\n                if (u == c) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) uniq.push_back(c);\n        }\n\n        if (uniq.empty()) return cands[0];\n        if (uniq.size() == 1) return uniq[0];\n\n        int C = (int)uniq.size();\n        int E = (int)edges.size();\n        uint16_t allMask = (uint16_t)((1u << M) - 1u);\n\n        auto gen_masks = [&](int samples) {\n            vector<uint16_t> m(samples * E);\n            for (int i = 0; i < samples * E; ++i) {\n                m[i] = (uint16_t)(rng.next_u64() & allMask);\n            }\n            return m;\n        };\n\n        const int s1 = 96;\n        const int s2 = 320;\n\n        vector<uint16_t> masks1 = gen_masks(s1);\n        vector<double> est(C, 0.0);\n\n        for (int i = 0; i < C; ++i) {\n            est[i] = mc_eval_layout(uniq[i], masks1, s1);\n        }\n\n        vector<int> ids(C);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return est[a] > est[b];\n        });\n\n        int L = min(3, C);\n        vector<uint16_t> masks2 = gen_masks(s2);\n        for (int t = 0; t < L; ++t) {\n            int i = ids[t];\n            double e2 = mc_eval_layout(uniq[i], masks2, s2);\n            est[i] = (est[i] * s1 + e2 * s2) / (double)(s1 + s2);\n        }\n\n        int best = 0;\n        for (int i = 1; i < C; ++i) {\n            if (est[i] > est[best]) best = i;\n        }\n        return uniq[best];\n    }\n\n    vector<int> decide_layout(int turn) {\n        Params prm = make_params(turn);\n        compute_turn_tables(prm);\n\n        vector<vector<int>> allCands;\n        vector<double> allScores;\n\n        vector<int> bestLayout;\n        double bestScore = -1e100;\n\n        for (int r = 0; r < prm.restarts; ++r) {\n            vector<int> selected = select_seeds(prm, r);\n            vector<int> init = construct_layout(selected, prm, r);\n\n            int iters = prm.iters + 400 * r;\n            auto [lay, sc] = sa_optimize(init, prm, iters);\n\n            allCands.push_back(lay);\n            allScores.push_back(sc);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestLayout = lay;\n            }\n        }\n\n        bestScore = greedy_polish(bestLayout, prm);\n        allCands.push_back(bestLayout);\n        allScores.push_back(bestScore);\n\n        if (turn == T - 1) {\n            // final turn: add a few nearby candidates, then MC rerank\n            for (int z = 0; z < 3; ++z) {\n                vector<int> v = bestLayout;\n                perturb_layout(v, 4 + 2 * z);\n                auto [lay, sc] = sa_optimize(v, prm, 1100 + 400 * z);\n                (void)sc;\n                allCands.push_back(lay);\n            }\n            return choose_by_mc(allCands);\n        }\n\n        if (turn == T - 2) {\n            // mild diversification one turn before final\n            vector<int> v = bestLayout;\n            perturb_layout(v, 4);\n            auto [lay, sc] = sa_optimize(v, prm, 1300);\n            if (sc > bestScore) bestLayout = lay;\n        }\n\n        return bestLayout;\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MAXC = 900; // 30*30\n    static constexpr int MAXK = 14;  // V-1, V<=15\n\n    // 0:R, 1:D, 2:L, 3:U\n    const int DX[4] = {0, 1, 0, -1};\n    const int DY[4] = {1, 0, -1, 0};\n\n    int N, M, V;\n    int C, K, Vp;\n\n    vector<string> S, T;\n\n    // Arm state\n    vector<int> len;       // leaf lengths, leaf id = vertex id - 1\n    vector<int> curDir;    // current direction of each leaf edge\n    vector<char> hold;     // whether each leaf holds takoyaki\n    int heldNow = 0;\n\n    // Remaining tasks\n    vector<uint8_t> src;   // s=1,t=0 and not yet picked\n    vector<uint8_t> dst;   // s=0,t=1 and not yet filled\n    int remSrc = 0, remDst = 0;\n\n    // For centroid-like tie-break\n    long long sumSrcX = 0, sumSrcY = 0;\n    long long sumDstX = 0, sumDstY = 0;\n\n    // Root position\n    int curX = 0, curY = 0;\n    int initX = 0, initY = 0;\n\n    // Precompute\n    int rotD[4][4];\n    vector<int> rx, ry;    // cell id -> x,y\n    vector<int> reach;     // ((rid*K + leaf)<<2)+dir -> cell id or -1\n\n    // Output operations\n    vector<string> ops;\n\n    // Matching work buffers (stamp based)\n    int owner[MAXC], ownerDir[MAXC], ownerStamp[MAXC];\n    int vis[MAXC], cellMark[MAXC];\n    int stampOwner = 1, stampVis = 1, stampCell = 1;\n\n    Solver() {\n        memset(ownerStamp, 0, sizeof(ownerStamp));\n        memset(vis, 0, sizeof(vis));\n        memset(cellMark, 0, sizeof(cellMark));\n    }\n\n    struct MR {\n        int cnt = 0;\n        int rmax = 0;\n    };\n\n    struct Cand {\n        bool ok = false;\n        int rid = -1;\n        int lp = 0; // rot limit for pick group\n        int ld = 0; // rot limit for drop group\n        int cnt = 0;\n        int pick = 0;\n        int drop = 0;\n        int turns = 1;\n        int dist = 0;\n        int pen = 0;\n    };\n\n    void input() {\n        cin >> N >> M >> V;\n        S.resize(N);\n        T.resize(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        C = N * N;\n        K = V - 1;\n        Vp = K + 1;\n\n        src.assign(C, 0);\n        dst.assign(C, 0);\n        remSrc = remDst = 0;\n        sumSrcX = sumSrcY = sumDstX = sumDstY = 0;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                int c = x * N + y;\n                int sv = (S[x][y] == '1');\n                int tv = (T[x][y] == '1');\n                if (sv && !tv) {\n                    src[c] = 1;\n                    remSrc++;\n                    sumSrcX += x;\n                    sumSrcY += y;\n                } else if (!sv && tv) {\n                    dst[c] = 1;\n                    remDst++;\n                    sumDstX += x;\n                    sumDstY += y;\n                }\n            }\n        }\n    }\n\n    void buildRot() {\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                int d = (b - a + 4) % 4;\n                rotD[a][b] = min(d, 4 - d);\n            }\n        }\n    }\n\n    void buildArm() {\n        int maxLen = max(1, (N - 1) / 2); // each leaf can reach every cell from some root\n\n        len.assign(K, 1);\n        if (K <= maxLen) {\n            if (K == 1) {\n                len[0] = maxLen;\n            } else {\n                for (int i = 0; i < K; i++) {\n                    len[i] = 1 + (long long)i * (maxLen - 1) / (K - 1);\n                }\n            }\n        } else {\n            for (int i = 0; i < maxLen; i++) len[i] = i + 1;\n            for (int i = maxLen; i < K; i++) len[i] = 1 + ((i - maxLen) % maxLen);\n        }\n\n        curDir.assign(K, 0); // initially all to the right\n        hold.assign(K, 0);\n        heldNow = 0;\n    }\n\n    void precomputeReach() {\n        rx.resize(C);\n        ry.resize(C);\n        for (int c = 0; c < C; c++) {\n            rx[c] = c / N;\n            ry[c] = c % N;\n        }\n\n        reach.assign(C * K * 4, -1);\n        for (int rid = 0; rid < C; rid++) {\n            int x = rx[rid], y = ry[rid];\n            for (int leaf = 0; leaf < K; leaf++) {\n                int L = len[leaf];\n                int base = ((rid * K + leaf) << 2);\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + DX[d] * L;\n                    int ny = y + DY[d] * L;\n                    if (0 <= nx && nx < N && 0 <= ny && ny < N) {\n                        reach[base + d] = nx * N + ny;\n                    } else {\n                        reach[base + d] = -1;\n                    }\n                }\n            }\n        }\n    }\n\n    // Maximum bipartite matching for one group of leaves to target cells, with rotLimit.\n    // If outDir/outCell given, writes assignments by leaf-id (global leaf index).\n    MR matchGroup(\n        int rid,\n        const int* leaves, int nLeaves,\n        const vector<uint8_t>& target,\n        int rotLimit,\n        int* outDir = nullptr,\n        int* outCell = nullptr\n    ) {\n        MR res;\n        if (nLeaves <= 0) return res;\n\n        int deg[MAXK];\n        int eCell[MAXK][4];\n        int eDir[MAXK][4];\n        uint8_t eRot[MAXK][4];\n\n        int candCells[4 * MAXK];\n        int candCnt = 0;\n        int cstamp = ++stampCell;\n\n        bool any = false;\n\n        for (int u = 0; u < nLeaves; u++) {\n            int leaf = leaves[u];\n            int base = ((rid * K + leaf) << 2);\n            int dcnt = 0;\n\n            for (int d = 0; d < 4; d++) {\n                int c = reach[base + d];\n                if (c < 0 || !target[c]) continue;\n\n                int rr = rotD[curDir[leaf]][d];\n                if (rr > rotLimit) continue;\n\n                eCell[u][dcnt] = c;\n                eDir[u][dcnt] = d;\n                eRot[u][dcnt] = (uint8_t)rr;\n                dcnt++;\n\n                if (cellMark[c] != cstamp) {\n                    cellMark[c] = cstamp;\n                    candCells[candCnt++] = c;\n                }\n            }\n\n            // Prefer smaller rotation first\n            for (int i = 0; i < dcnt; i++) {\n                for (int j = i + 1; j < dcnt; j++) {\n                    if (eRot[u][j] < eRot[u][i]) {\n                        swap(eRot[u][i], eRot[u][j]);\n                        swap(eCell[u][i], eCell[u][j]);\n                        swap(eDir[u][i], eDir[u][j]);\n                    }\n                }\n            }\n\n            deg[u] = dcnt;\n            if (dcnt > 0) any = true;\n        }\n\n        if (!any) return res;\n\n        int ord[MAXK];\n        for (int i = 0; i < nLeaves; i++) ord[i] = i;\n        for (int i = 0; i < nLeaves; i++) {\n            int best = i;\n            for (int j = i + 1; j < nLeaves; j++) {\n                if (deg[ord[j]] < deg[ord[best]]) best = j;\n            }\n            if (best != i) swap(ord[i], ord[best]);\n        }\n\n        int myStamp = ++stampOwner;\n\n        auto dfs = [&](auto&& self, int u, int tag) -> bool {\n            for (int ei = 0; ei < deg[u]; ei++) {\n                int c = eCell[u][ei];\n                if (vis[c] == tag) continue;\n                vis[c] = tag;\n\n                if (ownerStamp[c] != myStamp || self(self, owner[c], tag)) {\n                    ownerStamp[c] = myStamp;\n                    owner[c] = u;\n                    ownerDir[c] = eDir[u][ei];\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        int cnt = 0;\n        for (int i = 0; i < nLeaves; i++) {\n            int u = ord[i];\n            int tag = ++stampVis;\n            if (dfs(dfs, u, tag)) cnt++;\n        }\n\n        res.cnt = cnt;\n        if (cnt == 0) return res;\n\n        int rmax = 0;\n        for (int i = 0; i < candCnt; i++) {\n            int c = candCells[i];\n            if (ownerStamp[c] != myStamp) continue;\n            int u = owner[c];\n            int leaf = leaves[u];\n            int d = ownerDir[c];\n\n            int rr = rotD[curDir[leaf]][d];\n            rmax = max(rmax, rr);\n\n            if (outDir) {\n                outDir[leaf] = d;\n                outCell[leaf] = c;\n            }\n        }\n\n        res.rmax = rmax;\n        return res;\n    }\n\n    bool betterCand(const Cand& a, const Cand& b) {\n        if (!a.ok) return false;\n        if (!b.ok) return true;\n\n        long long lhs = 1LL * a.cnt * b.turns;\n        long long rhs = 1LL * b.cnt * a.turns;\n        if (lhs != rhs) return lhs > rhs; // maximize actions/turn\n\n        if (a.cnt != b.cnt) return a.cnt > b.cnt;\n        if (a.turns != b.turns) return a.turns < b.turns;\n        if (a.pen != b.pen) return a.pen < b.pen;\n        if (a.drop != b.drop) return a.drop > b.drop;\n        if (a.dist != b.dist) return a.dist < b.dist;\n\n        int ra = max(a.lp, a.ld);\n        int rb = max(b.lp, b.ld);\n        return ra < rb;\n    }\n\n    int holdPenaltyAt(\n        int rid, int held2,\n        int scx, int scy,\n        int dcx, int dcy\n    ) {\n        int target = 0;\n\n        if (remDst == 0) {\n            target = 0;\n        } else if (remSrc == 0) {\n            target = 0;\n        } else {\n            int ds = abs(rx[rid] - scx) + abs(ry[rid] - scy);\n            int dd = abs(rx[rid] - dcx) + abs(ry[rid] - dcy);\n            int denom = ds + dd;\n            if (denom == 0) target = K / 2;\n            else target = (K * dd + denom / 2) / denom; // near src -> larger target\n        }\n\n        target = max(0, min(K, target));\n        return abs(held2 - target);\n    }\n\n    void chooseInitialRoot() {\n        if (remSrc == 0) {\n            initX = N / 2;\n            initY = N / 2;\n            curX = initX;\n            curY = initY;\n            return;\n        }\n\n        int allLeaves[MAXK];\n        for (int i = 0; i < K; i++) allLeaves[i] = i;\n\n        int scx = (int)(sumSrcX / remSrc);\n        int scy = (int)(sumSrcY / remSrc);\n\n        Cand best;\n\n        for (int rid = 0; rid < C; rid++) {\n            MR p[3];\n            for (int l = 0; l <= 2; l++) {\n                p[l] = matchGroup(rid, allLeaves, K, src, l);\n            }\n\n            for (int lp = 0; lp <= 2; lp++) {\n                if (p[lp].cnt == 0) continue;\n                int turns = max(0, p[lp].rmax);\n                if (turns == 0) turns = 1;\n\n                Cand c;\n                c.ok = true;\n                c.rid = rid;\n                c.lp = lp;\n                c.ld = 0;\n                c.pick = p[lp].cnt;\n                c.drop = 0;\n                c.cnt = c.pick;\n                c.turns = turns;\n                c.dist = abs(rx[rid] - scx) + abs(ry[rid] - scy);\n                c.pen = 0;\n\n                if (betterCand(c, best)) best = c;\n            }\n        }\n\n        if (!best.ok) {\n            initX = N / 2;\n            initY = N / 2;\n        } else {\n            initX = rx[best.rid];\n            initY = ry[best.rid];\n        }\n        curX = initX;\n        curY = initY;\n    }\n\n    void executeMove(int rid, const vector<int>& assignDir, const vector<int>& assignCell) {\n        int bx = rx[rid], by = ry[rid];\n\n        int actLeaf[MAXK];\n        int actCnt = 0;\n        for (int i = 0; i < K; i++) {\n            if (assignDir[i] >= 0) actLeaf[actCnt++] = i;\n        }\n        if (actCnt == 0) return;\n\n        int rotRem[MAXK] = {};\n        int rotSign[MAXK] = {}; // +1: R, -1: L\n        int R = 0;\n\n        for (int z = 0; z < actCnt; z++) {\n            int leaf = actLeaf[z];\n            int td = assignDir[leaf];\n            int diff = (td - curDir[leaf] + 4) % 4;\n            if (diff == 0) {\n                rotRem[leaf] = 0;\n            } else if (diff == 1) {\n                rotRem[leaf] = 1;\n                rotSign[leaf] = +1;\n            } else if (diff == 3) {\n                rotRem[leaf] = 1;\n                rotSign[leaf] = -1;\n            } else { // diff == 2\n                rotRem[leaf] = 2;\n                rotSign[leaf] = +1;\n            }\n            R = max(R, rotRem[leaf]);\n        }\n\n        int D = abs(bx - curX) + abs(by - curY);\n        int turns = max(D, R);\n        if (turns == 0) turns = 1;\n\n        int remain = 100000 - (int)ops.size();\n        if (remain <= 0) return;\n        bool doAction = true;\n        if (turns > remain) {\n            turns = remain;\n            doAction = false;\n        }\n\n        int vx = bx - curX;\n        int vy = by - curY;\n\n        for (int t = 0; t < turns; t++) {\n            string line(2 * Vp, '.');\n\n            char mv = '.';\n            if (vx < 0) {\n                mv = 'U';\n                vx++;\n                curX--;\n            } else if (vx > 0) {\n                mv = 'D';\n                vx--;\n                curX++;\n            } else if (vy < 0) {\n                mv = 'L';\n                vy++;\n                curY--;\n            } else if (vy > 0) {\n                mv = 'R';\n                vy--;\n                curY++;\n            }\n            line[0] = mv;\n\n            for (int i = 0; i < K; i++) {\n                if (rotRem[i] > 0) {\n                    if (rotSign[i] >= 0) {\n                        line[1 + i] = 'R';\n                        curDir[i] = (curDir[i] + 1) & 3;\n                    } else {\n                        line[1 + i] = 'L';\n                        curDir[i] = (curDir[i] + 3) & 3;\n                    }\n                    rotRem[i]--;\n                }\n            }\n\n            if (doAction && t == turns - 1) {\n                for (int z = 0; z < actCnt; z++) {\n                    int leaf = actLeaf[z];\n                    line[Vp + (leaf + 1)] = 'P';\n                }\n            }\n\n            ops.push_back(move(line));\n        }\n\n        if (!doAction) return;\n\n        // Apply state updates after action turn\n        for (int z = 0; z < actCnt; z++) {\n            int leaf = actLeaf[z];\n            int c = assignCell[leaf];\n            if (c < 0) continue;\n\n            int x = c / N, y = c % N;\n\n            if (!hold[leaf]) {\n                // pick\n                if (src[c]) {\n                    src[c] = 0;\n                    remSrc--;\n                    sumSrcX -= x;\n                    sumSrcY -= y;\n\n                    hold[leaf] = 1;\n                    heldNow++;\n                }\n            } else {\n                // drop\n                if (dst[c]) {\n                    dst[c] = 0;\n                    remDst--;\n                    sumDstX -= x;\n                    sumDstY -= y;\n\n                    hold[leaf] = 0;\n                    heldNow--;\n                }\n            }\n        }\n    }\n\n    bool emergencySingleAction() {\n        // Try single drop first\n        if (heldNow > 0 && remDst > 0) {\n            int bestTurns = (int)1e9, bestDist = (int)1e9;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf = 0; leaf < K; leaf++) if (hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (dst[c]) {\n                    int tx = c / N, ty = c % N;\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int dist = abs(rr - curX) + abs(cc - curY);\n                        int rot = rotD[curDir[leaf]][d];\n                        int turns = max(dist, rot);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && dist < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = dist;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf >= 0) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        // Then single pick\n        if (remSrc > 0) {\n            int bestTurns = (int)1e9, bestDist = (int)1e9;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf = 0; leaf < K; leaf++) if (!hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (src[c]) {\n                    int tx = c / N, ty = c % N;\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int dist = abs(rr - curX) + abs(cc - curY);\n                        int rot = rotD[curDir[leaf]][d];\n                        int turns = max(dist, rot);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && dist < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = dist;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf >= 0) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void plan() {\n        ops.reserve(50000);\n        int safety = 0;\n\n        while ((remDst > 0 || heldNow > 0) && (int)ops.size() < 100000 && safety < 200000) {\n            safety++;\n\n            int emptyLeaves[MAXK], holdLeaves[MAXK];\n            int nE = 0, nH = 0;\n            for (int i = 0; i < K; i++) {\n                if (hold[i]) holdLeaves[nH++] = i;\n                else emptyLeaves[nE++] = i;\n            }\n\n            bool hasP = (remSrc > 0 && nE > 0);\n            bool hasD = (remDst > 0 && nH > 0);\n\n            if (!hasP && !hasD) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            int scx = remSrc ? (int)(sumSrcX / remSrc) : curX;\n            int scy = remSrc ? (int)(sumSrcY / remSrc) : curY;\n            int dcx = remDst ? (int)(sumDstX / remDst) : curX;\n            int dcy = remDst ? (int)(sumDstY / remDst) : curY;\n\n            Cand best;\n\n            for (int rid = 0; rid < C; rid++) {\n                int dist = abs(rx[rid] - curX) + abs(ry[rid] - curY);\n\n                if (dist <= 1) {\n                    MR p[3], d[3];\n                    for (int l = 0; l <= 2; l++) {\n                        p[l] = hasP ? matchGroup(rid, emptyLeaves, nE, src, l) : MR{};\n                        d[l] = hasD ? matchGroup(rid, holdLeaves, nH, dst, l) : MR{};\n                    }\n\n                    int lpMax = hasP ? 2 : 0;\n                    int ldMax = hasD ? 2 : 0;\n\n                    for (int lp = 0; lp <= lpMax; lp++) {\n                        for (int ld = 0; ld <= ldMax; ld++) {\n                            int pick = p[lp].cnt;\n                            int drop = d[ld].cnt;\n                            int cnt = pick + drop;\n                            if (cnt == 0) continue;\n\n                            int R = max(p[lp].rmax, d[ld].rmax);\n                            int turns = max(dist, R);\n                            if (turns == 0) turns = 1;\n\n                            int held2 = heldNow + pick - drop;\n                            int pen = holdPenaltyAt(rid, held2, scx, scy, dcx, dcy);\n\n                            Cand c;\n                            c.ok = true;\n                            c.rid = rid;\n                            c.lp = lp;\n                            c.ld = ld;\n                            c.pick = pick;\n                            c.drop = drop;\n                            c.cnt = cnt;\n                            c.turns = turns;\n                            c.dist = dist;\n                            c.pen = pen;\n\n                            if (betterCand(c, best)) best = c;\n                        }\n                    }\n                } else {\n                    MR pp = hasP ? matchGroup(rid, emptyLeaves, nE, src, 2) : MR{};\n                    MR dd = hasD ? matchGroup(rid, holdLeaves, nH, dst, 2) : MR{};\n\n                    int pick = pp.cnt;\n                    int drop = dd.cnt;\n                    int cnt = pick + drop;\n                    if (cnt == 0) continue;\n\n                    int R = max(pp.rmax, dd.rmax);\n                    int turns = max(dist, R);\n                    if (turns == 0) turns = 1;\n\n                    int held2 = heldNow + pick - drop;\n                    int pen = holdPenaltyAt(rid, held2, scx, scy, dcx, dcy);\n\n                    Cand c;\n                    c.ok = true;\n                    c.rid = rid;\n                    c.lp = hasP ? 2 : 0;\n                    c.ld = hasD ? 2 : 0;\n                    c.pick = pick;\n                    c.drop = drop;\n                    c.cnt = cnt;\n                    c.turns = turns;\n                    c.dist = dist;\n                    c.pen = pen;\n\n                    if (betterCand(c, best)) best = c;\n                }\n            }\n\n            if (!best.ok) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            vector<int> assignDir(K, -1), assignCell(K, -1);\n\n            if (hasP) {\n                matchGroup(best.rid, emptyLeaves, nE, src, best.lp, assignDir.data(), assignCell.data());\n            }\n            if (hasD) {\n                matchGroup(best.rid, holdLeaves, nH, dst, best.ld, assignDir.data(), assignCell.data());\n            }\n\n            int acts = 0;\n            for (int i = 0; i < K; i++) if (assignDir[i] >= 0) acts++;\n            if (acts == 0) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            executeMove(best.rid, assignDir, assignCell);\n        }\n\n        // Final guard\n        while ((remDst > 0 || heldNow > 0) && (int)ops.size() < 100000) {\n            if (!emergencySingleAction()) break;\n        }\n    }\n\n    void output() {\n        cout << Vp << '\\n';\n        for (int i = 0; i < K; i++) {\n            cout << 0 << ' ' << len[i] << '\\n';\n        }\n        cout << initX << ' ' << initY << '\\n';\n        for (const string& s : ops) {\n            cout << s << '\\n';\n        }\n    }\n\n    void run() {\n        input();\n        buildRot();\n        buildArm();\n        precomputeReach();\n        chooseInitialRoot();\n        plan();\n        output();\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}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstruct Point {\n    int x, y;\n};\n\nstruct RectCand {\n    int val;\n    int x1, x2, y1, y2;\n};\n\nstruct Component {\n    vector<int> cells;\n    int score = 0;\n    int perim = 0;\n    int minx = INT_MAX, maxx = -1;\n    int miny = INT_MAX, maxy = -1;\n};\n\nstruct Solver {\n    static constexpr int COORD_MAX = 100000;\n    static constexpr int PERIM_LIMIT = 400000;\n    static constexpr double SOFT_LIMIT = 1.90;\n\n    int N;\n    vector<Point> pts;\n    vector<int> wt; // +1 mackerel, -1 sardine\n\n    // Grid\n    int STEP = 500;\n    int W, H, C, PmaxUnits;\n    vector<int> raw; // cell score\n    vector<int> outsideSides;\n    vector<pair<int, int>> adjPairs;\n    vector<int> prefix; // 2D prefix of raw\n    vector<vector<int>> pointCandCells; // for exact inclusion on cell-union boundary\n\n    // Best answer\n    int bestDiff = -1e9;\n    vector<Point> bestPoly;\n\n    chrono::steady_clock::time_point st;\n\n    inline int id(int x, int y) const { return y * W + x; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void read_input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        pts.resize(2 * N);\n        wt.resize(2 * N);\n        for (int i = 0; i < 2 * N; i++) {\n            cin >> pts[i].x >> pts[i].y;\n            wt[i] = (i < N ? +1 : -1);\n        }\n    }\n\n    void build_grid() {\n        W = COORD_MAX / STEP;\n        H = COORD_MAX / STEP;\n        C = W * H;\n        PmaxUnits = PERIM_LIMIT / STEP;\n\n        raw.assign(C, 0);\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x / STEP;\n            int y = pts[i].y / STEP;\n            if (x >= W) x = W - 1; // handle x=100000\n            if (y >= H) y = H - 1; // handle y=100000\n            raw[id(x, y)] += wt[i];\n        }\n\n        outsideSides.assign(C, 0);\n        adjPairs.clear();\n        adjPairs.reserve(C * 2);\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 out = 0;\n                if (x == 0) out++;\n                if (x == W - 1) out++;\n                if (y == 0) out++;\n                if (y == H - 1) out++;\n                outsideSides[v] = out;\n\n                if (x + 1 < W) adjPairs.push_back({v, id(x + 1, y)});\n                if (y + 1 < H) adjPairs.push_back({v, id(x, y + 1)});\n            }\n        }\n\n        // Prefix sum\n        prefix.assign((W + 1) * (H + 1), 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int cur = raw[id(x, y)];\n                int A = prefix[y * (W + 1) + (x + 1)];\n                int B = prefix[(y + 1) * (W + 1) + x];\n                int D = prefix[y * (W + 1) + x];\n                prefix[(y + 1) * (W + 1) + (x + 1)] = cur + A + B - D;\n            }\n        }\n\n        // Exact inclusion candidates for each point (boundary-inclusive)\n        pointCandCells.assign(2 * N, {});\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x;\n            int y = pts[i].y;\n\n            int qx = x / STEP;\n            int qy = y / STEP;\n\n            vector<int> xs, ys;\n            if (qx == W) xs = {W - 1};\n            else if (x % STEP == 0 && qx > 0) xs = {qx - 1, qx};\n            else xs = {qx};\n\n            if (qy == H) ys = {H - 1};\n            else if (y % STEP == 0 && qy > 0) ys = {qy - 1, qy};\n            else ys = {qy};\n\n            vector<int> cand;\n            cand.reserve(4);\n            for (int xx : xs) for (int yy : ys) {\n                int v = id(xx, yy);\n                bool dup = false;\n                for (int z : cand) if (z == v) { dup = true; break; }\n                if (!dup) cand.push_back(v);\n            }\n            pointCandCells[i] = move(cand);\n        }\n    }\n\n    int rect_sum(int x1, int y1, int x2, int y2) const {\n        if (x1 > x2 || y1 > y2) return 0;\n        x1 = max(x1, 0);\n        y1 = max(y1, 0);\n        x2 = min(x2, W - 1);\n        y2 = min(y2, H - 1);\n        if (x1 > x2 || y1 > y2) return 0;\n\n        int A = prefix[(y2 + 1) * (W + 1) + (x2 + 1)];\n        int B = prefix[y1 * (W + 1) + (x2 + 1)];\n        int Cc = prefix[(y2 + 1) * (W + 1) + x1];\n        int D = prefix[y1 * (W + 1) + x1];\n        return A - B - Cc + D;\n    }\n\n    vector<int> build_profit(int r) const {\n        vector<int> p(C, 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int v = id(x, y);\n                int s = rect_sum(x - r, y - r, x + r, y + r);\n                if (r == 0) p[v] = raw[v] * 20;\n                else p[v] = s * 8 + raw[v] * 4;\n            }\n        }\n        return p;\n    }\n\n    vector<char> segment_cut(const vector<int>& profit, int lambda) const {\n        vector<char> sel(C, 0);\n\n        if (lambda == 0) {\n            for (int i = 0; i < C; i++) sel[i] = (profit[i] > 0);\n            return sel;\n        }\n\n        int S = C, T = C + 1;\n        mf_graph<ll> g(C + 2);\n\n        for (int v = 0; v < C; v++) {\n            ll c1 = -(ll)profit[v] + (ll)lambda * outsideSides[v];\n            if (c1 >= 0) g.add_edge(v, T, c1);\n            else g.add_edge(S, v, -c1);\n        }\n\n        for (auto [u, v] : adjPairs) {\n            g.add_edge(u, v, lambda);\n            g.add_edge(v, u, lambda);\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n        for (int i = 0; i < C; i++) sel[i] = cut[i] ? 1 : 0;\n        return sel;\n    }\n\n    vector<Component> top_components(const vector<char>& sel, int K) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n        vector<Component> comps;\n        comps.reserve(64);\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n\n            Component cp;\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cp.cells.push_back(v);\n                cp.score += raw[v];\n\n                int x = v % W, y = v / W;\n                cp.minx = min(cp.minx, x);\n                cp.maxx = max(cp.maxx, x);\n                cp.miny = min(cp.miny, y);\n                cp.maxy = max(cp.maxy, y);\n\n                if (x == 0 || !sel[v - 1]) cp.perim++;\n                else if (!vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n\n                if (x == W - 1 || !sel[v + 1]) cp.perim++;\n                else if (!vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n\n                if (y == 0 || !sel[v - W]) cp.perim++;\n                else if (!vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n\n                if (y == H - 1 || !sel[v + W]) cp.perim++;\n                else if (!vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (cp.score > 0) comps.push_back(move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [&](const Component& a, const Component& b) {\n            if (a.score != b.score) return a.score > b.score;\n            if (a.perim != b.perim) return a.perim < b.perim;\n            return a.cells.size() > b.cells.size();\n        });\n\n        if ((int)comps.size() > K) comps.resize(K);\n        return comps;\n    }\n\n    int bbox_dist(const Component& a, const Component& b) const {\n        int dx = 0, dy = 0;\n        if (a.maxx < b.minx) dx = b.minx - a.maxx - 1;\n        else if (b.maxx < a.minx) dx = a.minx - b.maxx - 1;\n\n        if (a.maxy < b.miny) dy = b.miny - a.maxy - 1;\n        else if (b.maxy < a.miny) dy = a.miny - b.maxy - 1;\n\n        return dx + dy;\n    }\n\n    bool connect_components(const Component& A, const Component& B, vector<char>& outSel, int& pathLen) const {\n        outSel.assign(C, 0);\n        vector<char> inB(C, 0);\n        vector<int> parent(C, -1);\n        queue<int> q;\n\n        for (int v : A.cells) {\n            outSel[v] = 1;\n            parent[v] = -2;\n            q.push(v);\n        }\n        for (int v : B.cells) {\n            outSel[v] = 1;\n            inB[v] = 1;\n        }\n\n        int target = -1;\n\n        while (!q.empty() && target == -1) {\n            int v = q.front(); q.pop();\n            if (inB[v]) {\n                target = v;\n                break;\n            }\n\n            int x = v % W, y = v / W;\n            auto relax = [&](int to) {\n                if (parent[to] == -1) {\n                    parent[to] = v;\n                    q.push(to);\n                    if (inB[to]) target = to;\n                }\n            };\n\n            if (x > 0 && target == -1) relax(v - 1);\n            if (x + 1 < W && target == -1) relax(v + 1);\n            if (y > 0 && target == -1) relax(v - W);\n            if (y + 1 < H && target == -1) relax(v + W);\n        }\n\n        if (target == -1) return false;\n\n        pathLen = 0;\n        int cur = target;\n        while (parent[cur] != -2) {\n            outSel[cur] = 1;\n            cur = parent[cur];\n            if (cur < 0) return false;\n            pathLen++;\n        }\n        outSel[cur] = 1;\n        return true;\n    }\n\n    vector<RectCand> best_rectangles(int K) const {\n        struct CmpMin {\n            bool operator()(const RectCand& a, const RectCand& b) const { return a.val > b.val; }\n        };\n        priority_queue<RectCand, vector<RectCand>, CmpMin> pq;\n\n        vector<int> acc(H, 0), ps(H + 1, 0);\n\n        for (int x1 = 0; x1 < W; x1++) {\n            fill(acc.begin(), acc.end(), 0);\n\n            for (int x2 = x1; x2 < W; x2++) {\n                for (int y = 0; y < H; y++) acc[y] += raw[id(x2, y)];\n\n                int wcell = x2 - x1 + 1;\n                int L = PmaxUnits / 2 - wcell;\n                if (L < 1) break;\n\n                ps[0] = 0;\n                for (int y = 0; y < H; y++) ps[y + 1] = ps[y] + acc[y];\n\n                deque<int> dq;\n                int best = INT_MIN;\n                int bl = 0, br = 0; // [bl, br)\n\n                for (int j = 1; j <= H; j++) {\n                    int add = j - 1;\n                    while (!dq.empty() && ps[dq.back()] >= ps[add]) dq.pop_back();\n                    dq.push_back(add);\n\n                    int lim = j - L;\n                    while (!dq.empty() && dq.front() < lim) dq.pop_front();\n\n                    if (!dq.empty()) {\n                        int val = ps[j] - ps[dq.front()];\n                        if (val > best) {\n                            best = val;\n                            bl = dq.front();\n                            br = j;\n                        }\n                    }\n                }\n\n                if (best <= 0 || br <= bl) continue;\n                RectCand rc{best, x1, x2, bl, br - 1};\n\n                if ((int)pq.size() < K) pq.push(rc);\n                else if (rc.val > pq.top().val) {\n                    pq.pop();\n                    pq.push(rc);\n                }\n            }\n        }\n\n        vector<RectCand> out;\n        while (!pq.empty()) {\n            out.push_back(pq.top());\n            pq.pop();\n        }\n        sort(out.begin(), out.end(), [](const RectCand& a, const RectCand& b) {\n            return a.val > b.val;\n        });\n        return out;\n    }\n\n    int count_nb(const vector<char>& sel, int v) const {\n        int x = v % W, y = v / W;\n        int c = 0;\n        if (x > 0 && sel[v - 1]) c++;\n        if (x + 1 < W && sel[v + 1]) c++;\n        if (y > 0 && sel[v - W]) c++;\n        if (y + 1 < H && sel[v + W]) c++;\n        return c;\n    }\n\n    pair<int, int> score_perim(const vector<char>& sel) const {\n        int sc = 0, per = 0;\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            sc += raw[v];\n            int x = v % W, y = v / W;\n            if (x == 0 || !sel[v - 1]) per++;\n            if (x == W - 1 || !sel[v + 1]) per++;\n            if (y == 0 || !sel[v - W]) per++;\n            if (y == H - 1 || !sel[v + W]) per++;\n        }\n        return {sc, per};\n    }\n\n    void enforce_single_component(vector<char>& sel) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n\n        int compCnt = 0;\n        int bestSc = INT_MIN;\n        vector<int> bestCells;\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n            compCnt++;\n\n            vector<int> cells;\n            int sc = 0;\n\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cells.push_back(v);\n                sc += raw[v];\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && !vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n                if (x + 1 < W && sel[v + 1] && !vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n                if (y > 0 && sel[v - W] && !vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n                if (y + 1 < H && sel[v + W] && !vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (sc > bestSc) {\n                bestSc = sc;\n                bestCells = move(cells);\n            }\n        }\n\n        if (compCnt <= 1) return;\n        fill(sel.begin(), sel.end(), 0);\n        for (int v : bestCells) sel[v] = 1;\n    }\n\n    void fill_holes(vector<char>& sel) const {\n        int minx = W, miny = H, maxx = -1, maxy = -1;\n        for (int v = 0; v < C; v++) if (sel[v]) {\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        if (maxx < minx) return;\n\n        int bw = maxx - minx + 1;\n        int bh = maxy - miny + 1;\n        int LW = bw + 2;\n        int LH = bh + 2;\n\n        vector<char> blocked(LW * LH, 0), vis(LW * LH, 0);\n\n        for (int y = miny; y <= maxy; y++) {\n            for (int x = minx; x <= maxx; x++) {\n                int gv = id(x, y);\n                if (sel[gv]) {\n                    int lx = (x - minx) + 1;\n                    int ly = (y - miny) + 1;\n                    blocked[ly * LW + lx] = 1;\n                }\n            }\n        }\n\n        queue<int> q;\n        auto push_if = [&](int lx, int ly) {\n            int t = ly * LW + lx;\n            if (!blocked[t] && !vis[t]) {\n                vis[t] = 1;\n                q.push(t);\n            }\n        };\n\n        for (int x = 0; x < LW; x++) {\n            push_if(x, 0);\n            push_if(x, LH - 1);\n        }\n        for (int y = 0; y < LH; y++) {\n            push_if(0, y);\n            push_if(LW - 1, y);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int x = v % LW, y = v / LW;\n            if (x > 0) push_if(x - 1, y);\n            if (x + 1 < LW) push_if(x + 1, y);\n            if (y > 0) push_if(x, y - 1);\n            if (y + 1 < LH) push_if(x, y + 1);\n        }\n\n        for (int ly = 1; ly <= bh; ly++) {\n            for (int lx = 1; lx <= bw; lx++) {\n                int t = ly * LW + lx;\n                if (!blocked[t] && !vis[t]) {\n                    int gx = minx + (lx - 1);\n                    int gy = miny + (ly - 1);\n                    sel[id(gx, gy)] = 1;\n                }\n            }\n        }\n    }\n\n    void refine(vector<char>& sel) const {\n        auto sp = score_perim(sel);\n        int perim = sp.second;\n\n        // 1) remove non-positive leaves\n        queue<int> q;\n        for (int v = 0; v < C; v++) {\n            if (sel[v] && raw[v] <= 0 && count_nb(sel, v) <= 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (!sel[v]) continue;\n            int nb = count_nb(sel, v);\n            if (raw[v] <= 0 && nb <= 1) {\n                sel[v] = 0;\n                perim += (-4 + 2 * nb);\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && raw[v - 1] <= 0 && count_nb(sel, v - 1) <= 1) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1] && raw[v + 1] <= 0 && count_nb(sel, v + 1) <= 1) q.push(v + 1);\n                if (y > 0 && sel[v - W] && raw[v - W] <= 0 && count_nb(sel, v - W) <= 1) q.push(v - W);\n                if (y + 1 < H && sel[v + W] && raw[v + W] <= 0 && count_nb(sel, v + W) <= 1) q.push(v + W);\n            }\n        }\n\n        // 2) if perimeter too large, remove leaves with smallest raw loss\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> leafPQ;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) leafPQ.push({raw[v], v});\n\n        while (perim > PmaxUnits && !leafPQ.empty()) {\n            auto [rw, v] = leafPQ.top(); leafPQ.pop();\n            (void)rw;\n            if (!sel[v]) continue;\n            int nb = count_nb(sel, v);\n            if (nb > 1) continue;\n\n            sel[v] = 0;\n            perim += (-4 + 2 * nb);\n\n            int x = v % W, y = v / W;\n            if (x > 0 && sel[v - 1] && count_nb(sel, v - 1) <= 1) leafPQ.push({raw[v - 1], v - 1});\n            if (x + 1 < W && sel[v + 1] && count_nb(sel, v + 1) <= 1) leafPQ.push({raw[v + 1], v + 1});\n            if (y > 0 && sel[v - W] && count_nb(sel, v - W) <= 1) leafPQ.push({raw[v - W], v - W});\n            if (y + 1 < H && sel[v + W] && count_nb(sel, v + W) <= 1) leafPQ.push({raw[v + W], v + W});\n        }\n\n        // 3) greedily grow frontier positives\n        priority_queue<pair<int, int>> pq; // (raw, idx)\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty()) {\n            auto [rw, v] = pq.top(); pq.pop();\n            (void)rw;\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            bool take = false;\n            if (raw[v] > 0) take = true;\n            else if (raw[v] == 0 && dP < 0) take = true;\n\n            if (take) {\n                sel[v] = 1;\n                perim += dP;\n\n                int x = v % W, y = v / W;\n                if (x > 0) push_frontier(v - 1);\n                if (x + 1 < W) push_frontier(v + 1);\n                if (y > 0) push_frontier(v - W);\n                if (y + 1 < H) push_frontier(v + W);\n            }\n        }\n    }\n\n    void resolve_diagonal_crosses(vector<char>& sel) const {\n        for (int it = 0; it < 2; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < H; y++) {\n                for (int x = 0; x + 1 < W; x++) {\n                    int a = id(x, y);\n                    int b = id(x + 1, y);\n                    int c = id(x, y + 1);\n                    int d = id(x + 1, y + 1);\n\n                    if (sel[a] && sel[d] && !sel[b] && !sel[c]) {\n                        sel[(raw[b] >= raw[c]) ? b : c] = 1;\n                        changed = true;\n                    } else if (!sel[a] && !sel[d] && sel[b] && sel[c]) {\n                        sel[(raw[a] >= raw[d]) ? a : d] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    int exact_diff(const vector<char>& sel) const {\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            bool inside = false;\n            for (int c : pointCandCells[i]) {\n                if (sel[c]) { inside = true; break; }\n            }\n            if (inside) diff += wt[i];\n        }\n        return diff;\n    }\n\n    static ll area2(const vector<Point>& poly) {\n        ll s = 0;\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            s += 1LL * poly[i].x * poly[j].y - 1LL * poly[i].y * poly[j].x;\n        }\n        return s;\n    }\n\n    vector<Point> cells_to_polygon(const vector<char>& sel) const {\n        const int SHIFT = 20;\n        auto key = [&](int x, int y) -> ll { return (ll(x) << SHIFT) | ll(y); };\n        auto decode = [&](ll k) -> Point { return Point{int(k >> SHIFT), int(k & ((1LL << SHIFT) - 1))}; };\n\n        unordered_map<ll, ll> nxt;\n        nxt.reserve(8192);\n\n        for (int v = 0; v < C; v++) {\n            if (!sel[v]) continue;\n            int cx = v % W, cy = v / W;\n            int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n            int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n\n            // CCW around cell\n            if (cy == 0 || !sel[v - W]) nxt[key(x0, y0)] = key(x1, y0);\n            if (cx == W - 1 || !sel[v + 1]) nxt[key(x1, y0)] = key(x1, y1);\n            if (cy == H - 1 || !sel[v + W]) nxt[key(x1, y1)] = key(x0, y1);\n            if (cx == 0 || !sel[v - 1]) nxt[key(x0, y1)] = key(x0, y0);\n        }\n\n        if (nxt.empty()) return {};\n\n        unordered_set<ll> used;\n        used.reserve(nxt.size() * 2 + 1);\n\n        vector<Point> best;\n        ll bestA = -1;\n\n        for (auto &kv : nxt) {\n            ll start = kv.first;\n            if (used.count(start)) continue;\n\n            unordered_set<ll> local;\n            local.reserve(nxt.size() * 2 + 1);\n\n            vector<Point> cyc;\n            ll cur = start;\n            bool ok = true;\n\n            while (true) {\n                if (local.count(cur)) {\n                    if (cur == start) break;\n                    ok = false;\n                    break;\n                }\n                local.insert(cur);\n                used.insert(cur);\n\n                auto it = nxt.find(cur);\n                if (it == nxt.end()) { ok = false; break; }\n\n                cyc.push_back(decode(cur));\n                cur = it->second;\n\n                if ((int)cyc.size() > (int)nxt.size() + 5) {\n                    ok = false;\n                    break;\n                }\n            }\n\n            if (!ok || (int)cyc.size() < 4) continue;\n            ll a = llabs(area2(cyc));\n            if (a > bestA) {\n                bestA = a;\n                best = move(cyc);\n            }\n        }\n\n        if (best.empty()) return {};\n\n        // Remove collinear points\n        bool changed = true;\n        while (changed && best.size() > 4) {\n            changed = false;\n            int m = (int)best.size();\n            vector<Point> np;\n            np.reserve(m);\n\n            for (int i = 0; i < m; i++) {\n                Point a = best[(i - 1 + m) % m];\n                Point b = best[i];\n                Point c = best[(i + 1) % m];\n\n                if ((a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y)) {\n                    changed = true;\n                    continue;\n                }\n                np.push_back(b);\n            }\n            if (np.size() < 4) break;\n            best.swap(np);\n        }\n\n        return best;\n    }\n\n    bool basic_valid(const vector<Point>& poly) const {\n        int m = (int)poly.size();\n        if (m < 4 || m > 1000) return false;\n\n        const int SHIFT = 20;\n        unordered_set<ll> s;\n        s.reserve(m * 2);\n\n        ll per = 0;\n        for (int i = 0; i < m; i++) {\n            int x = poly[i].x, y = poly[i].y;\n            if (x < 0 || x > COORD_MAX || y < 0 || y > COORD_MAX) return false;\n\n            ll k = (ll(x) << SHIFT) | ll(y);\n            if (s.count(k)) return false;\n            s.insert(k);\n\n            int j = (i + 1) % m;\n            int x2 = poly[j].x, y2 = poly[j].y;\n            if (x != x2 && y != y2) return false;\n            ll len = llabs((ll)x - x2) + llabs((ll)y - y2);\n            if (len <= 0) return false;\n            per += len;\n        }\n\n        if (per > PERIM_LIMIT) return false;\n        if (area2(poly) == 0) return false;\n        return true;\n    }\n\n    struct Seg {\n        int x1, y1, x2, y2;\n        bool vert;\n    };\n\n    static bool overlap1d(int a, int b, int c, int d) {\n        if (a > b) swap(a, b);\n        if (c > d) swap(c, d);\n        return max(a, c) <= min(b, d);\n    }\n\n    static bool seg_intersect(const Seg& A, const Seg& B) {\n        if (A.vert && B.vert) {\n            if (A.x1 != B.x1) return false;\n            return overlap1d(A.y1, A.y2, B.y1, B.y2);\n        }\n        if (!A.vert && !B.vert) {\n            if (A.y1 != B.y1) return false;\n            return overlap1d(A.x1, A.x2, B.x1, B.x2);\n        }\n\n        const Seg& V = A.vert ? A : B;\n        const Seg& Hs = A.vert ? B : A;\n\n        int vx = V.x1;\n        int hy = Hs.y1;\n        int hxL = min(Hs.x1, Hs.x2), hxR = max(Hs.x1, Hs.x2);\n        int vyL = min(V.y1, V.y2), vyR = max(V.y1, V.y2);\n\n        return (hxL <= vx && vx <= hxR && vyL <= hy && hy <= vyR);\n    }\n\n    bool final_valid(const vector<Point>& poly) const {\n        if (!basic_valid(poly)) return false;\n        int m = (int)poly.size();\n\n        vector<Seg> edges(m);\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            edges[i] = Seg{poly[i].x, poly[i].y, poly[j].x, poly[j].y, (poly[i].x == poly[j].x)};\n        }\n\n        for (int i = 0; i < m; i++) {\n            for (int j = i + 1; j < m; j++) {\n                if ((i + 1) % m == j) continue;      // adjacent\n                if ((j + 1) % m == i) continue;      // adjacent\n                if (seg_intersect(edges[i], edges[j])) return false;\n            }\n        }\n        return true;\n    }\n\n    void consider_candidate(vector<char> sel) {\n        if (elapsed() > SOFT_LIMIT) return;\n\n        bool any = false;\n        for (char b : sel) if (b) { any = true; break; }\n        if (!any) return;\n\n        enforce_single_component(sel);\n        fill_holes(sel);\n        refine(sel);\n        resolve_diagonal_crosses(sel);\n        fill_holes(sel);\n        enforce_single_component(sel);\n\n        auto [sc, per] = score_perim(sel);\n        (void)sc;\n        if (per <= 0 || per > PmaxUnits) return;\n\n        int diff = exact_diff(sel);\n        if (diff <= bestDiff) return;\n\n        auto poly = cells_to_polygon(sel);\n        if (!final_valid(poly)) return;\n\n        bestDiff = diff;\n        bestPoly = move(poly);\n    }\n\n    int rect_diff(int x0, int x1, int y0, int y1) const {\n        int d = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x0 <= x && x <= x1 && y0 <= y && y <= y1) d += wt[i];\n        }\n        return d;\n    }\n\n    vector<Point> tiny_square_around_first_mackerel() const {\n        int x = pts[0].x, y = pts[0].y;\n        int x0, x1, y0, y1;\n        if (x < COORD_MAX) { x0 = x; x1 = x + 1; }\n        else { x0 = x - 1; x1 = x; }\n\n        if (y < COORD_MAX) { y0 = y; y1 = y + 1; }\n        else { y0 = y - 1; y1 = y; }\n\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    vector<Point> cell_rect_poly(int v) const {\n        int cx = v % W, cy = v / W;\n        int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n        int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n        build_grid();\n\n        // Candidate 0: best single positive cell\n        int bestCell = 0;\n        for (int i = 1; i < C; i++) if (raw[i] > raw[bestCell]) bestCell = i;\n        if (raw[bestCell] > 0) {\n            vector<char> sel(C, 0);\n            sel[bestCell] = 1;\n            consider_candidate(move(sel));\n        }\n\n        // Candidate family: best rectangles under perimeter limit\n        auto rects = best_rectangles(10);\n        for (auto &rc : rects) {\n            if (elapsed() > SOFT_LIMIT * 0.55) break;\n            vector<char> sel(C, 0);\n            for (int y = rc.y1; y <= rc.y2; y++) {\n                for (int x = rc.x1; x <= rc.x2; x++) {\n                    sel[id(x, y)] = 1;\n                }\n            }\n            consider_candidate(move(sel));\n        }\n\n        // Profit maps\n        vector<vector<int>> profits(4);\n        for (int r = 0; r <= 3; r++) profits[r] = build_profit(r);\n\n        // (radius, lambda)\n        vector<pair<int, int>> params = {\n            {2, 0}, {3, 0}, {1, 0},\n            {0, 4}, {1, 8}, {2, 12},\n            {0, 7}, {1, 12}, {2, 16},\n            {0, 10}, {3, 18}\n        };\n\n        for (auto [r, lam] : params) {\n            if (lam > 0 && elapsed() > 1.78) break;\n            if (lam == 0 && elapsed() > 1.86) break;\n\n            auto sel = segment_cut(profits[r], lam);\n            auto comps = top_components(sel, 5);\n\n            int singleTake = min(4, (int)comps.size());\n            for (int i = 0; i < singleTake; i++) {\n                if (elapsed() > SOFT_LIMIT) break;\n                vector<char> compSel(C, 0);\n                for (int v : comps[i].cells) compSel[v] = 1;\n                consider_candidate(move(compSel));\n            }\n\n            int pairTake = min(3, (int)comps.size());\n            for (int i = 0; i < pairTake; i++) {\n                for (int j = i + 1; j < pairTake; j++) {\n                    if (elapsed() > SOFT_LIMIT) break;\n\n                    int d = bbox_dist(comps[i], comps[j]);\n                    if (d > PmaxUnits / 2) continue;\n\n                    int estPer = comps[i].perim + comps[j].perim + 2 * d + 8;\n                    if (estPer > PmaxUnits + 180) continue;\n\n                    vector<char> merged;\n                    int pathLen = 0;\n                    if (!connect_components(comps[i], comps[j], merged, pathLen)) continue;\n                    if (pathLen > PmaxUnits / 2 + 30) continue;\n\n                    consider_candidate(move(merged));\n                }\n            }\n        }\n\n        // Fallback candidates\n        vector<Point> fbTiny = tiny_square_around_first_mackerel();\n        int tinyDiff = rect_diff(fbTiny[0].x, fbTiny[1].x, fbTiny[0].y, fbTiny[2].y);\n\n        int cellBest = 0;\n        for (int i = 1; i < C; i++) if (raw[i] > raw[cellBest]) cellBest = i;\n        vector<Point> fbCell = cell_rect_poly(cellBest);\n        int cellDiff = rect_diff(fbCell[0].x, fbCell[1].x, fbCell[0].y, fbCell[2].y);\n\n        vector<Point> fb = (cellDiff >= tinyDiff ? fbCell : fbTiny);\n        int fbDiff = max(cellDiff, tinyDiff);\n\n        vector<Point> ans = bestPoly;\n        int ansDiff = bestDiff;\n\n        if (ans.empty() || ansDiff < fbDiff || !final_valid(ans)) ans = fb;\n        if (!final_valid(ans)) ans = fbTiny;\n\n        cout << ans.size() << '\\n';\n        for (auto &p : ans) {\n            cout << p.x << ' ' << p.y << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconstexpr int MAXN = 105;\nconstexpr ll DIM_MAX = 1000000000LL;\nconstexpr ll INF64 = (1LL << 60);\n\nstatic inline uint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstruct FastRNG {\n    uint64_t x;\n    bool has_spare = false;\n    double spare = 0.0;\n\n    explicit FastRNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next_u64() {\n        return splitmix64(x += 0x9e3779b97f4a7c15ULL);\n    }\n\n    double uniform01() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n\n    int randint(int l, int r) {\n        return l + int(next_u64() % (uint64_t)(r - l + 1));\n    }\n\n    double normal01() {\n        if (has_spare) {\n            has_spare = false;\n            return spare;\n        }\n        double u, v, s;\n        do {\n            u = uniform01() * 2.0 - 1.0;\n            v = uniform01() * 2.0 - 1.0;\n            s = u * u + v * v;\n        } while (s >= 1.0 || s == 0.0);\n        double m = sqrt(-2.0 * log(s) / s);\n        spare = v * m;\n        has_spare = true;\n        return u * m;\n    }\n};\n\nstruct Operation {\n    uint8_t r = 0; // 0/1\n    uint8_t d = 0; // 0:U, 1:L\n    int b = -1;    // -1 or previous index\n};\n\nstruct GreedyParam {\n    double gap_w = 0.35;\n    double bal_w = 0.006;\n    double noise_w = 0.0;\n};\n\nstruct BeamParam {\n    int beam_width = 32;\n    int keep_leaves = 12;\n    double gap_w = 0.35;\n    double bal_w = 0.006;\n    double noise_w = 0.0;\n};\n\nstruct Scenario {\n    vector<ll> w, h;\n};\n\nstruct Candidate {\n    vector<Operation> ops;\n    vector<ll> predW, predH, predS; // per scenario\n    double avg = 1e100;\n    uint64_t hash = 0;\n};\n\ninline ll clamp_dim(ll v) {\n    if (v < 1) return 1;\n    if (v > DIM_MAX) return DIM_MAX;\n    return v;\n}\n\ninline bool overlap(ll l1, ll r1, ll l2, ll r2) {\n    return (l1 < r2) && (l2 < r1);\n}\n\ninline double lower_bound_wh(ll curW, ll curH, double totalA, double sqrtA) {\n    double w = (double)curW;\n    double h = (double)curH;\n    if (w * h >= totalA) return w + h;\n\n    double c1 = w + max(h, totalA / max(1.0, w));\n    double c2 = h + max(w, totalA / max(1.0, h));\n    double c3 = 1e100;\n    if (w <= sqrtA && h <= sqrtA) c3 = 2.0 * sqrtA;\n    return min(c1, min(c2, c3));\n}\n\npair<ll, ll> simulate_layout(\n    const vector<ll>& baseW, const vector<ll>& baseH, const vector<Operation>& ops\n) {\n    int N = (int)ops.size();\n    ll x[MAXN] = {}, y[MAXN] = {}, w[MAXN] = {}, h[MAXN] = {};\n    ll BW = 0, BH = 0;\n\n    for (int i = 0; i < N; i++) {\n        const auto& op = ops[i];\n        ll wi = op.r ? baseH[i] : baseW[i];\n        ll hi = op.r ? baseW[i] : baseH[i];\n\n        ll xi = 0, yi = 0;\n        if (op.d == 0) { // U\n            xi = (op.b == -1) ? 0 : (x[op.b] + w[op.b]);\n            ll xr = xi + wi;\n            yi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(xi, xr, x[j], x[j] + w[j])) yi = max(yi, y[j] + h[j]);\n            }\n        } else { // L\n            yi = (op.b == -1) ? 0 : (y[op.b] + h[op.b]);\n            ll yb = yi + hi;\n            xi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(yi, yb, y[j], y[j] + h[j])) xi = max(xi, x[j] + w[j]);\n            }\n        }\n\n        x[i] = xi; y[i] = yi; w[i] = wi; h[i] = hi;\n        BW = max(BW, xi + wi);\n        BH = max(BH, yi + hi);\n    }\n\n    return {BW, BH};\n}\n\ninline ll score_on_base(const vector<ll>& baseW, const vector<ll>& baseH, const vector<Operation>& ops) {\n    auto [W, H] = simulate_layout(baseW, baseH, ops);\n    return W + H;\n}\n\nvector<Operation> build_linear_chain(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal, bool minimize_cross\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (minimize_cross) {\n            if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n            else r = (h[i] < w[i]) ? 1 : 0;\n        }\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 0 : 1), (i == 0 ? -1 : i - 1)};\n    }\n    return ops;\n}\n\nvector<Operation> build_single_stack(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n        else r = (h[i] < w[i]) ? 1 : 0;\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 1 : 0), -1};\n    }\n    return ops;\n}\n\nvector<Operation> build_greedy(\n    const vector<ll>& baseW, const vector<ll>& baseH, const GreedyParam& param, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n    vector<Operation> ops(N);\n\n    ll x[MAXN] = {}, y[MAXN] = {}, w[MAXN] = {}, h[MAXN] = {};\n    ll curW = 0, curH = 0;\n    double usedA = 0.0;\n\n    double totalA = 0.0;\n    for (int i = 0; i < N; i++) totalA += (double)baseW[i] * (double)baseH[i];\n    double sqrtA = sqrt(max(1.0, totalA));\n    double norm = sqrtA + 1.0;\n\n    for (int i = 0; i < N; i++) {\n        double bestScore = 1e300;\n        ll bestPerim = INF64;\n\n        Operation bestOp{};\n        ll bestX = 0, bestY = 0, bestWi = 0, bestHi = 0, nextW = 0, nextH = 0;\n\n        for (int rot = 0; rot < 2; rot++) {\n            ll wi = rot ? baseH[i] : baseW[i];\n            ll hi = rot ? baseW[i] : baseH[i];\n\n            for (int dir = 0; dir < 2; dir++) {\n                for (int b = -1; b < i; b++) {\n                    ll xi = 0, yi = 0;\n\n                    if (dir == 0) { // U\n                        xi = (b == -1) ? 0 : (x[b] + w[b]);\n                        ll xr = xi + wi;\n                        yi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(xi, xr, x[j], x[j] + w[j])) yi = max(yi, y[j] + h[j]);\n                        }\n                    } else { // L\n                        yi = (b == -1) ? 0 : (y[b] + h[b]);\n                        ll yb = yi + hi;\n                        xi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(yi, yb, y[j], y[j] + h[j])) xi = max(xi, x[j] + w[j]);\n                        }\n                    }\n\n                    ll nW = max(curW, xi + wi);\n                    ll nH = max(curH, yi + hi);\n\n                    double usedA2 = usedA + (double)wi * (double)hi;\n                    double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                    double gap = (double)nW * (double)nH - usedA2;\n                    if (gap < 0) gap = 0;\n\n                    double sc = lb\n                        + param.gap_w * (gap / norm)\n                        + param.bal_w * (double)llabs(nW - nH);\n                    if (param.noise_w > 0.0) sc += param.noise_w * rng.uniform01();\n\n                    ll perim = nW + nH;\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) <= 1e-12 && perim < bestPerim)) {\n                        bestScore = sc;\n                        bestPerim = perim;\n                        bestOp = Operation{(uint8_t)rot, (uint8_t)dir, b};\n                        bestX = xi; bestY = yi; bestWi = wi; bestHi = hi;\n                        nextW = nW; nextH = nH;\n                    }\n                }\n            }\n        }\n\n        ops[i] = bestOp;\n        x[i] = bestX; y[i] = bestY; w[i] = bestWi; h[i] = bestHi;\n        curW = nextW; curH = nextH;\n        usedA += (double)bestWi * (double)bestHi;\n    }\n\n    return ops;\n}\n\nuint64_t hash_ops(const vector<Operation>& ops) {\n    uint64_t h = 0xcbf29ce484222325ULL;\n    for (size_t i = 0; i < ops.size(); i++) {\n        uint64_t v = (uint64_t)(ops[i].r + 1);\n        v = v * 3ULL + (uint64_t)(ops[i].d + 1);\n        v = v * 1315423911ULL + (uint64_t)(ops[i].b + 3);\n        h ^= splitmix64(v + 0x9e3779b97f4a7c15ULL * (i + 1));\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvector<vector<Operation>> beam_generate(\n    const vector<ll>& baseW, const vector<ll>& baseH, const BeamParam& prm, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n\n    struct State {\n        array<ll, MAXN> x{}, y{}, w{}, h{};\n        array<Operation, MAXN> ops{};\n        ll W = 0, H = 0;\n        double usedA = 0.0;\n        double eval = 0.0;\n    };\n    struct Child {\n        double eval;\n        int parent;\n        Operation op;\n        ll x, y, w, h, W, H;\n        double usedA;\n    };\n\n    double totalA = 0.0;\n    for (int i = 0; i < N; i++) totalA += (double)baseW[i] * (double)baseH[i];\n    double sqrtA = sqrt(max(1.0, totalA));\n    double norm = sqrtA + 1.0;\n\n    vector<State> beam(1);\n\n    auto cmpChild = [](const Child& a, const Child& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        ll pa = a.W + a.H, pb = b.W + b.H;\n        return pa < pb;\n    };\n\n    for (int i = 0; i < N; i++) {\n        vector<Child> children;\n        children.reserve((int)beam.size() * 4 * (i + 1));\n\n        for (int si = 0; si < (int)beam.size(); si++) {\n            const State& st = beam[si];\n\n            for (int rot = 0; rot < 2; rot++) {\n                ll wi = rot ? baseH[i] : baseW[i];\n                ll hi = rot ? baseW[i] : baseH[i];\n\n                for (int dir = 0; dir < 2; dir++) {\n                    for (int b = -1; b < i; b++) {\n                        ll xi = 0, yi = 0;\n\n                        if (dir == 0) { // U\n                            xi = (b == -1) ? 0 : (st.x[b] + st.w[b]);\n                            ll xr = xi + wi;\n                            yi = 0;\n                            for (int j = 0; j < i; j++) {\n                                if (overlap(xi, xr, st.x[j], st.x[j] + st.w[j])) {\n                                    yi = max(yi, st.y[j] + st.h[j]);\n                                }\n                            }\n                        } else { // L\n                            yi = (b == -1) ? 0 : (st.y[b] + st.h[b]);\n                            ll yb = yi + hi;\n                            xi = 0;\n                            for (int j = 0; j < i; j++) {\n                                if (overlap(yi, yb, st.y[j], st.y[j] + st.h[j])) {\n                                    xi = max(xi, st.x[j] + st.w[j]);\n                                }\n                            }\n                        }\n\n                        ll nW = max(st.W, xi + wi);\n                        ll nH = max(st.H, yi + hi);\n\n                        double usedA2 = st.usedA + (double)wi * (double)hi;\n                        double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                        double gap = (double)nW * (double)nH - usedA2;\n                        if (gap < 0) gap = 0;\n\n                        double sc = lb\n                            + prm.gap_w * (gap / norm)\n                            + prm.bal_w * (double)llabs(nW - nH);\n                        if (prm.noise_w > 0.0) sc += prm.noise_w * rng.uniform01();\n\n                        children.push_back(Child{\n                            sc, si, Operation{(uint8_t)rot, (uint8_t)dir, b},\n                            xi, yi, wi, hi, nW, nH, usedA2\n                        });\n                    }\n                }\n            }\n        }\n\n        if (children.empty()) break;\n\n        int B = min(prm.beam_width, (int)children.size());\n        int limit = min((int)children.size(), max(B, B * 3));\n\n        if ((int)children.size() > limit) {\n            nth_element(children.begin(), children.begin() + limit, children.end(), cmpChild);\n        }\n        sort(children.begin(), children.begin() + limit, cmpChild);\n\n        vector<State> next;\n        next.reserve(B);\n        for (int k = 0; k < limit && (int)next.size() < B; k++) {\n            const Child& ch = children[k];\n            State ns = beam[ch.parent];\n            ns.ops[i] = ch.op;\n            ns.x[i] = ch.x;\n            ns.y[i] = ch.y;\n            ns.w[i] = ch.w;\n            ns.h[i] = ch.h;\n            ns.W = ch.W;\n            ns.H = ch.H;\n            ns.usedA = ch.usedA;\n            ns.eval = ch.eval;\n            next.push_back(std::move(ns));\n        }\n        beam.swap(next);\n        if (beam.empty()) break;\n    }\n\n    sort(beam.begin(), beam.end(), [](const State& a, const State& b) {\n        ll pa = a.W + a.H;\n        ll pb = b.W + b.H;\n        if (pa != pb) return pa < pb;\n        return a.eval < b.eval;\n    });\n\n    int M = min(prm.keep_leaves, (int)beam.size());\n    vector<vector<Operation>> out;\n    out.reserve(M);\n    for (int k = 0; k < M; k++) {\n        vector<Operation> ops(N);\n        for (int i = 0; i < N; i++) ops[i] = beam[k].ops[i];\n        out.push_back(std::move(ops));\n    }\n    return out;\n}\n\nvector<Operation> hill_climb(\n    const vector<ll>& baseW, const vector<ll>& baseH,\n    vector<Operation> ops, int iterations, FastRNG& rng\n) {\n    int N = (int)ops.size();\n    ll cur = score_on_base(baseW, baseH, ops);\n\n    for (int it = 0; it < iterations; it++) {\n        int i = rng.randint(0, N - 1);\n        Operation old = ops[i];\n        Operation nw = old;\n\n        int mode = rng.randint(0, 5);\n        if (mode == 0) nw.r ^= 1;\n        else if (mode == 1) nw.d ^= 1;\n        else if (mode == 2) {\n            if (i == 0) nw.b = -1;\n            else nw.b = rng.randint(-1, i - 1);\n        } else if (mode == 3) {\n            nw.r ^= 1;\n            nw.d ^= 1;\n        } else if (mode == 4) {\n            nw.r ^= 1;\n            if (i > 0) nw.b = rng.randint(-1, i - 1);\n        } else {\n            nw.d ^= 1;\n            if (i > 0 && rng.uniform01() < 0.7) nw.b = rng.randint(-1, i - 1);\n        }\n\n        if (i == 0) nw.b = -1;\n        else {\n            if (nw.b < -1) nw.b = -1;\n            if (nw.b >= i) nw.b = i - 1;\n        }\n\n        ops[i] = nw;\n        ll nxt = score_on_base(baseW, baseH, ops);\n        if (nxt <= cur) cur = nxt;\n        else ops[i] = old;\n    }\n    return ops;\n}\n\nvoid compute_predictions(Candidate& c, const vector<Scenario>& scenarios) {\n    int S = (int)scenarios.size();\n    c.predW.resize(S);\n    c.predH.resize(S);\n    c.predS.resize(S);\n\n    long double sum = 0.0L;\n    for (int s = 0; s < S; s++) {\n        auto [W, H] = simulate_layout(scenarios[s].w, scenarios[s].h, c.ops);\n        c.predW[s] = W;\n        c.predH[s] = H;\n        c.predS[s] = W + H;\n        sum += (long double)(W + H);\n    }\n    c.avg = (double)(sum / (long double)S);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    ll sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n\n    vector<ll> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    seed ^= splitmix64((uint64_t)N * 1000003ULL + (uint64_t)T * 10007ULL + (uint64_t)sigma * 911382323ULL);\n    for (int i = 0; i < N; i++) {\n        seed ^= splitmix64((uint64_t)obsW[i] * 1000003ULL + (uint64_t)obsH[i] + (uint64_t)(i + 1) * 19260817ULL);\n    }\n    FastRNG rng(seed);\n\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    // ---- scenarios ----\n    int S;\n    if (sigma <= 2500) S = 12;\n    else if (sigma <= 5000) S = 16;\n    else if (sigma <= 8000) S = 20;\n    else S = 24;\n\n    vector<Scenario> scenarios(S);\n    for (int s = 0; s < S; s++) {\n        scenarios[s].w.resize(N);\n        scenarios[s].h.resize(N);\n    }\n\n    // observed\n    for (int i = 0; i < N; i++) {\n        scenarios[0].w[i] = obsW[i];\n        scenarios[0].h[i] = obsH[i];\n    }\n    // global +sigma, -sigma\n    if (S >= 2) {\n        for (int i = 0; i < N; i++) {\n            scenarios[1].w[i] = clamp_dim(obsW[i] + sigma);\n            scenarios[1].h[i] = clamp_dim(obsH[i] + sigma);\n        }\n    }\n    if (S >= 3) {\n        for (int i = 0; i < N; i++) {\n            scenarios[2].w[i] = clamp_dim(obsW[i] - sigma);\n            scenarios[2].h[i] = clamp_dim(obsH[i] - sigma);\n        }\n    }\n    // antithetic random samples\n    for (int s = 3; s < S; s += 2) {\n        vector<double> zw(N), zh(N);\n        for (int i = 0; i < N; i++) {\n            zw[i] = rng.normal01();\n            zh[i] = rng.normal01();\n        }\n        for (int i = 0; i < N; i++) {\n            ll w1 = llround((double)obsW[i] + (double)sigma * zw[i]);\n            ll h1 = llround((double)obsH[i] + (double)sigma * zh[i]);\n            scenarios[s].w[i] = clamp_dim(w1);\n            scenarios[s].h[i] = clamp_dim(h1);\n            if (s + 1 < S) {\n                ll w2 = llround((double)obsW[i] - (double)sigma * zw[i]);\n                ll h2 = llround((double)obsH[i] - (double)sigma * zh[i]);\n                scenarios[s + 1].w[i] = clamp_dim(w2);\n                scenarios[s + 1].h[i] = clamp_dim(h2);\n            }\n        }\n    }\n\n    // ---- candidate generation ----\n    const int Pcap = 240;\n    int Ptarget = min(180, max(80, int(1.5 * T) + 20));\n\n    vector<Candidate> pool;\n    pool.reserve(Pcap + 16);\n    unordered_set<uint64_t> seen;\n    seen.reserve((Pcap + 16) * 4);\n\n    auto add_candidate_ops = [&](vector<Operation>&& ops) -> bool {\n        if ((int)ops.size() != N) return false;\n        if ((int)pool.size() >= Pcap) return false;\n        uint64_t h = hash_ops(ops);\n        if (!seen.insert(h).second) return false;\n        Candidate c;\n        c.ops = move(ops);\n        c.hash = h;\n        pool.push_back(move(c));\n        return true;\n    };\n\n    // baseline patterns\n    add_candidate_ops(build_linear_chain(obsW, obsH, true, true));\n    add_candidate_ops(build_linear_chain(obsW, obsH, false, true));\n    add_candidate_ops(build_single_stack(obsW, obsH, true));\n    add_candidate_ops(build_single_stack(obsW, obsH, false));\n    add_candidate_ops(build_linear_chain(obsW, obsH, true, false));\n    add_candidate_ops(build_linear_chain(obsW, obsH, false, false));\n\n    // deterministic greedy seeds\n    vector<GreedyParam> det = {\n        {0.30, 0.006, 0.0},\n        {0.55, 0.010, 0.0},\n        {0.80, 0.016, 0.0},\n        {0.12, 0.000, 0.0}\n    };\n    for (auto gp : det) add_candidate_ops(build_greedy(obsW, obsH, gp, rng));\n    if (S >= 2) add_candidate_ops(build_greedy(scenarios[1].w, scenarios[1].h, GreedyParam{0.45, 0.008, 0.0}, rng));\n    if (S >= 3) add_candidate_ops(build_greedy(scenarios[2].w, scenarios[2].h, GreedyParam{0.45, 0.008, 0.0}, rng));\n\n    // beam generation\n    int Bmain = (N <= 40 ? 52 : (N <= 70 ? 44 : (N <= 90 ? 36 : 30)));\n    int Bsub = max(18, Bmain - 12);\n\n    BeamParam bp1{Bmain, min(18, Bmain), 0.35, 0.006, 0.0};\n    BeamParam bp2{Bmain, min(16, Bmain), 0.65, 0.012, 0.0};\n    BeamParam bp3{Bsub, min(10, Bsub), 0.42, 0.010, 120.0 + 0.03 * (double)sigma};\n\n    auto run_beam = [&](const vector<ll>& bw, const vector<ll>& bh, const BeamParam& bp) {\n        if ((int)pool.size() >= Ptarget) return;\n        auto sols = beam_generate(bw, bh, bp, rng);\n        for (auto& ops : sols) {\n            add_candidate_ops(move(ops));\n            if ((int)pool.size() >= Ptarget) break;\n        }\n    };\n\n    double genBudget = (N <= 60 ? 1.05 : 0.95);\n    if (sigma >= 8000) genBudget += 0.10;\n\n    if (elapsed() < genBudget) run_beam(obsW, obsH, bp1);\n    if ((int)pool.size() < Ptarget && elapsed() < genBudget) run_beam(obsW, obsH, bp2);\n    if ((int)pool.size() < Ptarget && S >= 2 && sigma >= 2500 && elapsed() < genBudget) {\n        run_beam(scenarios[1].w, scenarios[1].h, bp3);\n    }\n    if ((int)pool.size() < Ptarget && S >= 3 && sigma >= 5000 && elapsed() < genBudget) {\n        run_beam(scenarios[2].w, scenarios[2].h, bp3);\n    }\n\n    // random greedy fill\n    int attempts = 0;\n    while ((int)pool.size() < Ptarget && elapsed() < genBudget && attempts < Ptarget * 50) {\n        int sid = rng.randint(0, S - 1);\n        GreedyParam gp;\n        gp.gap_w = 0.03 + 1.12 * rng.uniform01();\n        gp.bal_w = 0.03 * rng.uniform01();\n        gp.noise_w = (60.0 + 0.10 * (double)sigma) * rng.uniform01();\n        add_candidate_ops(build_greedy(scenarios[sid].w, scenarios[sid].h, gp, rng));\n        attempts++;\n    }\n\n    // targeted local refinement: improve top seeds on observed\n    if (!pool.empty() && elapsed() < genBudget + 0.35) {\n        vector<pair<ll, int>> rank;\n        rank.reserve(pool.size());\n        for (int i = 0; i < (int)pool.size(); i++) {\n            rank.emplace_back(score_on_base(obsW, obsH, pool[i].ops), i);\n        }\n        sort(rank.begin(), rank.end());\n\n        int topHC = min(10, (int)rank.size());\n        for (int k = 0; k < topHC && elapsed() < genBudget + 0.35; k++) {\n            int idx = rank[k].second;\n            auto ops2 = hill_climb(obsW, obsH, pool[idx].ops, 110 + N, rng);\n            add_candidate_ops(move(ops2));\n        }\n\n        if (sigma >= 5000 && S >= 2) {\n            int top2 = min(3, (int)rank.size());\n            for (int k = 0; k < top2 && elapsed() < genBudget + 0.45; k++) {\n                int idx = rank[k].second;\n                auto ops2 = hill_climb(scenarios[1].w, scenarios[1].h, pool[idx].ops, 80 + N, rng);\n                add_candidate_ops(move(ops2));\n            }\n        }\n    }\n\n    // final fill a bit more if needed\n    int attempts2 = 0;\n    while ((int)pool.size() < Ptarget && elapsed() < genBudget + 0.45 && attempts2 < Ptarget * 30) {\n        int sid = rng.randint(0, S - 1);\n        GreedyParam gp;\n        gp.gap_w = 0.05 + 1.00 * rng.uniform01();\n        gp.bal_w = 0.02 * rng.uniform01();\n        gp.noise_w = (40.0 + 0.08 * (double)sigma) * rng.uniform01();\n        add_candidate_ops(build_greedy(scenarios[sid].w, scenarios[sid].h, gp, rng));\n        attempts2++;\n    }\n\n    if (pool.empty()) {\n        add_candidate_ops(build_greedy(obsW, obsH, GreedyParam{0.40, 0.008, 0.0}, rng));\n    }\n\n    // precompute predictions\n    for (auto& c : pool) compute_predictions(c, scenarios);\n\n    // ---- online phase ----\n    vector<ll> bestScenario(S, INF64);\n    vector<double> logWeight(S, 0.0), post(S, 1.0 / S), weights(S, 1.0 / S);\n\n    vector<char> used(pool.size(), 0);\n    int usedCnt = 0;\n\n    double likeScale = max(700.0, (double)sigma * 1.75);\n    double invScale2 = 1.0 / (likeScale * likeScale);\n    double forget = 0.985;\n\n    int warmup = min(T - 1, max(3, T / 5));\n    int regen_turn1 = min(T - 1, max(4, T / 5));\n    int regen_turn2 = (T >= 24 ? min(T - 1, (2 * T) / 3) : -1);\n    bool regen_done1 = false, regen_done2 = false;\n\n    auto regenerate_from_posterior = [&](const vector<double>& posterior) {\n        if (elapsed() > 2.55) return;\n        if ((int)pool.size() >= Pcap) return;\n\n        vector<ll> mw(N), mh(N);\n        for (int i = 0; i < N; i++) {\n            long double sw = 0.0L, sh = 0.0L;\n            for (int s = 0; s < S; s++) {\n                sw += (long double)posterior[s] * (long double)scenarios[s].w[i];\n                sh += (long double)posterior[s] * (long double)scenarios[s].h[i];\n            }\n            mw[i] = clamp_dim((ll)llround(sw));\n            mh[i] = clamp_dim((ll)llround(sh));\n        }\n        int sid = int(max_element(posterior.begin(), posterior.end()) - posterior.begin());\n\n        size_t before = pool.size();\n\n        GreedyParam gA{0.32, 0.006, 0.0};\n        GreedyParam gB{0.62, 0.011, 0.0};\n        GreedyParam gC{0.42, 0.009, 80.0 + 0.02 * (double)sigma};\n\n        auto seedOps = build_greedy(mw, mh, gA, rng);\n        auto hcOps = hill_climb(mw, mh, seedOps, 90 + N, rng);\n        add_candidate_ops(move(seedOps));\n        add_candidate_ops(move(hcOps));\n        add_candidate_ops(build_greedy(mw, mh, gB, rng));\n        add_candidate_ops(build_greedy(mw, mh, gC, rng));\n        add_candidate_ops(build_greedy(scenarios[sid].w, scenarios[sid].h, gA, rng));\n\n        if (elapsed() < 2.40 && (int)pool.size() < Pcap - 4) {\n            int Br = max(16, Bmain - 12);\n            BeamParam rb{Br, min(8, Br), 0.40, 0.009, 0.0};\n            auto sols = beam_generate(mw, mh, rb, rng);\n            for (auto& ops : sols) {\n                add_candidate_ops(move(ops));\n                if ((int)pool.size() >= Pcap) break;\n            }\n        }\n\n        if (sigma >= 5000 && elapsed() < 2.50 && (int)pool.size() < Pcap) {\n            auto s2 = build_greedy(scenarios[sid].w, scenarios[sid].h, gB, rng);\n            auto h2 = hill_climb(scenarios[sid].w, scenarios[sid].h, s2, 70 + N, rng);\n            add_candidate_ops(move(s2));\n            add_candidate_ops(move(h2));\n        }\n\n        for (size_t idx = before; idx < pool.size(); idx++) {\n            compute_predictions(pool[idx], scenarios);\n            used.push_back(0);\n        }\n    };\n\n    for (int turn = 0; turn < T; turn++) {\n        // posterior softmax with flattening\n        double gamma = 0.30 + 0.55 * (double)turn / max(1, T - 1);\n        double mx = *max_element(logWeight.begin(), logWeight.end());\n        double sp = 0.0;\n        for (int s = 0; s < S; s++) {\n            post[s] = exp((logWeight[s] - mx) * gamma);\n            sp += post[s];\n        }\n        if (sp <= 0.0) {\n            for (int s = 0; s < S; s++) post[s] = 1.0 / S;\n        } else {\n            for (int s = 0; s < S; s++) post[s] /= sp;\n        }\n\n        double beta = 0.0;\n        if (turn >= warmup) {\n            beta = 0.70 * (double)(turn - warmup + 1) / max(1, T - warmup);\n            if (beta > 0.70) beta = 0.70;\n        }\n        for (int s = 0; s < S; s++) {\n            weights[s] = (1.0 - beta) * (1.0 / S) + beta * post[s];\n        }\n\n        // adaptive regeneration\n        if (!regen_done1 && turn == regen_turn1) {\n            regenerate_from_posterior(post);\n            regen_done1 = true;\n        }\n        if (!regen_done2 && regen_turn2 >= 0 && turn == regen_turn2) {\n            regenerate_from_posterior(post);\n            regen_done2 = true;\n        }\n\n        // choose candidate\n        bool hasUnused = (usedCnt < (int)used.size());\n        int chosen = -1;\n        long double bestVal = 1e300L;\n        double lambda_wc = 0.06 * (1.0 - (double)turn / max(1, T - 1));\n\n        for (int ci = 0; ci < (int)pool.size(); ci++) {\n            if (hasUnused && used[ci]) continue;\n\n            long double ev = 0.0L;\n            ll worst = 0;\n            for (int s = 0; s < S; s++) {\n                ll cur = min(bestScenario[s], pool[ci].predS[s]);\n                ev += (long double)weights[s] * (long double)cur;\n                if (cur > worst) worst = cur;\n            }\n            long double val = ev + lambda_wc * (long double)worst;\n\n            if (chosen == -1 || val < bestVal - 1e-12L ||\n                (fabsl(val - bestVal) <= 1e-12L && pool[ci].avg < pool[chosen].avg)) {\n                bestVal = val;\n                chosen = ci;\n            }\n        }\n        if (chosen == -1) chosen = 0;\n\n        if (!used[chosen]) {\n            used[chosen] = 1;\n            usedCnt++;\n        }\n\n        // output\n        cout << N << '\\n';\n        for (int i = 0; i < N; i++) {\n            const auto& op = pool[chosen].ops[i];\n            cout << i << ' ' << int(op.r) << ' ' << (op.d == 0 ? 'U' : 'L') << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        if (Wm == -1 && Hm == -1) return 0;\n\n        // update best score per scenario\n        for (int s = 0; s < S; s++) {\n            bestScenario[s] = min(bestScenario[s], pool[chosen].predS[s]);\n        }\n\n        // robust posterior update\n        for (int s = 0; s < S; s++) logWeight[s] *= forget;\n        for (int s = 0; s < S; s++) {\n            double dw = (double)Wm - (double)pool[chosen].predW[s];\n            double dh = (double)Hm - (double)pool[chosen].predH[s];\n            double d2 = (dw * dw + dh * dh) * invScale2;\n            logWeight[s] += -log1p(d2); // Cauchy-like\n        }\n\n        double mx2 = *max_element(logWeight.begin(), logWeight.end());\n        for (int s = 0; s < S; s++) logWeight[s] -= mx2;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() { x ^= x << 7; x ^= x >> 9; return x; }\n    inline int next_int(int l, int r) { return l + (int)(next_u64() % (uint64_t)(r - l + 1)); }\n    inline double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nclass Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<vector<int>> g;\n    vector<int> ordDesc, ordAsc;\n    XorShift64 rng;\n    chrono::steady_clock::time_point t0;\n\n    struct DState {\n        vector<int> d;\n        vector<int> cnt;\n        long long extra = 0;\n    };\n\n    struct Forest {\n        vector<int> p;\n        vector<vector<int>> ch;\n        vector<int> d;\n        long long extra = 0;\n    };\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void solve() {\n        read_input();\n        prepare_orders();\n        t0 = chrono::steady_clock::now();\n\n        const double TOTAL = 1.88;\n        const double T1 = 1.15;\n        const double T2 = 1.45;\n        const double T3 = 1.67;\n        const double T4 = TOTAL;\n\n        vector<int> d0;\n        if (elapsed() < T1) d0 = optimize_depths_scratch(T1);\n        else d0.assign(N, 0);\n        repair_depth(d0);\n\n        Forest globalBest = build_forest_from_depth(d0, 0);\n\n        if (elapsed() < T2) {\n            Forest f1 = tree_optimize(d0, T2);\n            if (f1.extra > globalBest.extra) globalBest = move(f1);\n        }\n\n        vector<int> dSeed = globalBest.d;\n\n        if (elapsed() < T3) {\n            dSeed = polish_depth_seed(dSeed, T3);\n            Forest b2 = build_forest_from_depth(dSeed, 0);\n            if (b2.extra > globalBest.extra) globalBest = move(b2);\n        }\n\n        if (elapsed() < T4 - 1e-4) {\n            Forest f2 = tree_optimize(dSeed, T4);\n            if (f2.extra > globalBest.extra) globalBest = move(f2);\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << globalBest.p[i];\n        }\n        cout << '\\n';\n    }\n\nprivate:\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        for (int i = 0; i < N; i++) {\n            int x, y;\n            cin >> x >> y;\n        }\n    }\n\n    void prepare_orders() {\n        ordDesc.resize(N);\n        iota(ordDesc.begin(), ordDesc.end(), 0);\n        sort(ordDesc.begin(), ordDesc.end(), [&](int a, int b) {\n            if (A[a] != A[b]) return A[a] > A[b];\n            if (g[a].size() != g[b].size()) return g[a].size() < g[b].size();\n            return a < b;\n        });\n        ordAsc = ordDesc;\n        reverse(ordAsc.begin(), ordAsc.end());\n    }\n\n    void shuffle_vec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i >= 1; --i) {\n            int j = rng.next_int(0, i);\n            swap(v[i], v[j]);\n        }\n    }\n\n    // ===== depth-label optimization =====\n\n    void rebuild(DState& st) const {\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n        for (int v = 0; v < N; v++) st.extra += 1LL * st.d[v] * A[v];\n\n        for (int v = 0; v < N; v++) {\n            if (st.d[v] == 0) continue;\n            int need = st.d[v] - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n    }\n\n    void repair_depth(vector<int>& d) const {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int v = 0; v < N; v++) {\n                while (d[v] > 0) {\n                    int need = d[v] - 1;\n                    bool ok = false;\n                    for (int u : g[v]) {\n                        if (d[u] == need) { ok = true; break; }\n                    }\n                    if (ok) break;\n                    --d[v];\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    inline bool feasible_change(const DState& st, int v, int nd) const {\n        int od = st.d[v];\n        if (nd == od) return false;\n        if (nd < 0 || nd > H) return false;\n\n        if (nd > 0) {\n            bool ok = false;\n            for (int u : g[v]) {\n                if (st.d[u] == nd - 1) { ok = true; break; }\n            }\n            if (!ok) return false;\n        }\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            int c = st.cnt[u];\n            if (od == need) --c;\n            if (nd == need) ++c;\n            if (c <= 0) return false;\n        }\n        return true;\n    }\n\n    inline void apply_change(DState& st, int v, int nd) const {\n        int od = st.d[v];\n        if (od == nd) return;\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            if (od == need) --st.cnt[u];\n            if (nd == need) ++st.cnt[u];\n        }\n\n        st.d[v] = nd;\n        if (nd == 0) st.cnt[v] = 0;\n        else {\n            int need = nd - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n        st.extra += 1LL * (nd - od) * A[v];\n    }\n\n    bool greedy_up_pass(DState& st, const vector<int>& order, bool stepwise) const {\n        bool changed = false;\n        for (int v : order) {\n            int cur = st.d[v];\n            if (stepwise) {\n                int nd = cur + 1;\n                if (nd <= H && feasible_change(st, v, nd)) {\n                    apply_change(st, v, nd);\n                    changed = true;\n                }\n            } else {\n                for (int nd = H; nd > cur; --nd) {\n                    if (feasible_change(st, v, nd)) {\n                        apply_change(st, v, nd);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n        return changed;\n    }\n\n    DState construct_initial_variant(int variant) {\n        DState st;\n        st.d.assign(N, 0);\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) key[v] = A[v] * 2048 + rng.next_int(0, 2047);\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 1) {\n            order = ordDesc;\n            int sw = N / 4;\n            for (int i = 0; i < sw; i++) {\n                int x = rng.next_int(0, N - 1), y = rng.next_int(0, N - 1);\n                swap(order[x], order[y]);\n            }\n        } else if (variant == 2) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) {\n                int deg = (int)g[v].size();\n                key[v] = (A[v] * 1200) / (deg + 1) + rng.next_int(0, 255);\n            }\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 3) {\n            order = ordDesc;\n            shuffle_vec(order);\n        } else {\n            order = ordDesc;\n        }\n\n        for (int pass = 0; pass < 24; pass++) {\n            bool step = (pass < 4);\n            bool changed = greedy_up_pass(st, order, step);\n            if (pass == 1 || pass == 4 || pass == 8) {\n                if (variant == 1 || variant == 3) shuffle_vec(order);\n            }\n            if (!changed && pass > 7) break;\n        }\n\n        for (int rep = 0; rep < 4; rep++) {\n            if (!greedy_up_pass(st, ordDesc, false)) break;\n        }\n\n        return st;\n    }\n\n    void short_sa_polish(DState& st, int iters, double T0, double T1, double timeLimit) {\n        int topK = min(N, 230);\n        vector<int> bestD = st.d;\n        long long bestE = st.extra;\n\n        for (int it = 0; it < iters; it++) {\n            if ((it & 127) == 0 && elapsed() >= timeLimit) break;\n\n            int v = (rng.next_double() < 0.70) ? ordDesc[rng.next_int(0, topK - 1)] : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = st.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != st.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.46) nd = cand[clen - 1];\n            else if (r < 0.58) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(st, v, nd)) continue;\n\n            int delta = (nd - st.d[v]) * A[v];\n            double p = (double)it / max(1, iters - 1);\n            double temp = T0 * pow(T1 / T0, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n            if (!accept) continue;\n\n            apply_change(st, v, nd);\n            if (st.extra > bestE) {\n                bestE = st.extra;\n                bestD = st.d;\n            }\n        }\n\n        if (bestE > st.extra) {\n            st.d = move(bestD);\n            rebuild(st);\n        }\n    }\n\n    void run_feasible_sa(DState& cur, DState& best, double timeLimit) {\n        double saStart = elapsed();\n        if (saStart >= timeLimit) return;\n\n        const double T0 = 55.0;\n        const double T1 = 0.18;\n        const double ratio = T1 / T0;\n        int topK = min(N, 300);\n\n        long long iter = 0;\n        while (true) {\n            if ((iter & 255LL) == 0 && elapsed() >= timeLimit) break;\n            ++iter;\n\n            int v = (rng.next_double() < 0.62) ? ordDesc[rng.next_int(0, topK - 1)] : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = cur.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != cur.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.48) nd = cand[clen - 1];\n            else if (r < 0.62) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(cur, v, nd)) continue;\n\n            int delta = (nd - cur.d[v]) * A[v];\n\n            double now = elapsed();\n            double p = (now - saStart) / max(1e-9, timeLimit - saStart);\n            p = max(0.0, min(1.0, p));\n            double temp = T0 * pow(ratio, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n            if (!accept) continue;\n\n            apply_change(cur, v, nd);\n            if (cur.extra > best.extra) best = cur;\n\n            if ((iter & 65535LL) == 0 && cur.extra + 5000 < best.extra) cur = best;\n        }\n    }\n\n    void macro_perturb_search(DState& best, double timeLimit) {\n        int topHigh = min(N, 300);\n        int topLow = min(N, 420);\n        vector<int> order = ordDesc;\n\n        while (elapsed() < timeLimit) {\n            DState tmp = best;\n            int mode = rng.next_int(0, 4);\n\n            if (mode == 0) {\n                int k = rng.next_int(1, 4);\n                for (int i = 0; i < k; i++) {\n                    int v = ordDesc[rng.next_int(0, topHigh - 1)];\n                    tmp.d[v] = H;\n                }\n            } else if (mode == 1) {\n                int k = rng.next_int(2, 7);\n                for (int i = 0; i < k; i++) {\n                    int v = ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = 0;\n                }\n            } else if (mode == 2) {\n                int k = rng.next_int(18, 80);\n                for (int i = 0; i < k; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    tmp.d[v] = rng.next_int(0, H);\n                }\n            } else if (mode == 3) {\n                int k = rng.next_int(15, 50);\n                for (int i = 0; i < k; i++) {\n                    bool hi = (rng.next_double() < 0.62);\n                    int v = hi ? ordDesc[rng.next_int(0, topHigh - 1)]\n                               : ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = hi ? H : 0;\n                }\n            } else {\n                int c = rng.next_int(0, N - 1);\n                tmp.d[c] = (rng.next_double() < 0.5 ? 0 : H);\n                for (int u : g[c]) if (rng.next_double() < 0.75) tmp.d[u] = rng.next_int(0, H);\n                int ex = rng.next_int(5, 20);\n                for (int i = 0; i < ex; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    if (rng.next_double() < 0.55) tmp.d[v] = 0;\n                }\n            }\n\n            repair_depth(tmp.d);\n            rebuild(tmp);\n\n            order = ordDesc;\n            for (int pass = 0; pass < 7; pass++) {\n                if (pass == 1 || pass == 4) shuffle_vec(order);\n                else if (pass == 2 || pass == 5) order = ordDesc;\n\n                bool step = (pass < 2);\n                bool changed = greedy_up_pass(tmp, order, step);\n\n                if (!changed && pass >= 4) break;\n                if (elapsed() >= timeLimit) break;\n            }\n\n            if (elapsed() + 0.010 < timeLimit && rng.next_double() < 0.52) {\n                short_sa_polish(tmp, 650, 2.1, 0.35, timeLimit);\n            }\n\n            if (tmp.extra > best.extra) best = move(tmp);\n        }\n    }\n\n    vector<int> optimize_depths_scratch(double endTime) {\n        DState best;\n        best.extra = LLONG_MIN;\n\n        double initEnd = min(endTime, 0.26);\n        int restart = 0;\n        while (elapsed() < initEnd) {\n            DState st = construct_initial_variant(restart % 5);\n\n            if ((restart & 1) == 0 && elapsed() + 0.008 < initEnd) {\n                short_sa_polish(st, 420, 4.5, 0.9, initEnd);\n            }\n\n            if (st.extra > best.extra) best = move(st);\n            ++restart;\n        }\n\n        if (best.extra == LLONG_MIN) {\n            best.d.assign(N, 0);\n            best.cnt.assign(N, 0);\n            best.extra = 0;\n        }\n\n        DState cur = best;\n\n        double saEnd = min(endTime, initEnd + (endTime - initEnd) * 0.58);\n        if (elapsed() < saEnd) run_feasible_sa(cur, best, saEnd);\n        if (elapsed() < endTime) macro_perturb_search(best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 5; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    vector<int> polish_depth_seed(const vector<int>& seed, double endTime) {\n        DState best;\n        best.d = seed;\n        repair_depth(best.d);\n        rebuild(best);\n\n        for (int i = 0; i < 4; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        DState cur = best;\n        double rem = max(0.0, endTime - elapsed());\n        double saEnd = min(endTime, elapsed() + rem * 0.62);\n        if (elapsed() < saEnd) run_feasible_sa(cur, best, saEnd);\n        if (elapsed() < endTime) macro_perturb_search(best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 3; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    // ===== forest / subtree phase =====\n\n    inline void erase_child(vector<int>& vec, int x) {\n        for (int i = 0; i < (int)vec.size(); i++) {\n            if (vec[i] == x) {\n                vec[i] = vec.back();\n                vec.pop_back();\n                return;\n            }\n        }\n    }\n\n    Forest build_forest_from_depth(const vector<int>& depth, int mode) {\n        Forest f;\n        f.d = depth;\n        f.p.assign(N, -1);\n        f.ch.assign(N, {});\n\n        for (int v = 0; v < N; v++) {\n            if (f.d[v] == 0) {\n                f.p[v] = -1;\n                continue;\n            }\n            int need = f.d[v] - 1;\n            vector<int> sup;\n            sup.reserve(g[v].size());\n            for (int u : g[v]) if (f.d[u] == need) sup.push_back(u);\n\n            int par = -1;\n            if (!sup.empty()) {\n                if ((int)sup.size() == 1) {\n                    par = sup[0];\n                } else if (mode == 1) {\n                    par = sup[rng.next_int(0, (int)sup.size() - 1)];\n                } else if (mode == 2) {\n                    long long bestKey = (1LL << 60);\n                    for (int u : sup) {\n                        long long key = 1LL * A[u] * 32 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            par = u;\n                        }\n                    }\n                } else {\n                    int bestA = 1e9, bestDeg = 1e9;\n                    for (int u : sup) {\n                        int au = A[u], du = (int)g[u].size();\n                        if (au < bestA || (au == bestA && du < bestDeg) ||\n                            (au == bestA && du == bestDeg && (par == -1 || u < par))) {\n                            bestA = au;\n                            bestDeg = du;\n                            par = u;\n                        }\n                    }\n                }\n            } else {\n                // safety fallback (should be rare)\n                for (int u : g[v]) {\n                    if (f.d[u] < f.d[v]) { par = u; break; }\n                }\n            }\n\n            f.p[v] = par;\n        }\n\n        for (int v = 0; v < N; v++) {\n            int p = f.p[v];\n            if (p != -1) f.ch[p].push_back(v);\n        }\n\n        f.extra = 0;\n        for (int v = 0; v < N; v++) f.extra += 1LL * f.d[v] * A[v];\n        return f;\n    }\n\n    void normalize_parents(Forest& f, int rounds, bool highFirst) {\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        for (int r = 0; r < rounds; r++) {\n            if (highFirst) order = ordDesc;\n            else shuffle_vec(order);\n\n            for (int v : order) {\n                if (f.d[v] == 0) continue;\n                int need = f.d[v] - 1;\n\n                int curp = f.p[v];\n                int best = curp;\n                long long bestKey = (1LL << 60);\n                if (curp != -1) {\n                    bestKey = 1LL * A[curp] * 256 + (int)f.ch[curp].size() * 8 + (int)g[curp].size();\n                }\n\n                for (int u : g[v]) {\n                    if (f.d[u] != need) continue;\n                    long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                    if (key < bestKey) {\n                        bestKey = key;\n                        best = u;\n                    }\n                }\n\n                if (best != -1 && best != curp) {\n                    if (curp != -1) erase_child(f.ch[curp], v);\n                    f.p[v] = best;\n                    f.ch[best].push_back(v);\n                }\n            }\n        }\n    }\n\n    void leafify_highA(Forest& f, int topK, int rounds) {\n        topK = min(topK, N);\n        for (int r = 0; r < rounds; r++) {\n            for (int i = 0; i < topK; i++) {\n                int v = ordDesc[i];\n                if (f.ch[v].empty()) continue;\n\n                vector<int> children = f.ch[v];\n                for (int x : children) {\n                    if (f.p[x] != v) continue;\n                    int need = f.d[x] - 1;\n                    if (need < 0) continue;\n\n                    int best = -1;\n                    long long bestKey = (1LL << 60);\n\n                    for (int u : g[x]) {\n                        if (u == v) continue;\n                        if (f.d[u] != need) continue;\n\n                        long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            best = u;\n                        }\n                    }\n\n                    if (best != -1) {\n                        erase_child(f.ch[v], x);\n                        f.p[x] = best;\n                        f.ch[best].push_back(x);\n                    }\n                }\n            }\n        }\n    }\n\n    void init_subinfo(const Forest& f, vector<long long>& subA, vector<int>& subMax) const {\n        subA.assign(N, 0);\n        subMax.assign(N, 0);\n        vector<vector<int>> bucket(H + 1);\n\n        for (int v = 0; v < N; v++) {\n            subA[v] = A[v];\n            subMax[v] = f.d[v];\n            bucket[f.d[v]].push_back(v);\n        }\n\n        for (int dep = H; dep >= 0; dep--) {\n            for (int v : bucket[dep]) {\n                int p = f.p[v];\n                if (p != -1) {\n                    subA[p] += subA[v];\n                    if (subMax[v] > subMax[p]) subMax[p] = subMax[v];\n                }\n            }\n        }\n    }\n\n    inline bool is_descendant(const Forest& f, int u, int anc) const {\n        while (u != -1 && f.d[u] > f.d[anc]) u = f.p[u];\n        return u == anc;\n    }\n\n    void run_tree_sa_fast(Forest& cur, Forest& best, double timeLimit) {\n        if (elapsed() >= timeLimit) return;\n\n        vector<long long> subA;\n        vector<int> subMax;\n        init_subinfo(cur, subA, subMax);\n\n        vector<int> nodes, st;\n        nodes.reserve(N);\n        st.reserve(N);\n\n        auto gather_nodes = [&](int root) {\n            nodes.clear();\n            st.clear();\n            st.push_back(root);\n            while (!st.empty()) {\n                int x = st.back();\n                st.pop_back();\n                nodes.push_back(x);\n                for (int y : cur.ch[x]) st.push_back(y);\n            }\n        };\n\n        auto recompute_up = [&](int a) {\n            while (a != -1) {\n                int mx = cur.d[a];\n                for (int c : cur.ch[a]) if (subMax[c] > mx) mx = subMax[c];\n                subMax[a] = mx;\n                a = cur.p[a];\n            }\n        };\n\n        auto apply_move = [&](int v, int np, int delta, long long gain) {\n            gather_nodes(v);\n\n            int oldp = cur.p[v];\n            if (oldp != -1) erase_child(cur.ch[oldp], v);\n\n            cur.p[v] = np;\n            if (np != -1) cur.ch[np].push_back(v);\n\n            if (delta != 0) {\n                for (int x : nodes) {\n                    cur.d[x] += delta;\n                    subMax[x] += delta;\n                }\n            }\n\n            cur.extra += gain;\n\n            long long sv = subA[v];\n            if (oldp != -1) {\n                int a = oldp;\n                while (a != -1) {\n                    subA[a] -= sv;\n                    a = cur.p[a];\n                }\n            }\n            if (np != -1) {\n                int a = np;\n                while (a != -1) {\n                    subA[a] += sv;\n                    a = cur.p[a];\n                }\n            }\n\n            if (oldp != -1) recompute_up(oldp);\n            if (np != -1) recompute_up(np);\n\n            if (cur.extra > best.extra) best = cur;\n        };\n\n        struct Cand { int par; int delta; long long gain; };\n        vector<Cand> cands;\n        cands.reserve(16);\n\n        double phaseStart = elapsed();\n        const double T0 = 3200.0;\n        const double T1 = 1.8;\n        const double ratio = T1 / T0;\n        const int topK = min(N, 320);\n\n        long long iter = 0;\n        while (true) {\n            if ((iter & 127LL) == 0 && elapsed() >= timeLimit) break;\n            ++iter;\n\n            int v;\n            double r = rng.next_double();\n            if (r < 0.65) v = ordDesc[rng.next_int(0, topK - 1)];\n            else v = rng.next_int(0, N - 1);\n\n            long long sv = subA[v];\n            int sm = subMax[v];\n\n            cands.clear();\n            long long bestGain = LLONG_MIN;\n            int bestIdx = -1;\n\n            for (int u : g[v]) {\n                if (is_descendant(cur, u, v)) continue;\n\n                int ndv = cur.d[u] + 1;\n                if (ndv > H) continue;\n\n                int delta = ndv - cur.d[v];\n                if (delta == 0 && cur.p[v] == u) continue;\n                if (sm + delta > H) continue;\n\n                long long gain = 1LL * delta * sv;\n                cands.push_back({u, delta, gain});\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestIdx = (int)cands.size() - 1;\n                }\n            }\n\n            if (cur.p[v] != -1) {\n                int delta = -cur.d[v];\n                if (sm + delta <= H) {\n                    long long gain = 1LL * delta * sv;\n                    cands.push_back({-1, delta, gain});\n                    if (gain > bestGain) {\n                        bestGain = gain;\n                        bestIdx = (int)cands.size() - 1;\n                    }\n                }\n            }\n\n            if (cands.empty()) continue;\n\n            int chosen;\n            if (bestIdx != -1 && bestGain > 0 && rng.next_double() < 0.82) {\n                chosen = bestIdx;\n            } else {\n                chosen = rng.next_int(0, (int)cands.size() - 1);\n            }\n\n            Cand c = cands[chosen];\n            long long gain = c.gain;\n\n            bool accept = false;\n            if (gain > 0) {\n                accept = true;\n            } else if (gain == 0) {\n                double pr = (c.par == cur.p[v] ? 0.10 : 0.38);\n                accept = (rng.next_double() < pr);\n            } else {\n                double p = (elapsed() - phaseStart) / max(1e-9, timeLimit - phaseStart);\n                p = max(0.0, min(1.0, p));\n                double temp = T0 * pow(ratio, p);\n\n                double x = (double)gain / temp;\n                if (x > -25.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n            apply_move(v, c.par, c.delta, c.gain);\n\n            if ((iter & 8191LL) == 0) {\n                if (cur.extra + 12000 < best.extra) {\n                    cur = best;\n                    init_subinfo(cur, subA, subMax);\n                }\n            }\n        }\n\n        // deterministic uphill finishing\n        for (int pass = 0; pass < 2 && elapsed() < timeLimit; pass++) {\n            bool changed = false;\n\n            for (int i = 0; i < N; i++) {\n                if ((i & 31) == 0 && elapsed() >= timeLimit) break;\n                int v = ordDesc[i];\n\n                long long sv = subA[v];\n                int sm = subMax[v];\n\n                long long bestG = 0;\n                int bestPar = -2, bestDelta = 0;\n\n                for (int u : g[v]) {\n                    if (is_descendant(cur, u, v)) continue;\n\n                    int ndv = cur.d[u] + 1;\n                    if (ndv > H) continue;\n\n                    int delta = ndv - cur.d[v];\n                    if (delta == 0 && cur.p[v] == u) continue;\n                    if (sm + delta > H) continue;\n\n                    long long gain = 1LL * delta * sv;\n                    if (gain > bestG) {\n                        bestG = gain;\n                        bestPar = u;\n                        bestDelta = delta;\n                    }\n                }\n\n                if (bestPar == -2) continue;\n                apply_move(v, bestPar, bestDelta, bestG);\n                changed = true;\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    Forest tree_optimize(const vector<int>& baseDepth, double endTime) {\n        vector<int> d = baseDepth;\n        repair_depth(d);\n\n        Forest best = build_forest_from_depth(d, 0);\n        normalize_parents(best, 1, true);\n        leafify_highA(best, 230, 1);\n\n        if (elapsed() >= endTime) return best;\n\n        Forest cur = best;\n        double rem = max(0.0, endTime - elapsed());\n        double mid = elapsed() + rem * 0.56;\n        run_tree_sa_fast(cur, best, mid);\n\n        if (elapsed() < endTime - 0.02) {\n            Forest alt = build_forest_from_depth(d, 1);\n            normalize_parents(alt, 1, false);\n            leafify_highA(alt, 260, 1);\n            run_tree_sa_fast(alt, best, endTime);\n        }\n\n        return best;\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}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 20;\nconstexpr int MAXC = 80;\nconstexpr int MAXD = 20;\nconstexpr int MAXM = 64;\n\nstruct Chain {\n    char dir, rev;\n    int idx;\n};\nstruct Option {\n    int chain, req;\n};\nstruct State {\n    array<uint8_t, MAXC> d{};\n    array<uint8_t, MAXM> sat{};\n    uint64_t unsatMask = 0;\n    int cost = 0; // 2 * sum(depth)\n};\nstruct UPlan {\n    array<uint8_t, MAXC> in{};\n    vector<int> ord;\n    int save = 0; // sum depth on ord\n};\n\nclass Solver {\n    using Grid = array<array<char, MAXN>, MAXN>;\n    using Op = pair<char,int>;\n\n    int N, Cn, M;\n    vector<string> board;\n    Grid initGrid{};\n    vector<pair<int,int>> oniPos;\n    int initialFuku = 0;\n\n    array<Chain, MAXC> chains{};\n    vector<vector<Option>> opts;\n\n    array<int, MAXC> cap{};\n    array<array<uint64_t, MAXD + 1>, MAXC> eqMask{};\n    array<array<uint64_t, MAXD + 1>, MAXC> leMask{};\n    array<vector<int>, MAXC> usefulDepths{};\n\n    uint64_t fullMask = 0;\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver(int n, vector<string> b): N(n), Cn(4*n), board(move(b)) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        build();\n    }\n\n    vector<Op> solve() {\n        st = chrono::steady_clock::now();\n\n        const double depthEnd   = 1.48;\n        const double unpair1End = 1.66;\n        const double shrinkEnd  = 1.77;\n        const double unpair2End = 1.84;\n        const double pruneEnd   = 1.90;\n\n        State s = optimizeDepth(depthEnd);\n        State guaranteed = s; // guaranteed-cover state (for fallback)\n\n        UPlan plan = optimizeUnpair(s, unpair1End, nullptr);\n\n        if (now() < shrinkEnd) {\n            exactDepthShrink(s, plan, shrinkEnd);\n        }\n\n        if (now() < unpair2End) {\n            plan = optimizeUnpair(s, unpair2End, &plan);\n        }\n\n        sanitizePlan(plan, s);\n        vector<Op> ans = buildOps(s, plan);\n\n        if (now() < pruneEnd) {\n            pruneOps(ans, pruneEnd);\n        }\n\n        if (!checkOpsValid(ans)) {\n            UPlan empty = emptyPlan();\n            vector<Op> safe = buildOps(guaranteed, empty);\n            if (checkOpsValid(safe)) {\n                ans.swap(safe);\n            } else {\n                vector<Op> fb = fallbackPerOni();\n                if (checkOpsValid(fb)) ans.swap(fb);\n                else ans = fb;\n            }\n        }\n\n        if ((int)ans.size() > 4 * N * N) {\n            vector<Op> fb = fallbackPerOni();\n            if (checkOpsValid(fb)) ans.swap(fb);\n        }\n\n        return ans;\n    }\n\nprivate:\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline double rand01() {\n        return (double)(rng() & ((1u << 24) - 1)) / (double)(1u << 24);\n    }\n\n    inline int idUp(int j) const { return j; }\n    inline int idDown(int j) const { return N + j; }\n    inline int idLeft(int i) const { return 2 * N + i; }\n    inline int idRight(int i) const { return 3 * N + i; }\n\n    void build() {\n        for (int i = 0; i < MAXN; i++) for (int j = 0; j < MAXN; j++) initGrid[i][j] = '.';\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            initGrid[i][j] = board[i][j];\n            if (board[i][j] == 'x') oniPos.push_back({i, j});\n            if (board[i][j] == 'o') initialFuku++;\n        }\n        M = (int)oniPos.size();\n        opts.assign(M, {});\n\n        vector<int> upSafe(N, N), downSafe(N, N), leftSafe(N, N), rightSafe(N, N);\n\n        for (int j = 0; j < N; j++) {\n            for (int i = 0; i < N; i++) if (board[i][j] == 'o') { upSafe[j] = i; break; }\n            for (int i = N - 1; i >= 0; i--) if (board[i][j] == 'o') { downSafe[j] = N - 1 - i; break; }\n        }\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) if (board[i][j] == 'o') { leftSafe[i] = j; break; }\n            for (int j = N - 1; j >= 0; j--) if (board[i][j] == 'o') { rightSafe[i] = N - 1 - j; break; }\n        }\n\n        for (int j = 0; j < N; j++) {\n            chains[idUp(j)] = {'U', 'D', j};\n            chains[idDown(j)] = {'D', 'U', j};\n        }\n        for (int i = 0; i < N; i++) {\n            chains[idLeft(i)] = {'L', 'R', i};\n            chains[idRight(i)] = {'R', 'L', i};\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto [r, c] = oniPos[m];\n            int reqU = r + 1;\n            int reqD = N - r;\n            int reqL = c + 1;\n            int reqR = N - c;\n\n            if (reqU <= upSafe[c]) opts[m].push_back({idUp(c), reqU});\n            if (reqD <= downSafe[c]) opts[m].push_back({idDown(c), reqD});\n            if (reqL <= leftSafe[r]) opts[m].push_back({idLeft(r), reqL});\n            if (reqR <= rightSafe[r]) opts[m].push_back({idRight(r), reqR});\n\n            if (opts[m].empty()) { // should not happen\n                opts[m].push_back({idUp(c), min(reqU, N)});\n            }\n        }\n\n        for (int c = 0; c < MAXC; c++) {\n            cap[c] = 0;\n            usefulDepths[c].clear();\n            for (int d = 0; d <= MAXD; d++) {\n                eqMask[c][d] = 0;\n                leMask[c][d] = 0;\n            }\n        }\n\n        for (int m = 0; m < M; m++) {\n            for (auto &op : opts[m]) {\n                eqMask[op.chain][op.req] |= (1ULL << m);\n            }\n        }\n\n        for (int c = 0; c < Cn; c++) {\n            leMask[c][0] = 0;\n            for (int d = 1; d <= N; d++) {\n                leMask[c][d] = leMask[c][d - 1] | eqMask[c][d];\n                if (eqMask[c][d]) {\n                    usefulDepths[c].push_back(d);\n                    cap[c] = d;\n                }\n            }\n        }\n\n        fullMask = (M == 64 ? ~0ULL : ((1ULL << M) - 1ULL));\n    }\n\n    // ---------- State operations ----------\n    State makeZeroState() const {\n        State s;\n        s.d.fill(0);\n        s.sat.fill(0);\n        s.unsatMask = fullMask;\n        s.cost = 0;\n        return s;\n    }\n\n    inline void incChain(State &s, int c) {\n        int nd = (int)s.d[c] + 1;\n        uint64_t bits = eqMask[c][nd];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            if (s.sat[m]++ == 0) s.unsatMask &= ~(1ULL << m);\n        }\n        s.d[c] = (uint8_t)nd;\n        s.cost += 2;\n    }\n\n    inline void decChain(State &s, int c) {\n        int t = (int)s.d[c];\n        uint64_t bits = eqMask[c][t];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            uint8_t v = --s.sat[m];\n            if (v == 0) s.unsatMask |= (1ULL << m);\n        }\n        s.d[c] = (uint8_t)(t - 1);\n        s.cost -= 2;\n    }\n\n    inline void setChain(State &s, int c, int nd) {\n        while ((int)s.d[c] < nd) incChain(s, c);\n        while ((int)s.d[c] > nd) decChain(s, c);\n    }\n\n    State fromDepth(const array<uint8_t, MAXC>& depth) {\n        State s = makeZeroState();\n        for (int c = 0; c < Cn; c++) {\n            for (int t = 0; t < (int)depth[c]; t++) incChain(s, c);\n        }\n        return s;\n    }\n\n    void reduceDepth(State &s, bool randomOrder) {\n        array<int, MAXC> ord{};\n        for (int i = 0; i < Cn; i++) ord[i] = i;\n        if (randomOrder) shuffle(ord.begin(), ord.begin() + Cn, rng);\n\n        for (int ii = 0; ii < Cn; ii++) {\n            int c = ord[ii];\n            while ((int)s.d[c] > 0) {\n                int t = (int)s.d[c];\n                uint64_t bits = eqMask[c][t];\n                bool ok = true;\n                while (bits) {\n                    int m = __builtin_ctzll(bits);\n                    bits &= bits - 1;\n                    if (s.sat[m] == 1) { ok = false; break; }\n                }\n                if (!ok) break;\n                decChain(s, c);\n            }\n        }\n    }\n\n    // Exact completion when uncovered Oni <= 10\n    bool exactRepairSmall(State &s) {\n        int k = __builtin_popcountll(s.unsatMask);\n        if (k == 0) return true;\n        if (k > 10) return false;\n\n        vector<int> uns;\n        uns.reserve(k);\n        int loc[MAXM];\n        for (int i = 0; i < MAXM; i++) loc[i] = -1;\n\n        uint64_t bits = s.unsatMask;\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            loc[m] = (int)uns.size();\n            uns.push_back(m);\n        }\n\n        int S = 1 << k;\n        const int INF = 1e9;\n\n        static int dp[1 << 10], ndp[1 << 10];\n        struct Parent { uint16_t prev; uint8_t dep; uint8_t used; };\n        static Parent par[MAXC + 1][1 << 10];\n\n        for (int mask = 0; mask < S; mask++) dp[mask] = INF;\n        dp[0] = 0;\n\n        for (int c = 0; c < Cn; c++) {\n            for (int mask = 0; mask < S; mask++) ndp[mask] = INF;\n\n            // not use chain c\n            for (int mask = 0; mask < S; mask++) {\n                if (dp[mask] < ndp[mask]) {\n                    ndp[mask] = dp[mask];\n                    par[c + 1][mask] = {(uint16_t)mask, 0, 0};\n                }\n            }\n\n            if ((int)s.d[c] < cap[c]) {\n                static int bestCost[1 << 10];\n                static uint8_t bestDep[1 << 10];\n                for (int i = 0; i < S; i++) {\n                    bestCost[i] = INF;\n                    bestDep[i] = 0;\n                }\n\n                for (int r = (int)s.d[c] + 1; r <= cap[c]; r++) {\n                    uint64_t gm = leMask[c][r] & s.unsatMask;\n                    if (!gm) continue;\n                    int lm = 0;\n                    uint64_t t = gm;\n                    while (t) {\n                        int m = __builtin_ctzll(t);\n                        t &= t - 1;\n                        lm |= (1 << loc[m]);\n                    }\n                    int add = r - (int)s.d[c];\n                    if (add < bestCost[lm]) {\n                        bestCost[lm] = add;\n                        bestDep[lm] = (uint8_t)r;\n                    }\n                }\n\n                vector<tuple<int,int,uint8_t>> cand;\n                cand.reserve(S);\n                for (int lm = 1; lm < S; lm++) {\n                    if (bestCost[lm] < INF) cand.emplace_back(lm, bestCost[lm], bestDep[lm]);\n                }\n\n                for (int mask = 0; mask < S; mask++) {\n                    if (dp[mask] >= INF) continue;\n                    for (auto [lm, add, dep] : cand) {\n                        int nm = mask | lm;\n                        int val = dp[mask] + add;\n                        if (val < ndp[nm]) {\n                            ndp[nm] = val;\n                            par[c + 1][nm] = {(uint16_t)mask, dep, 1};\n                        }\n                    }\n                }\n            }\n\n            for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n        }\n\n        int target = S - 1;\n        if (dp[target] >= INF) return false;\n\n        array<uint8_t, MAXC> tgt = s.d;\n        int mask = target;\n        for (int c = Cn; c >= 1; c--) {\n            auto p = par[c][mask];\n            if (p.used) {\n                int chain = c - 1;\n                tgt[chain] = max<int>(tgt[chain], p.dep);\n            }\n            mask = p.prev;\n        }\n\n        for (int c = 0; c < Cn; c++) setChain(s, c, tgt[c]);\n        return (s.unsatMask == 0);\n    }\n\n    void greedyRepair(State &s, bool randomized) {\n        while (s.unsatMask) {\n            int unsCnt = __builtin_popcountll(s.unsatMask);\n            if (unsCnt <= 10) {\n                if (exactRepairSmall(s)) return;\n            }\n\n            double bestScore = -1e100;\n            int bc = -1, br = -1;\n            int bg = -1, bdelta = 1e9;\n\n            for (int c = 0; c < Cn; c++) {\n                int dc = (int)s.d[c];\n                if (dc >= cap[c]) continue;\n\n                for (int r : usefulDepths[c]) {\n                    if (r <= dc) continue;\n                    uint64_t gainMask = leMask[c][r] & s.unsatMask;\n                    int g = __builtin_popcountll(gainMask);\n                    if (g == 0) continue;\n                    int delta = r - dc;\n                    double score = (double)g / (double)delta;\n                    if (randomized) score += (double)(rng() & 1023) * 1e-6;\n\n                    if (score > bestScore + 1e-12 ||\n                        (fabs(score - bestScore) <= 1e-12 && (g > bg || (g == bg && delta < bdelta)))) {\n                        bestScore = score;\n                        bc = c; br = r;\n                        bg = g; bdelta = delta;\n                    }\n                }\n            }\n\n            if (bc == -1) {\n                int m = __builtin_ctzll(s.unsatMask);\n                int bestDelta = 1e9;\n                for (auto &op : opts[m]) {\n                    int delta = max(0, op.req - (int)s.d[op.chain]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bc = op.chain;\n                        br = op.req;\n                    }\n                }\n                if (bc == -1) break;\n            }\n\n            setChain(s, bc, br);\n        }\n    }\n\n    // ---------- objective proxy ----------\n    int rowSave(const State &s) const {\n        int sv = 0;\n        for (int i = 0; i < N; i++) {\n            int l = s.d[idLeft(i)];\n            int r = s.d[idRight(i)];\n            if (l == 0 || r == 0) sv += l + r;\n            else sv += max(l, r);\n        }\n        return sv;\n    }\n    int colSave(const State &s) const {\n        int sv = 0;\n        for (int j = 0; j < N; j++) {\n            int u = s.d[idUp(j)];\n            int d = s.d[idDown(j)];\n            if (u == 0 || d == 0) sv += u + d;\n            else sv += max(u, d);\n        }\n        return sv;\n    }\n    int estimateMoves(const State &s) const {\n        return s.cost - max(rowSave(s), colSave(s));\n    }\n\n    // ---------- constructors for candidate states ----------\n    State baselineMinReq() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            depth[op.chain] = max<int>(depth[op.chain], op.req);\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, false);\n        return s;\n    }\n\n    State trialAssign() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n        stable_sort(ord.begin(), ord.end(),\n                    [&](int a, int b){ return opts[a].size() < opts[b].size(); });\n\n        for (int m : ord) {\n            int choose = 0;\n            if ((int)(rng() % 100) < 10) {\n                choose = (int)(rng() % opts[m].size());\n            } else {\n                int bestKey = 1e9;\n                vector<int> cand;\n                for (int i = 0; i < (int)opts[m].size(); i++) {\n                    auto op = opts[m][i];\n                    int delta = max(0, op.req - (int)depth[op.chain]);\n                    int key = delta * 64 + op.req;\n                    if (key < bestKey) {\n                        bestKey = key;\n                        cand.clear();\n                        cand.push_back(i);\n                    } else if (key == bestKey) {\n                        cand.push_back(i);\n                    }\n                }\n                choose = cand[(int)(rng() % cand.size())];\n            }\n            auto op = opts[m][choose];\n            if (op.req > depth[op.chain]) depth[op.chain] = (uint8_t)op.req;\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, true);\n        if ((rng() % 100) < 30) reduceDepth(s, true);\n        return s;\n    }\n\n    State trialCover(bool randomized) {\n        State s = makeZeroState();\n        greedyRepair(s, randomized);\n        if (s.unsatMask == 0) {\n            reduceDepth(s, true);\n            if (randomized && (rng() % 100) < 30) reduceDepth(s, true);\n        }\n        return s;\n    }\n\n    int pickNonZeroChain(const State &s) {\n        for (int t = 0; t < 24; t++) {\n            int c = (int)(rng() % Cn);\n            if (s.d[c] > 0) return c;\n        }\n        int cnt = 0;\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) cnt++;\n        if (cnt == 0) return -1;\n        int k = (int)(rng() % cnt);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) {\n            if (k-- == 0) return c;\n        }\n        return -1;\n    }\n\n    State optimizeDepth(double endTime) {\n        State best = baselineMinReq();\n        int bestObj = estimateMoves(best);\n\n        State c0 = trialCover(false);\n        if (c0.unsatMask == 0) {\n            int o = estimateMoves(c0);\n            if (o < bestObj || (o == bestObj && c0.cost < best.cost)) {\n                best = c0; bestObj = o;\n            }\n        }\n\n        double initEnd = min(endTime, 0.30);\n        int initIter = 0;\n        while (now() < initEnd) {\n            State cand = (initIter & 1) ? trialAssign() : trialCover(true);\n            initIter++;\n            if (cand.unsatMask) continue;\n            int obj = estimateMoves(cand);\n            if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                best = cand; bestObj = obj;\n            }\n        }\n\n        State cur = best;\n        int curObj = bestObj;\n        int iter = 0;\n\n        while (now() < endTime) {\n            iter++;\n            State cand = cur;\n\n            int k = 1 + (int)(rng() % 4);\n            if ((rng() % 100) < 20) k++;\n            for (int t = 0; t < k; t++) {\n                int c = pickNonZeroChain(cand);\n                if (c < 0) break;\n                int old = cand.d[c];\n                int nd;\n                int r = (int)(rng() % 100);\n                if (r < 55) nd = old - 1;\n                else if (r < 85) {\n                    int dec = 1 + (int)(rng() % max(1, min(4, old)));\n                    nd = max(0, old - dec);\n                } else nd = (int)(rng() % (old + 1));\n                setChain(cand, c, nd);\n            }\n\n            if ((rng() % 100) < 10) {\n                int c = (int)(rng() % Cn);\n                if ((int)cand.d[c] < cap[c]) {\n                    int nd = min(cap[c], (int)cand.d[c] + 1 + (int)(rng() % 3));\n                    setChain(cand, c, nd);\n                }\n            }\n\n            greedyRepair(cand, true);\n            if (cand.unsatMask) continue;\n\n            reduceDepth(cand, true);\n            if ((rng() % 100) < 35) reduceDepth(cand, true);\n\n            int candObj = estimateMoves(cand);\n            double prog = min(1.0, now() / max(1e-9, endTime));\n            double temp = 4.5 * pow(0.05 / 4.5, prog);\n            int delta = candObj - curObj;\n\n            bool accept = false;\n            if (delta <= 0) accept = true;\n            else {\n                double prob = exp(-(double)delta / temp);\n                if (rand01() < prob) accept = true;\n            }\n\n            if (accept) {\n                cur = cand;\n                curObj = candObj;\n            }\n            if (candObj < bestObj || (candObj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = candObj;\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if ((iter % 350) == 0 && (rng() % 100) < 50) {\n                cur = best;\n                curObj = bestObj;\n            }\n            if ((iter % 500) == 0 && now() < endTime && (rng() % 100) < 25) {\n                State rst = (rng() & 1) ? trialAssign() : trialCover(true);\n                if (rst.unsatMask == 0) {\n                    int ro = estimateMoves(rst);\n                    if (ro < curObj || rand01() < 0.2) { cur = rst; curObj = ro; }\n                    if (ro < bestObj || (ro == bestObj && rst.cost < best.cost)) {\n                        best = rst; bestObj = ro;\n                    }\n                }\n            }\n        }\n\n        bool improved = true;\n        while (improved && now() < endTime) {\n            improved = false;\n            vector<int> ord(Cn);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b){ return best.d[a] > best.d[b]; });\n\n            for (int c : ord) {\n                if (now() >= endTime) break;\n                if (best.d[c] == 0) continue;\n                State cand = best;\n                setChain(cand, c, 0);\n                greedyRepair(cand, false);\n                if (cand.unsatMask) continue;\n                reduceDepth(cand, true);\n                int obj = estimateMoves(cand);\n                if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                    best = cand;\n                    bestObj = obj;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    // ---------- simulation ----------\n    inline bool applyShift(Grid &g, char d, int p, int &oniLeft) const {\n        char out = '.';\n        if (d == 'L') {\n            out = g[p][0];\n            for (int j = 0; j + 1 < N; j++) g[p][j] = g[p][j + 1];\n            g[p][N - 1] = '.';\n        } else if (d == 'R') {\n            out = g[p][N - 1];\n            for (int j = N - 1; j >= 1; j--) g[p][j] = g[p][j - 1];\n            g[p][0] = '.';\n        } else if (d == 'U') {\n            out = g[0][p];\n            for (int i = 0; i + 1 < N; i++) g[i][p] = g[i + 1][p];\n            g[N - 1][p] = '.';\n        } else { // D\n            out = g[N - 1][p];\n            for (int i = N - 1; i >= 1; i--) g[i][p] = g[i - 1][p];\n            g[0][p] = '.';\n        }\n\n        if (out == 'o') return false;\n        if (out == 'x') oniLeft--;\n        return true;\n    }\n\n    bool checkOpsValid(const vector<Op>& ops) const {\n        if ((int)ops.size() > 4 * N * N) return false;\n        Grid g = initGrid;\n        int oniLeft = M;\n        for (auto [d, p] : ops) {\n            if (!applyShift(g, d, p, oniLeft)) return false;\n        }\n        return oniLeft == 0;\n    }\n\n    bool checkPlanValid(const State &s, const UPlan &p) const {\n        if (s.cost - p.save > 4 * N * N) return false;\n        Grid g = initGrid;\n        int oniLeft = M;\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c]) continue;\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].dir, chains[c].idx, oniLeft)) return false;\n            }\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].rev, chains[c].idx, oniLeft)) return false;\n            }\n        }\n\n        for (int c : p.ord) {\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].dir, chains[c].idx, oniLeft)) return false;\n            }\n        }\n\n        return oniLeft == 0;\n    }\n\n    // ---------- unpair plan ----------\n    UPlan emptyPlan() const {\n        UPlan p;\n        p.in.fill(0);\n        p.ord.clear();\n        p.save = 0;\n        return p;\n    }\n\n    int computeSave(const State &s, const UPlan &p) const {\n        int sv = 0;\n        for (int c : p.ord) sv += s.d[c];\n        return sv;\n    }\n\n    void sanitizePlan(UPlan &p, const State &s) const {\n        array<uint8_t, MAXC> used{};\n        used.fill(0);\n        vector<int> v;\n        v.reserve(p.ord.size());\n        for (int c : p.ord) {\n            if (c < 0 || c >= Cn) continue;\n            if (used[c]) continue;\n            if (s.d[c] == 0) continue;\n            used[c] = 1;\n            v.push_back(c);\n        }\n        p.ord.swap(v);\n        p.in.fill(0);\n        for (int c : p.ord) p.in[c] = 1;\n        p.save = computeSave(s, p);\n    }\n\n    UPlan makeRowPlan(const State &s, bool tieRight) const {\n        UPlan p = emptyPlan();\n        for (int i = 0; i < N; i++) {\n            int lc = idLeft(i), rc = idRight(i);\n            int l = s.d[lc], r = s.d[rc];\n            if (l == 0 && r == 0) continue;\n            int ch;\n            if (l > r) ch = lc;\n            else if (r > l) ch = rc;\n            else ch = tieRight ? rc : lc;\n            if (s.d[ch] > 0) {\n                p.ord.push_back(ch);\n                p.in[ch] = 1;\n            }\n        }\n        p.save = computeSave(s, p);\n        return p;\n    }\n\n    UPlan makeColPlan(const State &s, bool tieDown) const {\n        UPlan p = emptyPlan();\n        for (int j = 0; j < N; j++) {\n            int uc = idUp(j), dc = idDown(j);\n            int u = s.d[uc], d = s.d[dc];\n            if (u == 0 && d == 0) continue;\n            int ch;\n            if (u > d) ch = uc;\n            else if (d > u) ch = dc;\n            else ch = tieDown ? dc : uc;\n            if (s.d[ch] > 0) {\n                p.ord.push_back(ch);\n                p.in[ch] = 1;\n            }\n        }\n        p.save = computeSave(s, p);\n        return p;\n    }\n\n    int pickNotIn(const UPlan &p, const vector<int> &active) {\n        if ((int)p.ord.size() >= (int)active.size()) return -1;\n        for (int t = 0; t < 24; t++) {\n            int c = active[(int)(rng() % active.size())];\n            if (!p.in[c]) return c;\n        }\n        for (int c : active) if (!p.in[c]) return c;\n        return -1;\n    }\n\n    UPlan optimizeUnpair(const State &s, double endTime, const UPlan *seed) {\n        vector<UPlan> seeds;\n        seeds.reserve(8);\n        seeds.push_back(emptyPlan());\n        seeds.push_back(makeRowPlan(s, false));\n        seeds.push_back(makeRowPlan(s, true));\n        seeds.push_back(makeColPlan(s, false));\n        seeds.push_back(makeColPlan(s, true));\n        if (seed) seeds.push_back(*seed);\n\n        UPlan best = emptyPlan();\n        bool hasBest = false;\n\n        for (auto &p : seeds) {\n            if (now() >= endTime) break;\n            sanitizePlan(p, s);\n            if (checkPlanValid(s, p)) {\n                if (!hasBest || p.save > best.save) {\n                    best = p;\n                    hasBest = true;\n                }\n            }\n        }\n        if (!hasBest) return emptyPlan();\n\n        vector<int> active;\n        active.reserve(Cn);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) active.push_back(c);\n\n        if (active.empty()) return best;\n\n        // Greedy add\n        UPlan cur = best;\n        double greedyEnd = min(endTime, now() + (endTime - now()) * 0.40);\n\n        while (now() < greedyEnd) {\n            bool improved = false;\n            vector<int> cand;\n            cand.reserve(active.size());\n            for (int c : active) if (!cur.in[c]) cand.push_back(c);\n            if (cand.empty()) break;\n\n            shuffle(cand.begin(), cand.end(), rng);\n            sort(cand.begin(), cand.end(),\n                 [&](int a, int b) {\n                     if (s.d[a] != s.d[b]) return s.d[a] > s.d[b];\n                     return a < b;\n                 });\n\n            for (int c : cand) {\n                if (now() >= greedyEnd) break;\n                int sz = (int)cur.ord.size();\n\n                vector<int> pos;\n                pos.reserve(sz + 1);\n                pos.push_back(sz);      // end first (least disturbance)\n                if (sz > 0) pos.push_back(0);\n                for (int i = 1; i < sz; i++) pos.push_back(i);\n                if ((int)pos.size() > 2) shuffle(pos.begin() + 2, pos.end(), rng);\n\n                bool ok = false;\n                for (int pidx : pos) {\n                    UPlan q = cur;\n                    q.ord.insert(q.ord.begin() + pidx, c);\n                    q.in[c] = 1;\n                    q.save = computeSave(s, q);\n                    if (checkPlanValid(s, q)) {\n                        cur = move(q);\n                        if (cur.save > best.save) best = cur;\n                        improved = true;\n                        ok = true;\n                        break;\n                    }\n                }\n                if (ok) break;\n            }\n\n            if (!improved) break;\n        }\n\n        // SA / local search on set+order\n        cur = best;\n        double saStart = now();\n\n        while (now() < endTime) {\n            UPlan cand = cur;\n            bool moved = false;\n            int typ = (int)(rng() % 100);\n            int sz = (int)cand.ord.size();\n\n            if (typ < 35) { // add\n                int c = pickNotIn(cand, active);\n                if (c != -1) {\n                    int pos = (int)(rng() % (sz + 1));\n                    cand.ord.insert(cand.ord.begin() + pos, c);\n                    cand.in[c] = 1;\n                    moved = true;\n                }\n            } else if (typ < 55) { // remove\n                if (sz > 0) {\n                    int idx = (int)(rng() % sz);\n                    int c = cand.ord[idx];\n                    cand.ord.erase(cand.ord.begin() + idx);\n                    cand.in[c] = 0;\n                    moved = true;\n                }\n            } else if (typ < 75) { // swap\n                if (sz >= 2) {\n                    int i = (int)(rng() % sz), j = (int)(rng() % sz);\n                    if (i != j) {\n                        swap(cand.ord[i], cand.ord[j]);\n                        moved = true;\n                    }\n                }\n            } else if (typ < 90) { // move\n                if (sz >= 2) {\n                    int i = (int)(rng() % sz);\n                    int c = cand.ord[i];\n                    cand.ord.erase(cand.ord.begin() + i);\n                    int pos = (int)(rng() % sz); // [0..sz-1], after erase size is sz-1\n                    cand.ord.insert(cand.ord.begin() + pos, c);\n                    moved = true;\n                }\n            } else { // replace\n                if (sz > 0) {\n                    int idx = (int)(rng() % sz);\n                    int oldc = cand.ord[idx];\n                    cand.ord.erase(cand.ord.begin() + idx);\n                    cand.in[oldc] = 0;\n                    int nc = pickNotIn(cand, active);\n                    if (nc != -1) {\n                        int pos = (int)(rng() % ((int)cand.ord.size() + 1));\n                        cand.ord.insert(cand.ord.begin() + pos, nc);\n                        cand.in[nc] = 1;\n                        moved = true;\n                    } else {\n                        cand.ord.insert(cand.ord.begin() + idx, oldc);\n                        cand.in[oldc] = 1;\n                    }\n                }\n            }\n\n            if (!moved) continue;\n\n            cand.save = computeSave(s, cand);\n            if (!checkPlanValid(s, cand)) continue;\n\n            int delta = cand.save - cur.save;\n            double denom = max(1e-9, endTime - saStart);\n            double rem = (endTime - now()) / denom;\n            rem = max(0.0, min(1.0, rem));\n            double temp = 1.5 * rem + 0.03;\n\n            if (delta >= 0 || rand01() < exp((double)delta / temp)) {\n                cur = cand;\n            }\n            if (cand.save > best.save) best = cand;\n        }\n\n        sanitizePlan(best, s);\n        return best;\n    }\n\n    void exactDepthShrink(State &s, UPlan &p, double endTime) {\n        sanitizePlan(p, s);\n        if (!checkPlanValid(s, p)) return;\n\n        bool improved = true;\n        while (improved && now() < endTime) {\n            improved = false;\n            vector<int> ord(Cn);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b){ return s.d[a] > s.d[b]; });\n\n            for (int c : ord) {\n                if (now() >= endTime) break;\n                while (s.d[c] > 0 && now() < endTime) {\n                    State cand = s;\n                    setChain(cand, c, (int)s.d[c] - 1);\n\n                    UPlan q = p;\n                    if (q.in[c] && cand.d[c] == 0) {\n                        q.in[c] = 0;\n                        for (int i = 0; i < (int)q.ord.size(); i++) {\n                            if (q.ord[i] == c) {\n                                q.ord.erase(q.ord.begin() + i);\n                                break;\n                            }\n                        }\n                    }\n                    sanitizePlan(q, cand);\n\n                    if (checkPlanValid(cand, q)) {\n                        s = move(cand);\n                        p = move(q);\n                        improved = true;\n                    } else break;\n                }\n            }\n        }\n\n        sanitizePlan(p, s);\n    }\n\n    // ---------- build / prune ----------\n    vector<Op> buildOps(const State &s, const UPlan &p) const {\n        vector<Op> ops;\n        ops.reserve(max(0, s.cost - p.save) + 16);\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c]) continue;\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].rev, chains[c].idx});\n        }\n        for (int c : p.ord) {\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n        }\n        return ops;\n    }\n\n    void pruneOps(vector<Op> &ops, double endTime) {\n        if (!checkOpsValid(ops)) return;\n\n        bool changed = true;\n        while (changed && now() < endTime) {\n            changed = false;\n\n            // backward single deletion\n            for (int i = (int)ops.size() - 1; i >= 0 && now() < endTime; --i) {\n                Op tmp = ops[i];\n                ops.erase(ops.begin() + i);\n                if (checkOpsValid(ops)) {\n                    changed = true;\n                } else {\n                    ops.insert(ops.begin() + i, tmp);\n                }\n            }\n\n            // forward single deletion\n            for (int i = 0; i < (int)ops.size() && now() < endTime; ) {\n                Op tmp = ops[i];\n                ops.erase(ops.begin() + i);\n                if (checkOpsValid(ops)) {\n                    changed = true;\n                } else {\n                    ops.insert(ops.begin() + i, tmp);\n                    i++;\n                }\n            }\n\n            // consecutive pair deletion (light)\n            for (int i = (int)ops.size() - 2; i >= 0 && now() < endTime; --i) {\n                Op a = ops[i], b = ops[i + 1];\n                ops.erase(ops.begin() + i, ops.begin() + i + 2);\n                if (checkOpsValid(ops)) {\n                    changed = true;\n                } else {\n                    ops.insert(ops.begin() + i, b);\n                    ops.insert(ops.begin() + i, a);\n                }\n            }\n        }\n    }\n\n    vector<Op> fallbackPerOni() const {\n        vector<Op> ops;\n        ops.reserve(1600);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            const auto &ch = chains[op.chain];\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.dir, ch.idx});\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.rev, ch.idx});\n        }\n        return ops;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    Solver solver(N, C);\n    auto ans = solver.solve();\n\n    for (auto [d, p] : ans) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\nstatic inline long long absl(long long x) { return x < 0 ? -x : x; }\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstatic inline int sample_weighted(const uint64_t* w, int n, RNG& rng) {\n    uint64_t sum = 0;\n    for (int i = 0; i < n; i++) sum += w[i];\n    if (sum == 0) return rng.nextInt(n);\n    uint64_t r = rng.nextU64() % sum;\n    uint64_t acc = 0;\n    for (int i = 0; i < n; i++) {\n        acc += w[i];\n        if (r < acc) return i;\n    }\n    return n - 1;\n}\n\nstruct State {\n    array<int, MAXN> a{}, b{};\n    array<int, MAXN> cnt{}, useA{}, useB{};\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstatic inline void shuffle_order(array<int, MAXN>& ord, int N, RNG& rng) {\n    for (int i = N - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nstatic long long simulate(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N, int L,\n    const array<int, MAXN>& T,\n    array<int, MAXN>& cnt,\n    array<int, MAXN>& useA,\n    array<int, MAXN>& useB,\n    int& last\n) {\n    for (int i = 0; i < N; i++) cnt[i] = 0;\n    int cur = 0;\n    cnt[0] = 1;\n\n    for (int step = 1; step < L; step++) {\n        int s = cur;\n        if (cnt[s] & 1) cur = a[s];\n        else cur = b[s];\n        cnt[cur]++;\n    }\n    last = cur;\n\n    for (int i = 0; i < N; i++) {\n        int dep = cnt[i] - (i == last ? 1 : 0);\n        if (dep < 0) dep = 0;\n        useA[i] = (dep + 1) >> 1;\n        useB[i] = dep >> 1;\n    }\n\n    long long e = 0;\n    for (int i = 0; i < N; i++) e += absl((long long)cnt[i] - T[i]);\n    return e;\n}\n\nstatic inline void set_cycle_from_order(\n    const array<int, MAXN>& ord, int N, array<int, MAXN>& a\n) {\n    for (int k = 0; k < N; k++) {\n        int u = ord[k];\n        int v = ord[(k + 1) % N];\n        a[u] = v;\n    }\n}\n\nstatic long long hungarian(\n    int n,\n    int cost[MAXN][MAXN],\n    array<int, MAXN>& assignment\n) {\n    const long long INF = (1LL << 60);\n    static long long u[MAXN + 1], v[MAXN + 1], minv[MAXN + 1];\n    static int p[MAXN + 1], way[MAXN + 1];\n    static unsigned char used[MAXN + 1];\n\n    for (int i = 0; i <= n; i++) {\n        u[i] = v[i] = 0;\n        p[i] = way[i] = 0;\n    }\n\n    for (int i = 1; i <= n; i++) {\n        p[0] = i;\n        for (int j = 0; j <= n; j++) {\n            minv[j] = INF;\n            used[j] = 0;\n        }\n        int j0 = 0;\n        do {\n            used[j0] = 1;\n            int i0 = p[j0], j1 = 0;\n            long long delta = INF;\n            for (int j = 1; j <= n; j++) if (!used[j]) {\n                long long cur = (long long)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 <= n; 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    for (int j = 1; j <= n; j++) assignment[p[j] - 1] = j - 1;\n    return -v[0];\n}\n\nstatic void local_improve_b_with_rem(\n    array<int, MAXN>& b,\n    array<long long, MAXN>& rem,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    int passes\n) {\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool improved = false;\n        shuffle_order(ord, N, rng);\n\n        for (int z = 0; z < N; z++) {\n            int s = ord[z];\n            long long w = T[s];\n            int old = b[s];\n\n            int best = old;\n            long long bestDelta = 0;\n            long long absOld = absl(rem[old]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == old) continue;\n                long long delta =\n                    absl(rem[old] + w) + absl(rem[d] - w) - absOld - absl(rem[d]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = d;\n                }\n            }\n\n            if (best != old) {\n                rem[old] += w;\n                rem[best] -= w;\n                b[s] = best;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nstatic void optimize_b_given_a_greedy(\n    const array<int, MAXN>& a,\n    int N,\n    const array<int, MAXN>& T,\n    const array<int, MAXN>& srcDesc,\n    RNG& rng,\n    array<int, MAXN>& b,\n    int randomness = 1\n) {\n    array<long long, MAXN> rem{};\n    for (int i = 0; i < N; i++) rem[i] = 2LL * T[i];\n    for (int s = 0; s < N; s++) rem[a[s]] -= T[s];\n\n    for (int k = 0; k < N; k++) {\n        int s = srcDesc[k];\n        long long w = T[s];\n\n        int best = 0, second = 0;\n        long long vBest = absl(rem[0] - w), vSecond = (1LL << 60);\n\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] - w);\n            if (v < vBest) {\n                second = best;\n                vSecond = vBest;\n                best = d;\n                vBest = v;\n            } else if (v < vSecond) {\n                second = d;\n                vSecond = v;\n            }\n        }\n\n        int chosen = best;\n        if (randomness > 0 && second != best && rng.nextDouble() < 0.10 * randomness) {\n            chosen = second;\n        }\n\n        b[s] = chosen;\n        rem[chosen] -= w;\n    }\n\n    local_improve_b_with_rem(b, rem, N, T, rng, 5);\n}\n\nstatic void build_b_hungarian_given_a(\n    const array<int, MAXN>& a,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& b,\n    bool relax\n) {\n    array<int, MAXN> indeg{};\n    for (int i = 0; i < N; i++) indeg[a[i]]++;\n    bool perm = true;\n    for (int i = 0; i < N; i++) if (indeg[i] != 1) { perm = false; break; }\n\n    if (!perm) {\n        array<int, MAXN> srcDesc{};\n        iota(srcDesc.begin(), srcDesc.begin() + N, 0);\n        sort(srcDesc.begin(), srcDesc.begin() + N, [&](int x, int y) {\n            if (T[x] != T[y]) return T[x] > T[y];\n            return x < y;\n        });\n        optimize_b_given_a_greedy(a, N, T, srcDesc, rng, b, 1);\n        return;\n    }\n\n    array<int, MAXN> pred{};\n    for (int s = 0; s < N; s++) pred[a[s]] = s;\n\n    static int cost[MAXN][MAXN];\n    for (int s = 0; s < N; s++) {\n        for (int d = 0; d < N; d++) {\n            cost[s][d] = (int)absl((long long)T[s] + T[pred[d]] - 2LL * T[d]);\n        }\n    }\n\n    array<int, MAXN> assign{};\n    hungarian(N, cost, assign);\n    for (int s = 0; s < N; s++) b[s] = assign[s];\n\n    if (relax) {\n        array<long long, MAXN> rem{};\n        for (int i = 0; i < N; i++) rem[i] = 2LL * T[i];\n        for (int s = 0; s < N; s++) rem[a[s]] -= T[s];\n        for (int s = 0; s < N; s++) rem[b[s]] -= T[s];\n        local_improve_b_with_rem(b, rem, N, T, rng, 3);\n    }\n}\n\nstatic void build_cycle_greedy(\n    const array<int, MAXN>& ord,\n    int N,\n    const array<int, MAXN>& T,\n    const array<int, MAXN>& srcDesc,\n    RNG& rng,\n    array<int, MAXN>& a,\n    array<int, MAXN>& b\n) {\n    set_cycle_from_order(ord, N, a);\n    optimize_b_given_a_greedy(a, N, T, srcDesc, rng, b, 1);\n}\n\nstatic void build_cycle_hungarian(\n    const array<int, MAXN>& ord,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& a,\n    array<int, MAXN>& b,\n    bool relax\n) {\n    set_cycle_from_order(ord, N, a);\n    build_b_hungarian_given_a(a, N, T, rng, b, relax);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    array<int, MAXN> T{};\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    uint64_t seed = (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n    for (int i = 0; i < N; i++) {\n        seed ^= (uint64_t)(T[i] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2));\n    }\n    RNG rng(seed);\n\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    const double TL = 1.90;\n    const double INIT_END = 0.62;\n    const double SA_END = 1.84;\n\n    // Prepare base orders\n    array<int, MAXN> ordNatural{}, ordAsc{}, ordDesc{}, ordMountain{}, ordMountainRev{};\n    for (int i = 0; i < N; i++) ordNatural[i] = i;\n\n    vector<int> idx(N);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        if (T[x] != T[y]) return T[x] < T[y];\n        return x < y;\n    });\n    for (int i = 0; i < N; i++) ordAsc[i] = idx[i];\n    for (int i = 0; i < N; i++) ordDesc[i] = idx[N - 1 - i];\n\n    {\n        int l = 0, r = N - 1, p = 0;\n        while (l <= r) {\n            ordMountain[p++] = ordAsc[l++];\n            if (l <= r) ordMountain[p++] = ordAsc[r--];\n        }\n    }\n    for (int i = 0; i < N; i++) ordMountainRev[i] = ordMountain[N - 1 - i];\n\n    array<int, MAXN> srcDesc = ordDesc;\n\n    vector<array<int, MAXN>> baseOrders;\n    baseOrders.push_back(ordNatural);\n    baseOrders.push_back(ordAsc);\n    baseOrders.push_back(ordDesc);\n    baseOrders.push_back(ordMountain);\n    baseOrders.push_back(ordMountainRev);\n\n    State best;\n    best.err = (1LL << 60);\n    vector<State> pool;\n    pool.reserve(8);\n\n    auto add_pool = [&](const State& s) {\n        pool.push_back(s);\n        sort(pool.begin(), pool.end(), [&](const State& x, const State& y) {\n            return x.err < y.err;\n        });\n        if ((int)pool.size() > 8) pool.resize(8);\n    };\n\n    auto evaluate_candidate = [&](const array<int, MAXN>& a, const array<int, MAXN>& b) -> long long {\n        State s;\n        s.a = a;\n        s.b = b;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) best = s;\n        add_pool(s);\n        return s.err;\n    };\n\n    array<int, MAXN> candA{}, candB{};\n    array<int, MAXN> bestOrder = ordAsc;\n    long long bestOrderErr = (1LL << 60);\n\n    // deterministic initialization\n    for (const auto& ord : baseOrders) {\n        build_cycle_greedy(ord, N, T, srcDesc, rng, candA, candB);\n        long long e0 = evaluate_candidate(candA, candB);\n        if (e0 < bestOrderErr) { bestOrderErr = e0; bestOrder = ord; }\n\n        build_cycle_hungarian(ord, N, T, rng, candA, candB, false);\n        long long e1 = evaluate_candidate(candA, candB);\n        if (e1 < bestOrderErr) { bestOrderErr = e1; bestOrder = ord; }\n\n        build_cycle_hungarian(ord, N, T, rng, candA, candB, true);\n        long long e2 = evaluate_candidate(candA, candB);\n        if (e2 < bestOrderErr) { bestOrderErr = e2; bestOrder = ord; }\n    }\n\n    // randomized initialization\n    while (elapsed() < INIT_END) {\n        array<int, MAXN> ord{};\n        if (rng.nextDouble() < 0.55) ord = bestOrder;\n        else ord = baseOrders[rng.nextInt((int)baseOrders.size())];\n\n        int swaps = 1 + rng.nextInt(20);\n        for (int s = 0; s < swaps; s++) {\n            int i = rng.nextInt(N);\n            int j = rng.nextInt(N);\n            swap(ord[i], ord[j]);\n        }\n        if (rng.nextDouble() < 0.28) {\n            int l = rng.nextInt(N), r = rng.nextInt(N);\n            if (l > r) swap(l, r);\n            reverse(ord.begin() + l, ord.begin() + r + 1);\n        }\n        if (rng.nextDouble() < 0.07) {\n            shuffle_order(ord, N, rng);\n        }\n\n        int mode = rng.nextInt(3);\n        if (mode == 0) build_cycle_greedy(ord, N, T, srcDesc, rng, candA, candB);\n        else if (mode == 1) build_cycle_hungarian(ord, N, T, rng, candA, candB, false);\n        else build_cycle_hungarian(ord, N, T, rng, candA, candB, true);\n\n        long long e = evaluate_candidate(candA, candB);\n        if (e < bestOrderErr) {\n            bestOrderErr = e;\n            bestOrder = ord;\n        }\n    }\n\n    if (pool.empty()) add_pool(best);\n    State cur = best;\n\n    array<int, MAXN> trialA{}, trialB{};\n    array<int, MAXN> tmpCnt{}, tmpUseA{}, tmpUseB{};\n    int tmpLast = 0;\n\n    array<uint64_t, MAXN> w1{}, w2{};\n\n    double saStart = elapsed();\n    double saSpan = max(1e-9, SA_END - saStart);\n    long long iter = 0, lastImprove = 0;\n\n    while (elapsed() < SA_END) {\n        iter++;\n\n        if ((iter & 255LL) == 0 && !pool.empty()) {\n            if (cur.err > best.err + 1800 || (iter - lastImprove > 700 && rng.nextDouble() < 0.35)) {\n                cur = pool[rng.nextInt((int)pool.size())];\n            }\n        }\n\n        double prog = (elapsed() - saStart) / saSpan;\n        if (prog < 0.0) prog = 0.0;\n        if (prog > 1.0) prog = 1.0;\n        double temp = 1700.0 * (1.0 - prog) + 3.0;\n\n        trialA = cur.a;\n        trialB = cur.b;\n        bool changed = false;\n\n        double rr = rng.nextDouble();\n\n        if (rr < 0.45) {\n            // guided single change on b\n            for (int i = 0; i < N; i++) {\n                int dst = cur.b[i];\n                int over = cur.cnt[dst] - T[dst];\n                if (over < 0) over = 0;\n                w1[i] = (uint64_t)(cur.useB[i] + 1) * (uint64_t)(over + 1);\n            }\n            int s = sample_weighted(w1.data(), N, rng);\n            int old = cur.b[s];\n            int u = cur.useB[s];\n            if (u == 0 && rng.nextDouble() < 0.90) continue;\n\n            long long dOld = (long long)cur.cnt[old] - T[old];\n            int bestDst = old;\n            long long bestDelta = 0;\n\n            for (int d = 0; d < N; d++) {\n                if (d == old) continue;\n                long long dd = (long long)cur.cnt[d] - T[d];\n                long long delta = absl(dOld - u) + absl(dd + u) - absl(dOld) - absl(dd);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestDst = d;\n                }\n            }\n\n            if (bestDst == old) continue;\n            if (bestDelta > 0 && rng.nextDouble() < (0.70 + 0.22 * prog)) continue;\n            if (bestDelta == 0 && rng.nextDouble() < 0.45) continue;\n\n            trialB[s] = bestDst;\n            changed = true;\n\n        } else if (rr < 0.62) {\n            // random single change on b\n            for (int i = 0; i < N; i++) w1[i] = (uint64_t)(cur.useB[i] + 1);\n            int s = sample_weighted(w1.data(), N, rng);\n            int old = cur.b[s];\n            int u = cur.useB[s];\n            if (u == 0 && rng.nextDouble() < 0.75) continue;\n\n            for (int d = 0; d < N; d++) {\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w2[d] = (uint64_t)(under + 1);\n            }\n            int nd = sample_weighted(w2.data(), N, rng);\n            if (nd == old) continue;\n\n            long long dOld = (long long)cur.cnt[old] - T[old];\n            long long dNew = (long long)cur.cnt[nd] - T[nd];\n            long long pred = absl(dOld - u) + absl(dNew + u) - absl(dOld) - absl(dNew);\n\n            if (pred > 0 && rng.nextDouble() < (0.62 + 0.25 * prog)) continue;\n\n            trialB[s] = nd;\n            changed = true;\n\n        } else if (rr < 0.78) {\n            // swap two b edges\n            for (int i = 0; i < N; i++) {\n                int d = cur.b[i];\n                int over = cur.cnt[d] - T[d];\n                if (over < 0) over = 0;\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w1[i] = (uint64_t)(cur.useB[i] + 1) * (uint64_t)(over + 1);\n                w2[i] = (uint64_t)(cur.useB[i] + 1) * (uint64_t)(under + 1);\n            }\n            int i1 = sample_weighted(w1.data(), N, rng);\n            int i2 = sample_weighted(w2.data(), N, rng);\n            if (i1 == i2) {\n                i2 = rng.nextInt(N - 1);\n                if (i2 >= i1) i2++;\n            }\n\n            int d1 = cur.b[i1], d2 = cur.b[i2];\n            if (d1 == d2) continue;\n\n            int u1 = cur.useB[i1], u2 = cur.useB[i2];\n            long long x1 = (long long)cur.cnt[d1] - T[d1];\n            long long x2 = (long long)cur.cnt[d2] - T[d2];\n\n            long long pred = absl(x1 - u1 + u2) + absl(x2 - u2 + u1) - absl(x1) - absl(x2);\n            if (pred > 0 && rng.nextDouble() < (0.67 + 0.20 * prog)) continue;\n\n            swap(trialB[i1], trialB[i2]);\n            changed = true;\n\n        } else if (rr < 0.88) {\n            // swap two a edges (keeps permutation)\n            for (int i = 0; i < N; i++) {\n                int d = cur.a[i];\n                int over = cur.cnt[d] - T[d];\n                if (over < 0) over = 0;\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w1[i] = (uint64_t)(cur.useA[i] + 1) * (uint64_t)(over + 1);\n                w2[i] = (uint64_t)(cur.useA[i] + 1) * (uint64_t)(under + 1);\n            }\n            int i1 = sample_weighted(w1.data(), N, rng);\n            int i2 = sample_weighted(w2.data(), N, rng);\n            if (i1 == i2) {\n                i2 = rng.nextInt(N - 1);\n                if (i2 >= i1) i2++;\n            }\n\n            int d1 = cur.a[i1], d2 = cur.a[i2];\n            if (d1 == d2) continue;\n\n            int u1 = cur.useA[i1], u2 = cur.useA[i2];\n            long long x1 = (long long)cur.cnt[d1] - T[d1];\n            long long x2 = (long long)cur.cnt[d2] - T[d2];\n\n            long long pred = absl(x1 - u1 + u2) + absl(x2 - u2 + u1) - absl(x1) - absl(x2);\n            if (pred > 0 && rng.nextDouble() < (0.75 + 0.18 * prog)) continue;\n\n            swap(trialA[i1], trialA[i2]);\n            changed = true;\n\n        } else if (rr < 0.96) {\n            // batch guided changes on b\n            array<long long, MAXN> def{};\n            for (int i = 0; i < N; i++) def[i] = (long long)cur.cnt[i] - T[i];\n\n            int steps = 2 + rng.nextInt(5);\n            for (int stp = 0; stp < steps; stp++) {\n                for (int s = 0; s < N; s++) {\n                    int dst = trialB[s];\n                    long long over = def[dst];\n                    if (over < 0) over = 0;\n                    w1[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(over + 1);\n                }\n\n                int s = sample_weighted(w1.data(), N, rng);\n                int old = trialB[s];\n                int u = cur.useB[s];\n                if (u == 0 && rng.nextDouble() < 0.85) continue;\n\n                long long dOld = def[old];\n                int bestDst = old;\n                long long bestDelta = 0;\n\n                for (int d = 0; d < N; d++) {\n                    if (d == old) continue;\n                    long long delta =\n                        absl(dOld - u) + absl(def[d] + u) - absl(dOld) - absl(def[d]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestDst = d;\n                    }\n                }\n\n                if (bestDst != old && (bestDelta < 0 || rng.nextDouble() < 0.12)) {\n                    trialB[s] = bestDst;\n                    def[old] -= u;\n                    def[bestDst] += u;\n                    changed = true;\n                }\n            }\n\n        } else {\n            // large neighborhood rebuild of b\n            if (rng.nextDouble() < 0.58) {\n                optimize_b_given_a_greedy(trialA, N, T, srcDesc, rng, trialB, 1);\n            } else {\n                build_b_hungarian_given_a(trialA, N, T, rng, trialB, true);\n            }\n            for (int i = 0; i < N; i++) {\n                if (trialB[i] != cur.b[i]) { changed = true; break; }\n            }\n        }\n\n        if (!changed) continue;\n\n        long long newErr = simulate(trialA, trialB, N, L, T, tmpCnt, tmpUseA, tmpUseB, tmpLast);\n\n        bool accept = false;\n        if (newErr <= cur.err) accept = true;\n        else {\n            double prob = exp((double)(cur.err - newErr) / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.a = trialA;\n            cur.b = trialB;\n            cur.err = newErr;\n            cur.cnt = tmpCnt;\n            cur.useA = tmpUseA;\n            cur.useB = tmpUseB;\n            cur.last = tmpLast;\n\n            if (cur.err < best.err) {\n                best = cur;\n                add_pool(best);\n                lastImprove = iter;\n            } else if (cur.err <= best.err + 1200 && rng.nextDouble() < 0.20) {\n                add_pool(cur);\n            }\n        }\n    }\n\n    // Final polish\n    if (elapsed() < TL - 0.02) {\n        trialA = best.a;\n        optimize_b_given_a_greedy(trialA, N, T, srcDesc, rng, trialB, 0);\n        State s;\n        s.a = trialA; s.b = trialB;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) best = s;\n    }\n\n    if (elapsed() < TL - 0.02) {\n        trialA = best.a;\n        build_b_hungarian_given_a(trialA, N, T, rng, trialB, true);\n        State s;\n        s.a = trialA; s.b = trialB;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) best = s;\n    }\n\n    int polishTrials = 0;\n    while (elapsed() < TL - 0.015 && polishTrials < 32) {\n        trialA = best.a;\n        int i = rng.nextInt(N);\n        int j = rng.nextInt(N - 1);\n        if (j >= i) j++;\n        swap(trialA[i], trialA[j]);\n\n        if (rng.nextDouble() < 0.55) {\n            optimize_b_given_a_greedy(trialA, N, T, srcDesc, rng, trialB, 1);\n        } else {\n            build_b_hungarian_given_a(trialA, N, T, rng, trialB, true);\n        }\n\n        State s;\n        s.a = trialA; s.b = trialB;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) best = s;\n        polishTrials++;\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\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        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int MAXN = 800;\n    static constexpr int EDGE_BASE = 1024;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n\n    vector<int> lx, rx, ly, ry;\n    vector<int> wx, wy;              // rectangle widths\n    vector<int> cx2, cy2, cx, cy;    // center*2 and center\n    vector<uint32_t> zkey;\n\n    vector<int> d_center; // center-based distance (scaled coords)\n    vector<int> d_base;   // uncertainty-aware distance\n    vector<int> d_group;  // d_base + query-learned bonuses\n\n    vector<uint16_t> obsCnt;             // observed edge frequency\n    vector<pair<int,int>> touchedObs;    // unique (a<b) observed edges\n\n    mt19937 rng;\n\n    inline int ID(int a, int b) const { return a * N + b; }\n    inline int DBase(int a, int b) const { return d_base[ID(a, b)]; }\n    inline int DGroup(int a, int b) const { return d_group[ID(a, b)]; }\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffffu;\n        x = (x | (x << 8)) & 0x00FF00FFu;\n        x = (x | (x << 4)) & 0x0F0F0F0Fu;\n        x = (x | (x << 2)) & 0x33333333u;\n        x = (x | (x << 1)) & 0x55555555u;\n        return x;\n    }\n    static uint32_t morton(uint32_t x, uint32_t y) {\n        return part1by1(x) | (part1by1(y) << 1);\n    }\n\n    void input() {\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        wx.resize(N); wy.resize(N);\n        cx2.resize(N); cy2.resize(N);\n        cx.resize(N); cy.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            wx[i] = rx[i] - lx[i];\n            wy[i] = ry[i] - ly[i];\n            cx2[i] = lx[i] + rx[i];\n            cy2[i] = ly[i] + ry[i];\n            cx[i] = cx2[i] / 2;\n            cy[i] = cy2[i] / 2;\n        }\n    }\n\n    void init_rng() {\n        uint64_t seed = 0x9e3779b97f4a7c15ull;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n        };\n\n        mix(((uint64_t)N << 32) ^ (uint64_t)M);\n        mix(((uint64_t)Q << 32) ^ (uint64_t)L);\n        mix((uint64_t)W);\n        for (int i = 0; i < N; i++) {\n            mix(((uint64_t)(cx2[i] + 10007) << 32) ^ (uint64_t)(cy2[i] + 10009));\n            mix((uint64_t)(wx[i] + 1) * 1000003ull + (uint64_t)(wy[i] + 7));\n        }\n\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    void preprocess() {\n        zkey.resize(N);\n        for (int i = 0; i < N; i++) {\n            zkey[i] = morton((uint32_t)cx[i], (uint32_t)cy[i]);\n        }\n\n        d_center.assign(N * N, 0);\n        d_base.assign(N * N, 0);\n        d_group.assign(N * N, 0);\n\n        for (int i = 0; i < N; i++) {\n            d_center[ID(i, i)] = 0;\n            d_base[ID(i, i)] = 0;\n            for (int j = i + 1; j < N; j++) {\n                long long dx = (long long)cx2[i] - cx2[j];\n                long long dy = (long long)cy2[i] - cy2[j];\n                long long sq = dx * dx + dy * dy;\n                int dc = (int)std::sqrt((double)sq);\n                d_center[ID(i, j)] = d_center[ID(j, i)] = dc;\n\n                // uncertainty-aware proxy:\n                // E[(error_x)^2 + (error_y)^2] approx (wx_i^2 + wx_j^2 + wy_i^2 + wy_j^2)/3\n                long double add = ((long double)wx[i] * wx[i] + (long double)wx[j] * wx[j]\n                                 + (long double)wy[i] * wy[i] + (long double)wy[j] * wy[j]) / 3.0L;\n                long double bq = (long double)dc * dc + add;\n                int db = (int)std::sqrt((double)bq);\n\n                d_base[ID(i, j)] = d_base[ID(j, i)] = db;\n            }\n        }\n\n        d_group = d_base;\n        obsCnt.assign(N * N, 0);\n        touchedObs.clear();\n    }\n\n    int query_need(int g) const {\n        if (g <= 2) return 0;\n        return (g - 2) / (L - 1) + 1; // ceil((g-1)/(L-1))\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        cout << \"? \" << subset.size();\n        for (int c : subset) cout << \" \" << c;\n        cout << \"\\n\";\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)subset.size() - 1);\n        for (int i = 0; i < (int)subset.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.emplace_back(a, b);\n        }\n        return ret;\n    }\n\n    void record_edges(const vector<pair<int,int>>& edges) {\n        for (auto [a, b] : edges) {\n            if (a > b) swap(a, b);\n            int p = ID(a, b), q = ID(b, a);\n            if (obsCnt[p] == 0) touchedObs.emplace_back(a, b);\n            if (obsCnt[p] < 65535) obsCnt[p]++;\n            if (obsCnt[q] < 65535) obsCnt[q]++;\n        }\n    }\n\n    template<class F>\n    vector<int> make_city_order(F comp) const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), comp);\n        return ord;\n    }\n\n    vector<int> city_order_projection(double ang) const {\n        double ax = cos(ang), ay = sin(ang);\n        vector<double> key(N);\n        for (int i = 0; i < N; i++) key[i] = ax * cx2[i] + ay * cy2[i];\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (fabs(key[a] - key[b]) > 1e-12) return key[a] < key[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<vector<int>> build_knn(const vector<int>& mat, int K) const {\n        K = min(K, N - 1);\n        vector<vector<int>> near(N);\n\n        auto cmp = [](const pair<int,int>& p1, const pair<int,int>& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        };\n\n        for (int i = 0; i < N; i++) {\n            vector<pair<int,int>> arr;\n            arr.reserve(N - 1);\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                if (i == j) continue;\n                arr.emplace_back(mat[base + j], j);\n            }\n\n            if ((int)arr.size() > K) {\n                nth_element(arr.begin(), arr.begin() + K, arr.end(), cmp);\n                arr.resize(K);\n            }\n            sort(arr.begin(), arr.end(), cmp);\n\n            near[i].reserve((int)arr.size());\n            for (auto& p : arr) near[i].push_back(p.second);\n        }\n        return near;\n    }\n\n    void perform_exploration(int q_explore, int& q_used) {\n        if (q_explore <= 0) return;\n\n        int Kexp = min(N - 1, max(24, L * 4));\n        auto near = build_knn(d_base, Kexp);\n\n        vector<int> ordZ(N);\n        iota(ordZ.begin(), ordZ.end(), 0);\n        sort(ordZ.begin(), ordZ.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<double> w(N);\n        for (int i = 0; i < N; i++) w[i] = (double)(wx[i] + wy[i] + 20);\n        discrete_distribution<int> anchorDist(w.begin(), w.end());\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        vector<int> mark(N, 0);\n        int stamp = 1;\n\n        for (int t = 0; t < q_explore; t++) {\n            vector<int> subset;\n            subset.reserve(L);\n            ++stamp;\n\n            auto addNode = [&](int v) -> bool {\n                if (v < 0 || v >= N) return false;\n                if (mark[v] == stamp) return false;\n                mark[v] = stamp;\n                subset.push_back(v);\n                return true;\n            };\n\n            int mode = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (mode < 65) {\n                int a = anchorDist(rng);\n                addNode(a);\n                auto& ne = near[a];\n\n                int fixed = min((int)ne.size(), max(1, (L - 1) / 2));\n                for (int i = 0; i < fixed && (int)subset.size() < L; i++) addNode(ne[i]);\n\n                int R = min((int)ne.size(), max(10, L * 3));\n                if (R > 0) {\n                    for (int tries = 0; tries < R * 3 && (int)subset.size() < L; tries++) {\n                        int idx = uniform_int_distribution<int>(0, R - 1)(rng);\n                        addNode(ne[idx]);\n                    }\n                }\n\n                for (int tries = 0; tries < 20 && (int)subset.size() < L; tries++) addNode(uid(rng));\n            } else if (mode < 90) {\n                int a = anchorDist(rng);\n                addNode(a);\n\n                int b = uid(rng);\n                auto& na = near[a];\n                if (!na.empty()) {\n                    int R = min((int)na.size(), 10);\n                    b = na[uniform_int_distribution<int>(0, R - 1)(rng)];\n                }\n                addNode(b);\n\n                vector<int> bases = {a, b};\n                int ptr0 = 0, ptr1 = 0;\n\n                for (int step = 0; step < 200 && (int)subset.size() < L; step++) {\n                    int bi = step & 1;\n                    auto& ne = near[bases[bi]];\n                    int& ptr = (bi == 0 ? ptr0 : ptr1);\n\n                    while (ptr < (int)ne.size() && mark[ne[ptr]] == stamp) ptr++;\n                    if (ptr < (int)ne.size()) {\n                        addNode(ne[ptr]);\n                        ptr++;\n                    } else {\n                        addNode(uid(rng));\n                    }\n                }\n            } else {\n                int len = min(L, N);\n                int s = 0;\n                if (N > len) s = uniform_int_distribution<int>(0, N - len)(rng);\n                for (int i = 0; i < len; i++) addNode(ordZ[s + i]);\n                for (int tries = 0; tries < 20 && (int)subset.size() < L; tries++) addNode(uid(rng));\n            }\n\n            while ((int)subset.size() < 2) addNode(uid(rng));\n            if ((int)subset.size() > L) subset.resize(L);\n\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n        }\n    }\n\n    void rebuild_group_matrix_from_obs() {\n        d_group = d_base;\n        int beta = max(30, W / 14); // roughly 35..178\n\n        for (auto [a, b] : touchedObs) {\n            int c = (int)obsCnt[ID(a, b)];\n            if (c <= 0) continue;\n            int bonus = beta * c;\n            if (c >= 2) bonus += beta / 2;\n\n            int v = d_base[ID(a, b)] - bonus;\n            if (v < 1) v = 1;\n            d_group[ID(a, b)] = d_group[ID(b, a)] = v;\n        }\n    }\n\n    long long prim_cost(const vector<int>& nodes, const vector<int>& mat) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return 0;\n\n        const int INF = 1e9;\n        int mn[MAXN + 5];\n        unsigned char used[MAXN + 5];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        long long cost = 0;\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            cost += mn[v];\n\n            int idv = nodes[v];\n            int base = idv * N;\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = mat[base + nodes[u]];\n                if (w < mn[u]) mn[u] = w;\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> prim_tree(const vector<int>& nodes, const vector<int>& mat) const {\n        int n = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            edges.push_back(p);\n            return edges;\n        }\n\n        const int INF = 1e9;\n        int mn[MAXN + 5], par[MAXN + 5];\n        unsigned char used[MAXN + 5];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            par[i] = -1;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int idv = nodes[v];\n            int base = idv * N;\n\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = mat[base + nodes[u]];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        edges.reserve(n - 1);\n        for (int i = 1; i < n; i++) {\n            int a = nodes[i], b = nodes[par[i]];\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        return edges;\n    }\n\n    long long edge_proxy_cost(const vector<pair<int,int>>& edges, const vector<int>& mat) const {\n        long long s = 0;\n        for (auto [a, b] : edges) s += mat[ID(a, b)];\n        return s;\n    }\n\n    vector<int> global_mst_order(const vector<int>& mat) const {\n        const int INF = 1e9;\n        vector<int> mn(N, INF), par(N, -1);\n        vector<char> used(N, 0);\n\n        int root = 0;\n        for (int i = 1; i < N; i++) if (zkey[i] < zkey[root]) root = i;\n        mn[root] = 0;\n\n        for (int it = 0; it < N; it++) {\n            int v = -1;\n            for (int i = 0; i < N; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int base = v * N;\n            for (int u = 0; u < N; u++) {\n                if (used[u]) continue;\n                int w = mat[base + u];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<vector<int>> adj(N);\n        for (int i = 0; i < N; i++) {\n            if (i == root) continue;\n            if (par[i] >= 0) {\n                adj[i].push_back(par[i]);\n                adj[par[i]].push_back(i);\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            sort(adj[i].begin(), adj[i].end(), [&](int a, int b) {\n                if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                return a < b;\n            });\n        }\n\n        vector<int> order;\n        order.reserve(N);\n        vector<int> st;\n        vector<int> itPtr(N, 0);\n        vector<char> vis(N, 0);\n\n        st.push_back(root);\n        vis[root] = 1;\n        order.push_back(root);\n\n        while (!st.empty()) {\n            int v = st.back();\n            if (itPtr[v] == (int)adj[v].size()) {\n                st.pop_back();\n                continue;\n            }\n            int to = adj[v][itPtr[v]++];\n            if (vis[to]) continue;\n            vis[to] = 1;\n            order.push_back(to);\n            st.push_back(to);\n        }\n\n        if ((int)order.size() < N) {\n            vector<char> used2(N, 0);\n            for (int x : order) used2[x] = 1;\n            for (int i = 0; i < N; i++) if (!used2[i]) order.push_back(i);\n        }\n        return order;\n    }\n\n    bool validate_groups(const vector<vector<int>>& groups) const {\n        if ((int)groups.size() != M) return false;\n        vector<int> cnt(N, 0);\n        for (int g = 0; g < M; g++) {\n            if ((int)groups[g].size() != G[g]) return false;\n            for (int c : groups[g]) {\n                if (c < 0 || c >= N) return false;\n                cnt[c]++;\n            }\n        }\n        for (int i = 0; i < N; i++) if (cnt[i] != 1) return false;\n        return true;\n    }\n\n    long long eval_groups(const vector<vector<int>>& groups) const {\n        long long s = 0;\n        for (int g = 0; g < M; g++) s += prim_cost(groups[g], d_group);\n        return s;\n    }\n\n    vector<vector<int>> build_order_trial(const vector<int>& city_order, const vector<int>& group_order) const {\n        vector<vector<int>> out(M);\n        int p = 0;\n        for (int gid : group_order) {\n            int sz = G[gid];\n            out[gid].assign(city_order.begin() + p, city_order.begin() + p + sz);\n            p += sz;\n        }\n        return out;\n    }\n\n    void rec_assign(vector<int> cities, vector<int> gids, vector<vector<int>>& out, bool randomized) {\n        if ((int)gids.size() == 1) {\n            out[gids[0]] = std::move(cities);\n            return;\n        }\n\n        int S = (int)cities.size();\n\n        int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;\n        for (int c : cities) {\n            minx = min(minx, cx2[c]);\n            maxx = max(maxx, cx2[c]);\n            miny = min(miny, cy2[c]);\n            maxy = max(maxy, cy2[c]);\n        }\n\n        int axis = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 28) axis ^= 1;\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            if (axis == 0) {\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                return a < b;\n            } else {\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                return a < b;\n            }\n        });\n\n        vector<int> pg = gids;\n        if (randomized) shuffle(pg.begin(), pg.end(), rng);\n\n        vector<char> dp(S + 1, 0);\n        vector<int> prv(S + 1, -1), itm(S + 1, -1);\n        dp[0] = 1;\n\n        for (int j = 0; j < (int)pg.size(); j++) {\n            int w = G[pg[j]];\n            for (int s = S - w; s >= 0; s--) {\n                if (dp[s] && !dp[s + w]) {\n                    dp[s + w] = 1;\n                    prv[s + w] = s;\n                    itm[s + w] = j;\n                }\n            }\n        }\n\n        int target = S / 2;\n        if (randomized) {\n            int r = max(1, S / 6);\n            target += uniform_int_distribution<int>(-r, r)(rng);\n            target = max(1, min(S - 1, target));\n        }\n\n        int bestDiff = INT_MAX;\n        vector<int> candS;\n        for (int s = 1; s <= S - 1; s++) {\n            if (!dp[s]) continue;\n            int diff = abs(s - target);\n            if (diff < bestDiff) {\n                bestDiff = diff;\n                candS.clear();\n                candS.push_back(s);\n            } else if (diff == bestDiff) {\n                candS.push_back(s);\n            }\n        }\n\n        int split = -1;\n        if (!candS.empty()) {\n            split = randomized\n                ? candS[uniform_int_distribution<int>(0, (int)candS.size() - 1)(rng)]\n                : candS[0];\n        }\n\n        vector<int> gA, gB;\n        bool ok = (split > 0 && split < S);\n        if (ok) {\n            vector<char> take(pg.size(), 0);\n            int cur = split;\n            while (cur > 0) {\n                int j = itm[cur];\n                if (j < 0 || take[j]) {\n                    ok = false;\n                    break;\n                }\n                take[j] = 1;\n                cur = prv[cur];\n            }\n\n            if (ok) {\n                int sumA = 0;\n                for (int j = 0; j < (int)pg.size(); j++) {\n                    if (take[j]) {\n                        gA.push_back(pg[j]);\n                        sumA += G[pg[j]];\n                    } else {\n                        gB.push_back(pg[j]);\n                    }\n                }\n                if (gA.empty() || gB.empty() || sumA != split) ok = false;\n            }\n        }\n\n        if (!ok) {\n            gA.clear(); gB.clear();\n            gA.push_back(pg[0]);\n            split = G[pg[0]];\n            for (int j = 1; j < (int)pg.size(); j++) gB.push_back(pg[j]);\n        }\n\n        vector<int> cA(cities.begin(), cities.begin() + split);\n        vector<int> cB(cities.begin() + split, cities.end());\n\n        rec_assign(std::move(cA), std::move(gA), out, randomized);\n        rec_assign(std::move(cB), std::move(gB), out, randomized);\n    }\n\n    vector<vector<int>> build_recursive_trial(bool randomized) {\n        vector<vector<int>> out(M);\n        vector<int> cities(N), gids(M);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        sort(gids.begin(), gids.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 20) {\n            shuffle(gids.begin(), gids.end(), rng);\n        }\n\n        rec_assign(std::move(cities), std::move(gids), out, randomized);\n        return out;\n    }\n\n    vector<vector<int>> make_grouping() {\n        vector<vector<int>> best;\n        long long bestScore = (1LL << 62);\n\n        auto consider = [&](vector<vector<int>> cand) {\n            if (!validate_groups(cand)) return;\n            long long sc = eval_groups(cand);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = std::move(cand);\n            }\n        };\n\n        vector<int> goOrig(M), goDesc(M), goAsc(M), goRand(M);\n        iota(goOrig.begin(), goOrig.end(), 0);\n        goDesc = goOrig;\n        goAsc = goOrig;\n        goRand = goOrig;\n\n        sort(goDesc.begin(), goDesc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        sort(goAsc.begin(), goAsc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        shuffle(goRand.begin(), goRand.end(), rng);\n\n        vector<vector<int>> groupOrders = {goDesc, goOrig, goAsc, goRand};\n\n        vector<vector<int>> cityOrders;\n        auto ordZ = make_city_order([&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n        auto ordX = make_city_order([&](int a, int b) {\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        auto ordY = make_city_order([&](int a, int b) {\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ordD1 = make_city_order([&](int a, int b) {\n            int ka = cx2[a] + cy2[a];\n            int kb = cx2[b] + cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ordD2 = make_city_order([&](int a, int b) {\n            int ka = cx2[a] - cy2[a];\n            int kb = cx2[b] - cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n\n        cityOrders.push_back(ordZ);\n        cityOrders.push_back(ordX);\n        cityOrders.push_back(ordY);\n        cityOrders.push_back(ordD1);\n        cityOrders.push_back(ordD2);\n\n        auto rev = ordZ;\n        reverse(rev.begin(), rev.end());\n        cityOrders.push_back(rev);\n\n        cityOrders.push_back(global_mst_order(d_group));\n\n        const double PI = acos(-1.0);\n        cityOrders.push_back(city_order_projection(PI * 1.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 3.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 5.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 7.0 / 8.0));\n\n        uniform_real_distribution<double> ur(0.0, PI);\n        cityOrders.push_back(city_order_projection(ur(rng)));\n        cityOrders.push_back(city_order_projection(ur(rng)));\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                consider(build_order_trial(co, go));\n            }\n        }\n\n        consider(build_recursive_trial(false));\n        for (int t = 0; t < 6; t++) consider(build_recursive_trial(true));\n\n        if (best.empty()) best = build_order_trial(ordZ, goOrig);\n        return best;\n    }\n\n    void optimize_groups(vector<vector<int>>& groups, double sec_budget) {\n        using Clock = chrono::steady_clock;\n        auto start = Clock::now();\n        auto deadline = start + chrono::milliseconds((int)(sec_budget * 1000.0));\n        auto stage1 = start + chrono::milliseconds((int)(sec_budget * 650.0));\n\n        vector<int> gid(N, -1), pos(N, -1);\n        for (int g = 0; g < M; g++) {\n            for (int i = 0; i < (int)groups[g].size(); i++) {\n                int c = groups[g][i];\n                gid[c] = g;\n                pos[c] = i;\n            }\n        }\n\n        vector<long long> gcost(M, 0);\n        for (int g = 0; g < M; g++) gcost[g] = prim_cost(groups[g], d_group);\n\n        auto near = build_knn(d_group, 24);\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        long long opBudget = 45000000;\n\n        auto try_swap = [&](int u, int v) -> bool {\n            int ga = gid[u], gb = gid[v];\n            if (ga == gb || ga < 0 || gb < 0) return false;\n\n            int sa = (int)groups[ga].size();\n            int sb = (int)groups[gb].size();\n            long long est = 1LL * sa * sa + 1LL * sb * sb;\n            if (est > opBudget) return false;\n            opBudget -= est;\n\n            int pu = pos[u], pv = pos[v];\n            auto& A = groups[ga];\n            auto& B = groups[gb];\n\n            swap(A[pu], B[pv]);\n            long long nA = prim_cost(A, d_group);\n            long long nB = prim_cost(B, d_group);\n\n            if (nA + nB < gcost[ga] + gcost[gb]) {\n                gid[u] = gb; gid[v] = ga;\n                pos[u] = pv; pos[v] = pu;\n                gcost[ga] = nA;\n                gcost[gb] = nB;\n                return true;\n            } else {\n                swap(A[pu], B[pv]);\n                return false;\n            }\n        };\n\n        while (Clock::now() < stage1 && opBudget > 0) {\n            bool improved = false;\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int it = 0; it < N; it++) {\n                if ((it & 31) == 0) {\n                    if (Clock::now() >= stage1 || opBudget <= 0) break;\n                }\n\n                int u = order[it];\n                bool ok = false;\n\n                int T = min(12, (int)near[u].size());\n                for (int i = 0; i < T; i++) {\n                    int v = near[u][i];\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        ok = true;\n                        break;\n                    }\n                }\n                if (ok) continue;\n\n                for (int r = 0; r < 2; r++) {\n                    int v = uid(rng);\n                    if (v == u) continue;\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n\n        auto try_pair_repartition = [&](int a, int b) -> bool {\n            if (a == b) return false;\n            int sa = (int)groups[a].size();\n            int sb = (int)groups[b].size();\n            if (sa == 0 || sb == 0) return false;\n            if (sa + sb > 220) return false;\n\n            vector<int> U = groups[a];\n            U.insert(U.end(), groups[b].begin(), groups[b].end());\n\n            long long oldCost = gcost[a] + gcost[b];\n            long long bestCost = oldCost;\n            long long bestCA = gcost[a], bestCB = gcost[b];\n            vector<int> bestA = groups[a], bestB = groups[b];\n\n            auto centroid = [&](const vector<int>& V) -> pair<double,double> {\n                double sx = 0.0, sy = 0.0;\n                for (int c : V) {\n                    sx += cx2[c];\n                    sy += cy2[c];\n                }\n                double inv = 1.0 / (double)V.size();\n                return {sx * inv, sy * inv};\n            };\n\n            auto [ax, ay] = centroid(groups[a]);\n            auto [bx, by] = centroid(groups[b]);\n\n            auto considerAB = [&](const vector<int>& A, const vector<int>& B) {\n                if ((int)A.size() != sa || (int)B.size() != sb) return;\n                long long cA = prim_cost(A, d_group);\n                long long cB = prim_cost(B, d_group);\n                if (cA + cB < bestCost) {\n                    bestCost = cA + cB;\n                    bestCA = cA;\n                    bestCB = cB;\n                    bestA = A;\n                    bestB = B;\n                }\n            };\n\n            auto eval_sorted = [&](vector<pair<double,int>>& arr) {\n                sort(arr.begin(), arr.end(), [&](const auto& p1, const auto& p2) {\n                    if (fabs(p1.first - p2.first) > 1e-12) return p1.first < p2.first;\n                    return p1.second < p2.second;\n                });\n\n                vector<int> A, B;\n                A.reserve(sa); B.reserve(sb);\n\n                // first sa -> A\n                for (int i = 0; i < sa; i++) A.push_back(arr[i].second);\n                for (int i = sa; i < sa + sb; i++) B.push_back(arr[i].second);\n                considerAB(A, B);\n\n                // first sb -> B\n                A.clear(); B.clear();\n                for (int i = 0; i < sb; i++) B.push_back(arr[i].second);\n                for (int i = sb; i < sa + sb; i++) A.push_back(arr[i].second);\n                considerAB(A, B);\n            };\n\n            // proposal 1: da-db\n            {\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    double dax = cx2[v] - ax, day = cy2[v] - ay;\n                    double dbx = cx2[v] - bx, dby = cy2[v] - by;\n                    double da = dax * dax + day * day;\n                    double db = dbx * dbx + dby * dby;\n                    arr.push_back({da - db, v});\n                }\n                eval_sorted(arr);\n            }\n\n            // proposal 2: centroid axis projection\n            {\n                double vx = bx - ax, vy = by - ay;\n                if (fabs(vx) + fabs(vy) < 1e-12) {\n                    double ang = uniform_real_distribution<double>(0.0, acos(-1.0))(rng);\n                    vx = cos(ang); vy = sin(ang);\n                }\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    arr.push_back({vx * cx2[v] + vy * cy2[v], v});\n                }\n                eval_sorted(arr);\n            }\n\n            // proposal 3: random projection\n            {\n                double ang = uniform_real_distribution<double>(0.0, acos(-1.0))(rng);\n                double vx = cos(ang), vy = sin(ang);\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    arr.push_back({vx * cx2[v] + vy * cy2[v], v});\n                }\n                eval_sorted(arr);\n            }\n\n            if (bestCost < oldCost) {\n                groups[a] = std::move(bestA);\n                groups[b] = std::move(bestB);\n                gcost[a] = bestCA;\n                gcost[b] = bestCB;\n\n                for (int i = 0; i < (int)groups[a].size(); i++) {\n                    int c = groups[a][i];\n                    gid[c] = a;\n                    pos[c] = i;\n                }\n                for (int i = 0; i < (int)groups[b].size(); i++) {\n                    int c = groups[b][i];\n                    gid[c] = b;\n                    pos[c] = i;\n                }\n                return true;\n            }\n            return false;\n        };\n\n        for (int pass = 0; pass < 3; pass++) {\n            if (Clock::now() >= deadline) break;\n\n            vector<pair<double,double>> cent(M, {0.0, 0.0});\n            for (int g = 0; g < M; g++) {\n                double sx = 0.0, sy = 0.0;\n                for (int c : groups[g]) {\n                    sx += cx2[c];\n                    sy += cy2[c];\n                }\n                if (!groups[g].empty()) {\n                    double inv = 1.0 / (double)groups[g].size();\n                    cent[g] = {sx * inv, sy * inv};\n                }\n            }\n\n            const int K = 5;\n            vector<pair<int,int>> pairs;\n            vector<char> seen(M * M, 0);\n\n            for (int a = 0; a < M; a++) {\n                vector<pair<double,int>> arr;\n                arr.reserve(M - 1);\n                for (int b = 0; b < M; b++) {\n                    if (a == b) continue;\n                    double dx = cent[a].first - cent[b].first;\n                    double dy = cent[a].second - cent[b].second;\n                    arr.push_back({dx * dx + dy * dy, b});\n                }\n\n                int k = min(K, (int)arr.size());\n                if ((int)arr.size() > k) {\n                    nth_element(arr.begin(), arr.begin() + k, arr.end(),\n                                [&](const auto& p1, const auto& p2) { return p1.first < p2.first; });\n                    arr.resize(k);\n                }\n                sort(arr.begin(), arr.end(),\n                     [&](const auto& p1, const auto& p2) { return p1.first < p2.first; });\n\n                for (auto& e : arr) {\n                    int b = e.second;\n                    int x = min(a, b), y = max(a, b);\n                    int key = x * M + y;\n                    if (!seen[key]) {\n                        seen[key] = 1;\n                        pairs.push_back({x, y});\n                    }\n                }\n            }\n\n            shuffle(pairs.begin(), pairs.end(), rng);\n\n            bool improved = false;\n            for (auto [a, b] : pairs) {\n                if (Clock::now() >= deadline) break;\n                if (try_pair_repartition(a, b)) improved = true;\n            }\n            if (!improved) break;\n        }\n    }\n\n    int choose_medoid_idx(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        int best = 0;\n        long long bestSum = (1LL << 62);\n\n        for (int i = 0; i < n; i++) {\n            int a = nodes[i];\n            int base = a * N;\n            long long s = 0;\n            for (int j = 0; j < n; j++) {\n                s += d_base[base + nodes[j]];\n                if (s >= bestSum) break;\n            }\n            if (s < bestSum) {\n                bestSum = s;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_base_group_edges(const vector<int>& nodes, int& q_used, vector<pair<int,int>>& cand_store) {\n        int g = (int)nodes.size();\n        vector<pair<int,int>> base;\n        if (g <= 1) return base;\n\n        auto append_ret = [&](const vector<pair<int,int>>& ret) {\n            for (auto [a, b] : ret) {\n                if (a > b) swap(a, b);\n                base.emplace_back(a, b);\n                cand_store.emplace_back(a, b);\n            }\n        };\n\n        if (g == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            base.push_back(p);\n            cand_store.push_back(p);\n            return base;\n        }\n\n        int need = query_need(g);\n        if (q_used + need > Q) {\n            base = prim_tree(nodes, d_base);\n            cand_store.insert(cand_store.end(), base.begin(), base.end());\n            return base;\n        }\n\n        vector<int> ord = nodes;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        if (g <= L) {\n            auto ret = do_query(ord);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n            if ((int)base.size() != g - 1) {\n                base = prim_tree(nodes, d_base);\n                cand_store.insert(cand_store.end(), base.begin(), base.end());\n            }\n            return base;\n        }\n\n        int root = choose_medoid_idx(ord);\n\n        vector<char> conn(g, 0);\n        vector<int> nearestDist(g, (int)1e9), nearestAnchor(g, -1);\n\n        // first query: root + nearest (L-1)\n        vector<pair<int,int>> arr;\n        arr.reserve(g - 1);\n        for (int i = 0; i < g; i++) {\n            if (i == root) continue;\n            arr.push_back({DBase(ord[root], ord[i]), i});\n        }\n        sort(arr.begin(), arr.end(), [&](const auto& p1, const auto& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        });\n\n        int t0 = min(L - 1, g - 1);\n        vector<int> firstIdx;\n        firstIdx.reserve(t0);\n        for (int i = 0; i < t0; i++) firstIdx.push_back(arr[i].second);\n\n        vector<int> subset;\n        subset.reserve(1 + t0);\n        subset.push_back(ord[root]);\n        for (int idx : firstIdx) subset.push_back(ord[idx]);\n\n        {\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n        }\n\n        conn[root] = 1;\n        for (int idx : firstIdx) conn[idx] = 1;\n        int rem = g - 1 - t0;\n\n        auto update_by_new = [&](int idx) {\n            int c = ord[idx];\n            for (int j = 0; j < g; j++) {\n                if (conn[j]) continue;\n                int d = DBase(c, ord[j]);\n                if (d < nearestDist[j]) {\n                    nearestDist[j] = d;\n                    nearestAnchor[j] = idx;\n                }\n            }\n        };\n\n        for (int i = 0; i < g; i++) {\n            nearestDist[i] = (int)1e9;\n            nearestAnchor[i] = -1;\n        }\n        update_by_new(root);\n        for (int idx : firstIdx) update_by_new(idx);\n\n        while (rem > 0) {\n            int u = -1, best = (int)1e9;\n            for (int i = 0; i < g; i++) {\n                if (!conn[i] && nearestDist[i] < best) {\n                    best = nearestDist[i];\n                    u = i;\n                }\n            }\n            if (u < 0) break;\n\n            int anchor = nearestAnchor[u];\n            if (anchor < 0) anchor = root;\n\n            int t = min(L - 1, rem);\n            vector<int> batch;\n            batch.reserve(t);\n            batch.push_back(u);\n\n            if (t > 1) {\n                vector<pair<int,int>> cand;\n                cand.reserve(rem - 1);\n                int ac = ord[anchor];\n                for (int i = 0; i < g; i++) {\n                    if (conn[i] || i == u) continue;\n                    cand.push_back({DBase(ac, ord[i]), i});\n                }\n                sort(cand.begin(), cand.end(), [&](const auto& p1, const auto& p2) {\n                    if (p1.first != p2.first) return p1.first < p2.first;\n                    return p1.second < p2.second;\n                });\n                for (int i = 0; i < t - 1 && i < (int)cand.size(); i++) {\n                    batch.push_back(cand[i].second);\n                }\n            }\n\n            subset.clear();\n            subset.push_back(ord[anchor]);\n            for (int idx : batch) subset.push_back(ord[idx]);\n\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n\n            for (int idx : batch) {\n                if (!conn[idx]) {\n                    conn[idx] = 1;\n                    rem--;\n                }\n            }\n            for (int idx : batch) update_by_new(idx);\n        }\n\n        if ((int)base.size() != g - 1) {\n            base = prim_tree(nodes, d_base);\n            cand_store.insert(cand_store.end(), base.begin(), base.end());\n        }\n        return base;\n    }\n\n    vector<int> make_subset_window(const vector<int>& ordz) {\n        int g = (int)ordz.size();\n        int l = min(L, g);\n        if (l < 2) return {};\n        if (g == l) return ordz;\n        int s = uniform_int_distribution<int>(0, g - l)(rng);\n        return vector<int>(ordz.begin() + s, ordz.begin() + s + l);\n    }\n\n    vector<int> make_subset_star(const vector<int>& nodes) {\n        int g = (int)nodes.size();\n        int l = min(L, g);\n        if (l < 2) return {};\n        if (g == l) return nodes;\n\n        int center = nodes[uniform_int_distribution<int>(0, g - 1)(rng)];\n        vector<pair<int,int>> arr;\n        arr.reserve(g - 1);\n        for (int v : nodes) if (v != center) {\n            arr.push_back({DBase(center, v), v});\n        }\n\n        auto cmp = [](const pair<int,int>& p1, const pair<int,int>& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        };\n\n        if ((int)arr.size() > l - 1) {\n            nth_element(arr.begin(), arr.begin() + (l - 1), arr.end(), cmp);\n            arr.resize(l - 1);\n        }\n        sort(arr.begin(), arr.end(), cmp);\n\n        vector<int> subset;\n        subset.reserve(l);\n        subset.push_back(center);\n        for (auto& p : arr) {\n            if ((int)subset.size() >= l) break;\n            subset.push_back(p.second);\n        }\n\n        if ((int)subset.size() < 2) {\n            for (int v : nodes) if (v != center) {\n                subset.push_back(v);\n                break;\n            }\n        }\n        return subset;\n    }\n\n    vector<pair<int,int>> mst_from_candidates(const vector<int>& nodes, const vector<pair<int,int>>& cand) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return {};\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            return {p};\n        }\n\n        vector<int> loc(N, -1);\n        for (int i = 0; i < n; i++) loc[nodes[i]] = i;\n\n        unordered_map<int, int> cnt;\n        cnt.reserve(cand.size() * 2 + 1);\n\n        for (auto [a, b] : cand) {\n            if (a > b) swap(a, b);\n            if (a < 0 || b < 0 || a >= N || b >= N || a == b) continue;\n            if (loc[a] < 0 || loc[b] < 0) continue;\n            int key = a * EDGE_BASE + b;\n            cnt[key]++;\n        }\n\n        struct E {\n            long long w;\n            int a, b;\n        };\n        vector<E> es;\n        es.reserve(cnt.size());\n\n        for (auto& kv : cnt) {\n            int key = kv.first;\n            int c = kv.second;\n            int a = key / EDGE_BASE;\n            int b = key % EDGE_BASE;\n\n            long long w = 1LL * d_base[ID(a, b)] * 10 - 90LL * min(c, 6);\n            es.push_back({w, a, b});\n        }\n\n        sort(es.begin(), es.end(), [&](const E& e1, const E& e2) {\n            if (e1.w != e2.w) return e1.w < e2.w;\n            if (e1.a != e2.a) return e1.a < e2.a;\n            return e1.b < e2.b;\n        });\n\n        DSU dsu(n);\n        vector<pair<int,int>> out;\n        out.reserve(n - 1);\n\n        for (auto& e : es) {\n            int ia = loc[e.a], ib = loc[e.b];\n            if (ia < 0 || ib < 0) continue;\n            if (dsu.unite(ia, ib)) {\n                int a = e.a, b = e.b;\n                if (a > b) swap(a, b);\n                out.emplace_back(a, b);\n                if ((int)out.size() == n - 1) break;\n            }\n        }\n\n        if ((int)out.size() != n - 1) return {};\n        return out;\n    }\n\n    vector<vector<int>> fallback_grouping() const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<vector<int>> groups(M);\n        int p = 0;\n        for (int k = 0; k < M; k++) {\n            groups[k].assign(ord.begin() + p, ord.begin() + p + G[k]);\n            p += G[k];\n        }\n        return groups;\n    }\n\n    void solve() {\n        input();\n        init_rng();\n        preprocess();\n\n        int reqMin = 0;\n        for (int g : G) reqMin += query_need(g);\n        int spare = Q - reqMin;\n\n        int q_used = 0;\n        int q_explore = 0;\n        if (spare > 20) {\n            if (spare <= 80) q_explore = spare / 3;\n            else if (spare <= 180) q_explore = spare / 2;\n            else q_explore = (spare * 2) / 3;\n            q_explore = min(q_explore, 180);\n            q_explore = min(q_explore, spare);\n        }\n\n        // 1) Exploration for better grouping\n        perform_exploration(q_explore, q_used);\n        rebuild_group_matrix_from_obs();\n\n        // 2) Grouping + local improvement (on learned distance)\n        auto groups = make_grouping();\n        if (!validate_groups(groups)) groups = fallback_grouping();\n\n        optimize_groups(groups, 0.72);\n        if (!validate_groups(groups)) groups = fallback_grouping();\n\n        // 3) Mandatory group-edge construction queries\n        vector<vector<pair<int,int>>> baseEdges(M), candEdges(M);\n\n        vector<int> gidOrder(M);\n        iota(gidOrder.begin(), gidOrder.end(), 0);\n        sort(gidOrder.begin(), gidOrder.end(), [&](int a, int b) {\n            if ((int)groups[a].size() != (int)groups[b].size()) return groups[a].size() > groups[b].size();\n            return a < b;\n        });\n\n        for (int gid : gidOrder) {\n            baseEdges[gid] = build_base_group_edges(groups[gid], q_used, candEdges[gid]);\n        }\n\n        // 4) Extra queries for large groups only\n        if (q_used < Q) {\n            vector<int> targets;\n            for (int g = 0; g < M; g++) if ((int)groups[g].size() > L) targets.push_back(g);\n\n            if (!targets.empty()) {\n                vector<vector<int>> ordz(M);\n                for (int gid : targets) {\n                    ordz[gid] = groups[gid];\n                    sort(ordz[gid].begin(), ordz[gid].end(), [&](int a, int b) {\n                        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                        return a < b;\n                    });\n                }\n\n                vector<double> weights;\n                weights.reserve(targets.size());\n                for (int gid : targets) {\n                    double sz = (double)groups[gid].size();\n                    weights.push_back(pow(sz, 1.35));\n                }\n\n                discrete_distribution<int> pick(weights.begin(), weights.end());\n\n                while (q_used < Q) {\n                    int gid = targets[pick(rng)];\n                    vector<int> subset;\n                    int mode = uniform_int_distribution<int>(0, 99)(rng);\n                    if (mode < 55) subset = make_subset_window(ordz[gid]);\n                    else subset = make_subset_star(groups[gid]);\n\n                    if ((int)subset.size() < 2) continue;\n                    auto ret = do_query(subset);\n                    q_used++;\n                    record_edges(ret);\n\n                    for (auto [a, b] : ret) {\n                        if (a > b) swap(a, b);\n                        candEdges[gid].emplace_back(a, b);\n                    }\n                }\n            }\n        }\n\n        // 5) Build final trees\n        vector<int> city_gid(N, -1);\n        for (int g = 0; g < M; g++) {\n            for (int c : groups[g]) city_gid[c] = g;\n        }\n\n        // Add all observed in-group edges (explore + mandatory + extra) as candidates\n        for (auto [a, b] : touchedObs) {\n            int ga = city_gid[a], gb = city_gid[b];\n            if (ga >= 0 && ga == gb) {\n                int c = (int)obsCnt[ID(a, b)];\n                int rep = min(4, c);\n                for (int t = 0; t < rep; t++) candEdges[ga].emplace_back(a, b);\n            }\n        }\n\n        vector<vector<pair<int,int>>> finalEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int sz = (int)groups[k].size();\n            if (sz <= 1) {\n                finalEdges[k].clear();\n                continue;\n            }\n\n            if ((int)baseEdges[k].size() != sz - 1) {\n                baseEdges[k] = prim_tree(groups[k], d_base);\n            }\n\n            // If sz<=L, baseEdges is exact MST query result (or trivial), so keep it.\n            if (sz <= L) {\n                finalEdges[k] = baseEdges[k];\n                continue;\n            }\n\n            auto candTree = mst_from_candidates(groups[k], candEdges[k]);\n            if ((int)candTree.size() == sz - 1) {\n                long long bc = edge_proxy_cost(baseEdges[k], d_base);\n                long long cc = edge_proxy_cost(candTree, d_base);\n                if (cc < bc) finalEdges[k] = std::move(candTree);\n                else finalEdges[k] = baseEdges[k];\n            } else {\n                finalEdges[k] = baseEdges[k];\n            }\n\n            if ((int)finalEdges[k].size() != sz - 1) {\n                finalEdges[k] = prim_tree(groups[k], d_base);\n            }\n        }\n\n        // 6) Output\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n            for (auto [a, b] : finalEdges[k]) {\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int r, c; };\nstruct Action { char a, d; };\n\nclass Solver {\n    static constexpr int MAXN = 20;\n    static constexpr int INF = 1e9;\n    using Clock = chrono::steady_clock;\n\n    int N, M, LIMIT, n2;\n    vector<Point> pts;                 // pts[0]=start, pts[1..]=targets\n    vector<int> pid;                   // cell id for pts[i]\n    vector<int> cellR, cellC;          // cell id -> r,c\n    vector<array<int,4>> to;           // neighbors for move\n    vector<int> targetIdxAtCell;       // cell id -> index in pts, -1 if non-target\n\n    array<uint32_t, MAXN> lowMask{}, highMask{};\n    const array<int,4> DR{{-1, 1, 0, 0}};\n    const array<int,4> DC{{0, 0, -1, 1}};\n    const array<char,4> DCH{{'U','D','L','R'}};\n\n    struct Node {\n        array<uint32_t, MAXN> row{};\n        array<uint32_t, MAXN> col{};\n        int cost = INF;\n        int parent = -1;          // index in previous layer\n        uint8_t op = 0;           // 0:none, 1:A, 2:M+A, 3:S+A, 4:A+A\n        uint8_t d1 = 0, d2 = 0;   // params for op\n        uint16_t bcnt = 0;        // number of blocked cells (tracked incrementally)\n        int eval = 0;\n    };\n\n    struct Config {\n        bool allowFutureToggle = false;\n        bool enableDoubleAlter = false; // A+A\n        int wEarly = 180, wMid = 140, wLate = 110;\n        int preMul = 6;\n        int elitePct = 50;\n\n        int wCost = 10;\n        int wH1 = 4;\n        int wH2 = 2;\n        int wFutureBlocked = 0;\n        int wBlockBonus = 1;\n        int evalDistLimit = 55;\n    };\n\n    inline int widthAt(const Config& cfg, int k) const {\n        if (k < 12) return cfg.wEarly;\n        if (k < 26) return cfg.wMid;\n        return cfg.wLate;\n    }\n\n    inline bool isBlocked(const array<uint32_t,MAXN>& row, int id) const {\n        return ((row[cellR[id]] >> cellC[id]) & 1u) != 0u;\n    }\n\n    inline void toggleCell(array<uint32_t,MAXN>& row, array<uint32_t,MAXN>& col, int id) const {\n        int r = cellR[id], c = cellC[id];\n        row[r] ^= (1u << c);\n        col[c] ^= (1u << r);\n    }\n\n    inline int rowCompare(const array<uint32_t,MAXN>& a, const array<uint32_t,MAXN>& b) const {\n        return memcmp(a.data(), b.data(), N * sizeof(uint32_t));\n    }\n\n    inline bool isEmptyBoard(const array<uint32_t,MAXN>& row) const {\n        for (int r = 0; r < N; r++) if (row[r]) return false;\n        return true;\n    }\n\n    inline bool allowToggleCell(int cell, int k, const Config& cfg) const {\n        if (cell < 0) return false;\n        if (cfg.allowFutureToggle) return true;\n        int idx = targetIdxAtCell[cell];\n        return !(idx != -1 && idx > k);\n    }\n\n    inline int slideDest(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col, int u, int d) const {\n        int r = cellR[u], c = cellC[u];\n        if (d == 0) { // U\n            uint32_t m = col[c] & lowMask[r];\n            int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n            return nr * N + c;\n        } else if (d == 1) { // D\n            uint32_t m = col[c] & highMask[r];\n            int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n            return nr * N + c;\n        } else if (d == 2) { // L\n            uint32_t m = row[r] & lowMask[c];\n            int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n            return r * N + nc;\n        } else { // R\n            uint32_t m = row[r] & highMask[c];\n            int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n            return r * N + nc;\n        }\n    }\n\n    // Returns shortest distance if <= lim, else INF.\n    int bfsDistLimit(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                     int s, int g, int lim) const {\n        if (lim < 0) return INF;\n        if (s == g) return 0;\n\n        int dist[400];\n        for (int i = 0; i < n2; i++) dist[i] = -1;\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            if (du > lim) continue;\n            int r = cellR[u], c = cellC[u];\n\n            // Move\n            for (int d = 0; d < 4; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du;\n                if (v == g) return du;\n                q[tail++] = v;\n            }\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n        }\n        return INF;\n    }\n\n    bool bfsPath(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                 int s, int g, vector<Action>& out) const {\n        out.clear();\n        if (s == g) return true;\n\n        int dist[400], par[400];\n        uint8_t pdir[400];\n        char pact[400];\n        for (int i = 0; i < n2; i++) {\n            dist[i] = -1;\n            par[i] = -1;\n        }\n\n        int q[400], head = 0, tail = 0;\n        dist[s] = 0;\n        par[s] = s;\n        q[tail++] = s;\n\n        bool found = false;\n        while (head < tail && !found) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            auto relax = [&](int v, char a, int d)->bool {\n                if (v == u) return false;\n                if (dist[v] != -1) return false;\n                dist[v] = du;\n                par[v] = u;\n                pact[v] = a;\n                pdir[v] = (uint8_t)d;\n                q[tail++] = v;\n                return v == g;\n            };\n\n            // Move\n            for (int d = 0; d < 4 && !found; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (relax(v, 'M', d)) found = true;\n            }\n            if (found) break;\n\n            // Slides\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 0)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 1)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 2)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 3)) found = true;\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        vector<Action> rev;\n        int cur = g;\n        while (cur != s) {\n            if (cur < 0 || par[cur] < 0) return false;\n            rev.push_back(Action{pact[cur], DCH[pdir[cur]]});\n            cur = par[cur];\n        }\n        reverse(rev.begin(), rev.end());\n        out.swap(rev);\n        return true;\n    }\n\n    int countBlockedFutureTargets(const array<uint32_t,MAXN>& row, int fromIdx) const {\n        if (fromIdx >= M) return 0;\n        int cnt = 0;\n        for (int i = fromIdx; i < M; i++) {\n            int id = pid[i];\n            if ((row[cellR[id]] >> cellC[id]) & 1u) cnt++;\n        }\n        return cnt;\n    }\n\n    vector<Action> fallbackManhattan() const {\n        vector<Action> ans;\n        int r = pts[0].r, c = pts[0].c;\n        for (int k = 1; k < M; k++) {\n            int tr = pts[k].r, tc = pts[k].c;\n            while (r < tr) { ans.push_back({'M','D'}); r++; }\n            while (r > tr) { ans.push_back({'M','U'}); r--; }\n            while (c < tc) { ans.push_back({'M','R'}); c++; }\n            while (c > tc) { ans.push_back({'M','L'}); c--; }\n        }\n        return ans;\n    }\n\n    vector<Action> fallbackNoBlock() const {\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u); col.fill(0u);\n\n        vector<Action> ans;\n        int cur = pid[0];\n        for (int k = 0; k < M - 1; k++) {\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, pid[k+1], path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = pid[k+1];\n        }\n        return ans;\n    }\n\n    bool validate(const vector<Action>& acts) const {\n        if ((int)acts.size() > LIMIT) return false;\n        vector<vector<uint8_t>> blk(N, vector<uint8_t>(N, 0));\n\n        int r = pts[0].r, c = pts[0].c;\n        int nxt = 1;\n\n        auto dirId = [&](char ch)->int {\n            if (ch == 'U') return 0;\n            if (ch == 'D') return 1;\n            if (ch == 'L') return 2;\n            if (ch == 'R') return 3;\n            return -1;\n        };\n\n        for (const auto& ac : acts) {\n            int d = dirId(ac.d);\n            if (d < 0) return false;\n\n            if (ac.a == 'M') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                if (blk[nr][nc]) return false;\n                r = nr; c = nc;\n            } else if (ac.a == 'S') {\n                int nr = r, nc = c;\n                while (true) {\n                    int tr = nr + DR[d], tc = nc + DC[d];\n                    if (!(0 <= tr && tr < N && 0 <= tc && tc < N)) break;\n                    if (blk[tr][tc]) break;\n                    nr = tr; nc = tc;\n                }\n                r = nr; c = nc;\n            } else if (ac.a == 'A') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                blk[nr][nc] ^= 1;\n            } else {\n                return false;\n            }\n\n            if (nxt < M && r == pts[nxt].r && c == pts[nxt].c) nxt++;\n        }\n\n        return nxt == M;\n    }\n\n    vector<Action> runBeam(int upperBound, const Config& cfg, Clock::time_point dl) {\n        if (upperBound <= 0) return {};\n\n        vector<vector<Node>> layers(M);\n        layers[0].reserve(1);\n        Node init;\n        init.row.fill(0u);\n        init.col.fill(0u);\n        init.cost = 0;\n        init.parent = -1;\n        init.op = 0;\n        init.d1 = init.d2 = 0;\n        init.bcnt = 0;\n        layers[0].push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            if (Clock::now() >= dl) return {};\n\n            int s = pid[k], g = pid[k+1];\n            int W = widthAt(cfg, k);\n            int PRE = max(W + 1, W * cfg.preMul);\n\n            int approxTrans = 1 + 4 + 16 + 16 + (cfg.enableDoubleAlter ? 6 : 0);\n            vector<Node> cand;\n            cand.reserve((int)layers[k].size() * approxTrans + 16);\n\n            for (int si = 0; si < (int)layers[k].size(); si++) {\n                if ((si & 15) == 0 && Clock::now() >= dl) return {};\n                const Node& st = layers[k][si];\n\n                // 0) no prep\n                {\n                    int rem = upperBound - 1 - st.cost;\n                    if (rem >= 0) {\n                        int d0 = bfsDistLimit(st.row, st.col, s, g, rem);\n                        if (d0 < INF) {\n                            Node nd = st;\n                            nd.cost = st.cost + d0;\n                            nd.parent = si;\n                            nd.op = 0;\n                            nd.d1 = nd.d2 = 0;\n                            nd.eval = 0;\n                            cand.push_back(std::move(nd));\n                        }\n                    }\n                }\n\n                // 1) A\n                {\n                    int rem = upperBound - 1 - (st.cost + 1);\n                    if (rem >= 0) {\n                        array<uint32_t,MAXN> rowA = st.row;\n                        array<uint32_t,MAXN> colA = st.col;\n\n                        for (int ad = 0; ad < 4; ad++) {\n                            int tcell = to[s][ad];\n                            if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                            bool was = isBlocked(rowA, tcell);\n                            toggleCell(rowA, colA, tcell);\n\n                            int d = bfsDistLimit(rowA, colA, s, g, rem);\n                            if (d < INF) {\n                                Node nd;\n                                nd.row = rowA;\n                                nd.col = colA;\n                                nd.cost = st.cost + 1 + d;\n                                nd.parent = si;\n                                nd.op = 1;\n                                nd.d1 = (uint8_t)ad;\n                                nd.d2 = 0;\n                                int nb = (int)st.bcnt + (was ? -1 : +1);\n                                if (nb < 0) nb = 0;\n                                nd.bcnt = (uint16_t)nb;\n                                nd.eval = 0;\n                                cand.push_back(std::move(nd));\n                            }\n\n                            toggleCell(rowA, colA, tcell); // revert\n                        }\n                    }\n                }\n\n                // 2) M + A\n                // 3) S + A\n                {\n                    int rem = upperBound - 1 - (st.cost + 2);\n                    if (rem >= 0) {\n                        // M + A\n                        for (int md = 0; md < 4; md++) {\n                            int ncell = to[s][md];\n                            if (ncell == -1) continue;\n                            if (isBlocked(st.row, ncell)) continue; // move first\n\n                            array<uint32_t,MAXN> rowMA = st.row;\n                            array<uint32_t,MAXN> colMA = st.col;\n\n                            for (int ad = 0; ad < 4; ad++) {\n                                int tcell = to[ncell][ad];\n                                if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                                bool was = isBlocked(rowMA, tcell);\n                                toggleCell(rowMA, colMA, tcell);\n\n                                int d = bfsDistLimit(rowMA, colMA, ncell, g, rem);\n                                if (d < INF) {\n                                    Node nd;\n                                    nd.row = rowMA;\n                                    nd.col = colMA;\n                                    nd.cost = st.cost + 2 + d;\n                                    nd.parent = si;\n                                    nd.op = 2;\n                                    nd.d1 = (uint8_t)md;\n                                    nd.d2 = (uint8_t)ad;\n                                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                                    if (nb < 0) nb = 0;\n                                    nd.bcnt = (uint16_t)nb;\n                                    nd.eval = 0;\n                                    cand.push_back(std::move(nd));\n                                }\n\n                                toggleCell(rowMA, colMA, tcell); // revert\n                            }\n                        }\n\n                        // S + A\n                        for (int sd = 0; sd < 4; sd++) {\n                            int ncell = slideDest(st.row, st.col, s, sd);\n                            if (ncell == s) continue; // cannot slide\n\n                            array<uint32_t,MAXN> rowSA = st.row;\n                            array<uint32_t,MAXN> colSA = st.col;\n\n                            for (int ad = 0; ad < 4; ad++) {\n                                int tcell = to[ncell][ad];\n                                if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                                bool was = isBlocked(rowSA, tcell);\n                                toggleCell(rowSA, colSA, tcell);\n\n                                int d = bfsDistLimit(rowSA, colSA, ncell, g, rem);\n                                if (d < INF) {\n                                    Node nd;\n                                    nd.row = rowSA;\n                                    nd.col = colSA;\n                                    nd.cost = st.cost + 2 + d;\n                                    nd.parent = si;\n                                    nd.op = 3;\n                                    nd.d1 = (uint8_t)sd;\n                                    nd.d2 = (uint8_t)ad;\n                                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                                    if (nb < 0) nb = 0;\n                                    nd.bcnt = (uint16_t)nb;\n                                    nd.eval = 0;\n                                    cand.push_back(std::move(nd));\n                                }\n\n                                toggleCell(rowSA, colSA, tcell); // revert\n                            }\n                        }\n\n                        // 4) A + A (optional)\n                        if (cfg.enableDoubleAlter) {\n                            array<uint32_t,MAXN> rowAA = st.row;\n                            array<uint32_t,MAXN> colAA = st.col;\n\n                            for (int d1 = 0; d1 < 4; d1++) {\n                                int c1 = to[s][d1];\n                                if (!allowToggleCell(c1, k, cfg)) continue;\n\n                                bool was1 = isBlocked(rowAA, c1);\n                                toggleCell(rowAA, colAA, c1);\n                                int delta1 = was1 ? -1 : +1;\n\n                                for (int d2 = d1 + 1; d2 < 4; d2++) {\n                                    int c2 = to[s][d2];\n                                    if (!allowToggleCell(c2, k, cfg)) continue;\n\n                                    bool was2 = isBlocked(rowAA, c2); // c2 != c1\n                                    toggleCell(rowAA, colAA, c2);\n\n                                    int d = bfsDistLimit(rowAA, colAA, s, g, rem);\n                                    if (d < INF) {\n                                        Node nd;\n                                        nd.row = rowAA;\n                                        nd.col = colAA;\n                                        nd.cost = st.cost + 2 + d;\n                                        nd.parent = si;\n                                        nd.op = 4;\n                                        nd.d1 = (uint8_t)d1;\n                                        nd.d2 = (uint8_t)d2;\n                                        int nb = (int)st.bcnt + delta1 + (was2 ? -1 : +1);\n                                        if (nb < 0) nb = 0;\n                                        nd.bcnt = (uint16_t)nb;\n                                        nd.eval = 0;\n                                        cand.push_back(std::move(nd));\n                                    }\n\n                                    toggleCell(rowAA, colAA, c2); // revert d2\n                                }\n\n                                toggleCell(rowAA, colAA, c1); // revert d1\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (cand.empty()) return {};\n\n            // Dedup by board\n            sort(cand.begin(), cand.end(), [&](const Node& a, const Node& b) {\n                int cmp = rowCompare(a.row, b.row);\n                if (cmp != 0) return cmp < 0;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.bcnt != b.bcnt) return a.bcnt > b.bcnt;\n                return a.parent < b.parent;\n            });\n\n            vector<Node> uniq;\n            uniq.reserve(cand.size());\n            for (auto& nd : cand) {\n                if (uniq.empty() || rowCompare(uniq.back().row, nd.row) != 0) {\n                    uniq.push_back(nd);\n                } else {\n                    Node& cur = uniq.back();\n                    if (nd.cost < cur.cost || (nd.cost == cur.cost && nd.bcnt > cur.bcnt)) {\n                        cur = nd;\n                    }\n                }\n            }\n\n            sort(uniq.begin(), uniq.end(), [](const Node& a, const Node& b) {\n                if (a.cost != b.cost) return a.cost < b.cost;\n                return a.bcnt > b.bcnt;\n            });\n\n            if ((int)uniq.size() > PRE) uniq.resize(PRE);\n\n            // Heuristic pruning\n            if ((int)uniq.size() > W) {\n                int from1 = pid[k+1];\n                int to1 = (k + 2 < M ? pid[k+2] : -1);\n                int from2 = (k + 2 < M ? pid[k+2] : -1);\n                int to2 = (k + 3 < M ? pid[k+3] : -1);\n\n                for (auto& nd : uniq) {\n                    int h1 = 0, h2 = 0;\n                    if (to1 != -1) {\n                        h1 = bfsDistLimit(nd.row, nd.col, from1, to1, cfg.evalDistLimit);\n                        if (h1 >= INF) h1 = cfg.evalDistLimit + 20;\n                    }\n                    if (to2 != -1) {\n                        h2 = bfsDistLimit(nd.row, nd.col, from2, to2, cfg.evalDistLimit);\n                        if (h2 >= INF) h2 = cfg.evalDistLimit + 20;\n                    }\n                    int fblk = (cfg.wFutureBlocked > 0) ? countBlockedFutureTargets(nd.row, k + 2) : 0;\n                    nd.eval = nd.cost * cfg.wCost\n                              + h1 * cfg.wH1\n                              + h2 * cfg.wH2\n                              + fblk * cfg.wFutureBlocked\n                              - min<int>(nd.bcnt, 40) * cfg.wBlockBonus;\n                }\n\n                vector<int> ord(uniq.size());\n                iota(ord.begin(), ord.end(), 0);\n                sort(ord.begin(), ord.end(), [&](int i, int j) {\n                    const Node& a = uniq[i];\n                    const Node& b = uniq[j];\n                    if (a.eval != b.eval) return a.eval < b.eval;\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                vector<Node> chosen;\n                chosen.reserve(W);\n                vector<char> used(uniq.size(), 0);\n\n                int elite = max(1, W * cfg.elitePct / 100);\n                elite = min(elite, (int)uniq.size());\n\n                for (int i = 0; i < elite; i++) {\n                    chosen.push_back(uniq[i]);\n                    used[i] = 1;\n                }\n                for (int id : ord) {\n                    if ((int)chosen.size() >= W) break;\n                    if (used[id]) continue;\n                    chosen.push_back(uniq[id]);\n                    used[id] = 1;\n                }\n\n                // keep empty-board state if available\n                bool hasEmpty = false;\n                for (const auto& nd : chosen) {\n                    if (isEmptyBoard(nd.row)) { hasEmpty = true; break; }\n                }\n                if (!hasEmpty) {\n                    for (const auto& nd : uniq) {\n                        if (isEmptyBoard(nd.row)) {\n                            if (!chosen.empty()) chosen.back() = nd;\n                            else chosen.push_back(nd);\n                            break;\n                        }\n                    }\n                }\n\n                sort(chosen.begin(), chosen.end(), [](const Node& a, const Node& b) {\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                uniq.swap(chosen);\n            }\n\n            if (uniq.empty()) return {};\n            layers[k+1].swap(uniq);\n        }\n\n        if (layers[M-1].empty()) return {};\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)layers[M-1].size(); i++) {\n            if (layers[M-1][i].cost < layers[M-1][bestIdx].cost) bestIdx = i;\n        }\n\n        struct Dec { uint8_t op, d1, d2; };\n        vector<Dec> dec(max(0, M - 1));\n\n        int idx = bestIdx;\n        for (int k = M - 2; k >= 0; k--) {\n            const Node& nd = layers[k+1][idx];\n            dec[k] = Dec{nd.op, nd.d1, nd.d2};\n            idx = nd.parent;\n            if (idx < 0 && k > 0) return {};\n        }\n        if (M >= 2 && idx < 0) return {};\n\n        // Reconstruct concrete actions\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u);\n        col.fill(0u);\n\n        int cur = pid[0];\n        vector<Action> ans;\n        ans.reserve(layers[M-1][bestIdx].cost + 16);\n\n        for (int k = 0; k < M - 1; k++) {\n            int s = pid[k], g = pid[k+1];\n            if (cur != s) return {};\n\n            auto [op, d1, d2] = dec[k];\n\n            if (op == 1) { // A\n                int t = to[cur][d1];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d1]});\n                toggleCell(row, col, t);\n\n            } else if (op == 2) { // M + A\n                int ncell = to[cur][d1];\n                if (ncell == -1 || isBlocked(row, ncell)) return {};\n                ans.push_back({'M', DCH[d1]});\n                cur = ncell;\n\n                int t = to[cur][d2];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t);\n\n            } else if (op == 3) { // S + A\n                int ncell = slideDest(row, col, cur, d1);\n                if (ncell == cur) return {};\n                ans.push_back({'S', DCH[d1]});\n                cur = ncell;\n\n                int t = to[cur][d2];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t);\n\n            } else if (op == 4) { // A + A\n                int t1 = to[cur][d1];\n                int t2 = to[cur][d2];\n                if (t1 == -1 || t2 == -1 || d1 == d2) return {};\n                ans.push_back({'A', DCH[d1]});\n                toggleCell(row, col, t1);\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t2);\n            }\n\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, g, path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = g;\n        }\n\n        return ans;\n    }\n\n    void init() {\n        n2 = N * N;\n        LIMIT = 2 * N * M;\n\n        pid.resize(M);\n        for (int i = 0; i < M; i++) pid[i] = pts[i].r * N + pts[i].c;\n\n        cellR.resize(n2);\n        cellC.resize(n2);\n        to.assign(n2, array<int,4>{-1,-1,-1,-1});\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                cellR[id] = r;\n                cellC[id] = c;\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + DR[d], nc = c + DC[d];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                        to[id][d] = nr * N + nc;\n                    }\n                }\n            }\n        }\n\n        for (int i = 0; i < MAXN; i++) {\n            lowMask[i] = (i == 0 ? 0u : ((1u << i) - 1u));\n            highMask[i] = ~((1u << (i + 1)) - 1u);\n        }\n\n        targetIdxAtCell.assign(n2, -1);\n        for (int i = 0; i < M; i++) {\n            targetIdxAtCell[pid[i]] = i;\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        pts.resize(M);\n        for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n        init();\n\n        vector<Action> best = fallbackNoBlock();\n        if (best.empty() || (int)best.size() > LIMIT || !validate(best)) {\n            best = fallbackManhattan();\n        }\n\n        auto start = Clock::now();\n        auto globalDL = start + chrono::milliseconds(1950);\n\n        Config c1;\n        c1.allowFutureToggle = false;\n        c1.enableDoubleAlter = false;\n        c1.wEarly = 190; c1.wMid = 150; c1.wLate = 115;\n        c1.preMul = 6; c1.elitePct = 50;\n        c1.wCost = 10; c1.wH1 = 4; c1.wH2 = 2;\n        c1.wFutureBlocked = 0; c1.wBlockBonus = 1;\n        c1.evalDistLimit = 55;\n\n        Config c2;\n        c2.allowFutureToggle = true;\n        c2.enableDoubleAlter = false;\n        c2.wEarly = 175; c2.wMid = 140; c2.wLate = 105;\n        c2.preMul = 6; c2.elitePct = 45;\n        c2.wCost = 10; c2.wH1 = 5; c2.wH2 = 2;\n        c2.wFutureBlocked = 4; c2.wBlockBonus = 1;\n        c2.evalDistLimit = 55;\n\n        Config c3;\n        c3.allowFutureToggle = true;\n        c3.enableDoubleAlter = true;\n        c3.wEarly = 145; c3.wMid = 115; c3.wLate = 90;\n        c3.preMul = 5; c3.elitePct = 40;\n        c3.wCost = 10; c3.wH1 = 5; c3.wH2 = 3;\n        c3.wFutureBlocked = 4; c3.wBlockBonus = 1;\n        c3.evalDistLimit = 55;\n\n        Config c4 = c3;\n        c4.wEarly = 130; c4.wMid = 105; c4.wLate = 82;\n        c4.elitePct = 35;\n        c4.wH1 = 6;\n        c4.wFutureBlocked = 5;\n        c4.evalDistLimit = 50;\n\n        vector<pair<Config, int>> plan = {\n            {c1, 1100},\n            {c2, 1650},\n            {c3, 1930},\n            {c4, 1950},\n        };\n\n        for (auto &p : plan) {\n            auto dl = min(globalDL, start + chrono::milliseconds(p.second));\n            if (Clock::now() >= dl) continue;\n\n            vector<Action> cand = runBeam((int)best.size(), p.first, dl);\n            if (cand.empty()) continue;\n            if ((int)cand.size() <= LIMIT && cand.size() < best.size() && validate(cand)) {\n                best.swap(cand);\n            }\n        }\n\n        if ((int)best.size() > LIMIT || !validate(best)) {\n            best = fallbackManhattan();\n        }\n\n        for (const auto& ac : best) {\n            cout << ac.a << ' ' << ac.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}"},"8":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int BOARD = 10000;\nenum Side { LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3 };\n\nstruct Company {\n    int x, y, r; // desired point cell (x,y), target area r\n};\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n};\n\nstruct State {\n    vector<Rect> rects;\n    vector<long long> area;\n    vector<double> p;\n    double total = 0.0;\n};\n\nint n;\nvector<Company> C;\nchrono::steady_clock::time_point gStart;\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - gStart).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed ? seed : 88172645463325252ull) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int l, int r) {\n        if (l >= r) return l;\n        uint64_t span = (uint64_t)(r - l + 1);\n        return l + (int)(nextU64() % span);\n    }\n};\n\ninline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\ninline long long rectArea(const Rect& rc) {\n    return 1LL * (rc.r - rc.l) * (rc.t - rc.b);\n}\n\ninline double satisfaction(long long s, long long target) {\n    if (s <= 0) return 0.0;\n    double ratio = (s < target) ? (double)s / (double)target : (double)target / (double)s;\n    double d = 1.0 - ratio;\n    return 1.0 - d * d;\n}\n\ninline int getCoord(const Rect& rc, int side) {\n    if (side == LEFT) return rc.l;\n    if (side == RIGHT) return rc.r;\n    if (side == BOTTOM) return rc.b;\n    return rc.t;\n}\n\ninline void setCoord(Rect& rc, int side, int v) {\n    if (side == LEFT) rc.l = v;\n    else if (side == RIGHT) rc.r = v;\n    else if (side == BOTTOM) rc.b = v;\n    else rc.t = v;\n}\n\ninline long long areaWithSide(const Rect& rc, int side, int v) {\n    if (side == LEFT) return 1LL * (rc.r - v) * (rc.t - rc.b);\n    if (side == RIGHT) return 1LL * (v - rc.l) * (rc.t - rc.b);\n    if (side == BOTTOM) return 1LL * (rc.r - rc.l) * (rc.t - v);\n    return 1LL * (rc.r - rc.l) * (v - rc.b);\n}\n\nState makeState(const vector<Rect>& rects) {\n    State st;\n    st.rects = rects;\n    st.area.resize(n);\n    st.p.resize(n);\n    st.total = 0.0;\n    for (int i = 0; i < n; ++i) {\n        st.area[i] = rectArea(st.rects[i]);\n        st.p[i] = satisfaction(st.area[i], C[i].r);\n        st.total += st.p[i];\n    }\n    return st;\n}\n\nbool validateRects(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = rects[i];\n        if (!(0 <= a.l && a.l < a.r && a.r <= BOARD && 0 <= a.b && a.b < a.t && a.t <= BOARD)) return false;\n        if (!(a.l <= C[i].x && C[i].x + 1 <= a.r && a.b <= C[i].y && C[i].y + 1 <= a.t)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect& a = rects[i];\n            const Rect& b = rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && overlap1D(a.b, a.t, b.b, b.t)) return false;\n        }\n    }\n    return true;\n}\n\n// Movable range for one side, optionally ignoring one rectangle (for pair moves).\npair<int, int> sideRange(const State& st, int i, int side, int ignore = -1) {\n    const Rect& a = st.rects[i];\n\n    if (side == LEFT) {\n        int L = 0;\n        int U = min(C[i].x, a.r - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.l < a.r) L = max(L, b.r);\n        }\n        return {L, U};\n    }\n\n    if (side == RIGHT) {\n        int L = max(C[i].x + 1, a.l + 1);\n        int U = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.r > a.l) U = min(U, b.l);\n        }\n        return {L, U};\n    }\n\n    if (side == BOTTOM) {\n        int L = 0;\n        int U = min(C[i].y, a.t - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && b.b < a.t) L = max(L, b.t);\n        }\n        return {L, U};\n    }\n\n    int L = max(C[i].y + 1, a.b + 1);\n    int U = BOARD;\n    for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n        const Rect& b = st.rects[j];\n        if (overlap1D(a.l, a.r, b.l, b.r) && b.t > a.b) U = min(U, b.b);\n    }\n    return {L, U};\n}\n\npair<int, int> shiftRangeX(const State& st, int i) {\n    const Rect& a = st.rects[i];\n\n    int LB = -a.l;\n    int UB = BOARD - a.r;\n\n    // point containment\n    LB = max(LB, C[i].x + 1 - a.r);\n    UB = min(UB, C[i].x - a.l);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.b, a.t, b.b, b.t)) continue;\n        if (b.r <= a.l) LB = max(LB, b.r - a.l);\n        else if (b.l >= a.r) UB = min(UB, b.l - a.r);\n        else return {1, 0}; // invalid state\n    }\n    return {LB, UB};\n}\n\npair<int, int> shiftRangeY(const State& st, int i) {\n    const Rect& a = st.rects[i];\n\n    int LB = -a.b;\n    int UB = BOARD - a.t;\n\n    // point containment\n    LB = max(LB, C[i].y + 1 - a.t);\n    UB = min(UB, C[i].y - a.b);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.l, a.r, b.l, b.r)) continue;\n        if (b.t <= a.b) LB = max(LB, b.t - a.b);\n        else if (b.b >= a.t) UB = min(UB, b.b - a.t);\n        else return {1, 0}; // invalid state\n    }\n    return {LB, UB};\n}\n\nconstexpr int MAX_CAND = 24;\n\ninline void addCand(int arr[], int& m, int v, int L, int U) {\n    if (v < L || v > U) return;\n    for (int i = 0; i < m; ++i) if (arr[i] == v) return;\n    if (m < MAX_CAND) arr[m++] = v;\n}\n\nvoid fillCandidatesForSide(const State& st, int i, int side, int L, int U, int arr[], int& m, RNG* rng = nullptr) {\n    m = 0;\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n\n    addCand(arr, m, cur, L, U);\n    addCand(arr, m, L, L, U);\n    addCand(arr, m, U, L, U);\n    addCand(arr, m, (L + U) >> 1, L, U);\n\n    long long target = C[i].r;\n    if (side == LEFT || side == RIGHT) {\n        int h = a.t - a.b;\n        if (h > 0) {\n            int w0 = (int)llround((double)target / (double)h);\n            for (int dw = -2; dw <= 2; ++dw) {\n                int w = w0 + dw;\n                if (w < 1) continue;\n                int v = (side == LEFT) ? (a.r - w) : (a.l + w);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    } else {\n        int w = a.r - a.l;\n        if (w > 0) {\n            int h0 = (int)llround((double)target / (double)w);\n            for (int dh = -2; dh <= 2; ++dh) {\n                int h = h0 + dh;\n                if (h < 1) continue;\n                int v = (side == BOTTOM) ? (a.t - h) : (a.b + h);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    }\n\n    if (rng && U > L) {\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n    }\n}\n\nint bestCoordForSide(const State& st, int i, int side, int L, int U) {\n    int cands[MAX_CAND], m;\n    fillCandidatesForSide(st, i, side, L, U, cands, m, nullptr);\n\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n    int best = cur;\n    double bestP = st.p[i];\n\n    for (int k = 0; k < m; ++k) {\n        int v = cands[k];\n        long long ar = areaWithSide(a, side, v);\n        double np = satisfaction(ar, C[i].r);\n        if (np > bestP + 1e-15 || (fabs(np - bestP) <= 1e-15 && abs(v - cur) < abs(best - cur))) {\n            bestP = np;\n            best = v;\n        }\n    }\n    return best;\n}\n\ninline void applySingleSide(State& st, int i, int side, int v) {\n    st.total -= st.p[i];\n    setCoord(st.rects[i], side, v);\n    st.area[i] = rectArea(st.rects[i]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.total += st.p[i];\n}\n\nint pickRect(const State& st, RNG& rng) {\n    int best = rng.nextInt(0, n - 1);\n    for (int t = 0; t < 4; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nint pickRect2(const State& st, RNG& rng, int avoid) {\n    int best = rng.nextInt(0, n - 1);\n    if (best == avoid) best = (best + 1) % n;\n    for (int t = 0; t < 4; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (j == avoid) continue;\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nstruct PairMove {\n    int i = -1, j = -1;\n    int sideI = -1, sideJ = -1;\n    int vI = 0, vJ = 0;\n    double delta = 0.0;\n    bool valid = false;\n};\n\nbool proposeHorizontal(const State& st, int left, int right, RNG& rng, bool greedy, PairMove& out) {\n    // left is left of right (in x): left.r <= right.l\n    auto [L1, U1] = sideRange(st, left, RIGHT, right);\n    auto [L2, U2] = sideRange(st, right, LEFT, left);\n\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false;\n\n    int curX = st.rects[left].r;\n    int curY = st.rects[right].l;\n    double oldS = st.p[left] + st.p[right];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, left, RIGHT, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, right, LEFT, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n                long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n                double s = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n        long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n        double ns = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposeVertical(const State& st, int bottom, int top, RNG& rng, bool greedy, PairMove& out) {\n    // bottom is below top (in y): bottom.t <= top.b\n    auto [L1, U1] = sideRange(st, bottom, TOP, top);\n    auto [L2, U2] = sideRange(st, top, BOTTOM, bottom);\n\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false;\n\n    int curX = st.rects[bottom].t;\n    int curY = st.rects[top].b;\n    double oldS = st.p[bottom] + st.p[top];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, bottom, TOP, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, top, BOTTOM, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n                long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n                double s = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n        long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n        double ns = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposePairMove(const State& st, int i, int j, RNG& rng, bool greedy, PairMove& out) {\n    if (i == j) return false;\n    const Rect& a = st.rects[i];\n    const Rect& b = st.rects[j];\n\n    bool found = false;\n    PairMove best;\n\n    // Horizontal relation\n    if (overlap1D(a.b, a.t, b.b, b.t)) {\n        if (a.r <= b.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, i, j, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        } else if (b.r <= a.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, j, i, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        }\n    }\n\n    // Vertical relation\n    if (overlap1D(a.l, a.r, b.l, b.r)) {\n        if (a.t <= b.b) {\n            PairMove mv;\n            if (proposeVertical(st, i, j, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        } else if (b.t <= a.b) {\n            PairMove mv;\n            if (proposeVertical(st, j, i, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        }\n    }\n\n    if (!found) return false;\n    out = best;\n    return true;\n}\n\ninline void applyPairMove(State& st, const PairMove& mv) {\n    int i = mv.i, j = mv.j;\n    st.total -= st.p[i] + st.p[j];\n\n    setCoord(st.rects[i], mv.sideI, mv.vI);\n    setCoord(st.rects[j], mv.sideJ, mv.vJ);\n\n    st.area[i] = rectArea(st.rects[i]);\n    st.area[j] = rectArea(st.rects[j]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.p[j] = satisfaction(st.area[j], C[j].r);\n\n    st.total += st.p[i] + st.p[j];\n}\n\n// Build neighbor-focused pair list (nearest left/right/up/down for each rectangle)\nvector<pair<int, int>> buildNeighborPairs(const State& st) {\n    vector<pair<int, int>> pairs;\n    vector<unsigned char> used(n * n, 0);\n    auto addPair = [&](int a, int b) {\n        if (a < 0 || b < 0 || a == b) return;\n        if (a > b) swap(a, b);\n        int id = a * n + b;\n        if (!used[id]) {\n            used[id] = 1;\n            pairs.push_back({a, b});\n        }\n    };\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = st.rects[i];\n\n        int leftJ = -1, leftV = -1;\n        int rightJ = -1, rightV = BOARD + 1;\n        int downJ = -1, downV = -1;\n        int upJ = -1, upV = BOARD + 1;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& b = st.rects[j];\n\n            if (overlap1D(a.b, a.t, b.b, b.t)) {\n                if (b.r <= a.l && b.r > leftV) {\n                    leftV = b.r;\n                    leftJ = j;\n                }\n                if (b.l >= a.r && b.l < rightV) {\n                    rightV = b.l;\n                    rightJ = j;\n                }\n            }\n\n            if (overlap1D(a.l, a.r, b.l, b.r)) {\n                if (b.t <= a.b && b.t > downV) {\n                    downV = b.t;\n                    downJ = j;\n                }\n                if (b.b >= a.t && b.b < upV) {\n                    upV = b.b;\n                    upJ = j;\n                }\n            }\n        }\n\n        addPair(i, leftJ);\n        addPair(i, rightJ);\n        addPair(i, downJ);\n        addPair(i, upJ);\n    }\n\n    return pairs;\n}\n\npair<int, int> pickNeighborPair(const State& st, const vector<pair<int, int>>& pairs, RNG& rng) {\n    if (pairs.empty()) return {-1, -1};\n    int m = (int)pairs.size();\n\n    int bestIdx = rng.nextInt(0, m - 1);\n    double bestScore = -1e100;\n\n    int trials = min(6, m);\n    for (int t = 0; t < trials; ++t) {\n        int idx = rng.nextInt(0, m - 1);\n        auto [i, j] = pairs[idx];\n\n        double e1 = (double)st.area[i] / (double)C[i].r - 1.0;\n        double e2 = (double)st.area[j] / (double)C[j].r - 1.0;\n        double opposite = max(0.0, -e1 * e2); // useful for area transfer\n        double score = (1.0 - st.p[i]) + (1.0 - st.p[j]) + 0.25 * opposite;\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestIdx = idx;\n        }\n    }\n    return pairs[bestIdx];\n}\n\nvoid greedyOptimize(State& st, RNG& rng, int maxPass) {\n    vector<int> ord(n);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (st.p[a] != st.p[b]) return st.p[a] < st.p[b];\n            return a < b;\n        });\n\n        int rndSwap = max(1, n / 12);\n        for (int s = 0; s < rndSwap; ++s) {\n            int i = rng.nextInt(0, n - 1);\n            int j = rng.nextInt(0, n - 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int idx = 0; idx < n; ++idx) {\n            int i = ord[idx];\n            double oldP = st.p[i];\n\n            int bestSide = -1;\n            int bestV = 0;\n            double bestDelta = 1e-12;\n\n            for (int side = 0; side < 4; ++side) {\n                auto [L, U] = sideRange(st, i, side);\n                if (L > U) continue;\n\n                int curV = getCoord(st.rects[i], side);\n                int v = bestCoordForSide(st, i, side, L, U);\n                if (v == curV) continue;\n\n                long long ar = areaWithSide(st.rects[i], side, v);\n                double np = satisfaction(ar, C[i].r);\n                double delta = np - oldP;\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSide = side;\n                    bestV = v;\n                }\n            }\n\n            if (bestSide != -1) {\n                applySingleSide(st, i, bestSide, bestV);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid pairGreedyOptimize(State& st, RNG& rng, int maxPass) {\n    for (int pass = 0; pass < maxPass; ++pass) {\n        auto pairs = buildNeighborPairs(st);\n        if (pairs.empty()) break;\n\n        for (int i = (int)pairs.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(0, i);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        for (auto [a, b] : pairs) {\n            PairMove mv;\n            if (!proposePairMove(st, a, b, rng, true, mv)) continue;\n            if (mv.delta > 1e-12) {\n                applyPairMove(st, mv);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\n// -------- Randomized guillotine initializer --------\nstruct SplitCand {\n    int ori; // 0 vertical, 1 horizontal\n    int k;\n    int t;\n    double cost;\n};\n\nint buildCallCount = 0;\nconstexpr int BUILD_CALL_LIMIT = 80000;\n\nbool buildPartitionRec(const vector<int>& ids, int L, int B, int R, int T, vector<Rect>& out, RNG& rng) {\n    if (++buildCallCount > BUILD_CALL_LIMIT) return false;\n\n    int m = (int)ids.size();\n    if (m == 0) return true;\n    if (L >= R || B >= T) return false;\n    if (1LL * (R - L) * (T - B) < m) return false;\n\n    if (m == 1) {\n        int id = ids[0];\n        if (!(L <= C[id].x && C[id].x + 1 <= R && B <= C[id].y && C[id].y + 1 <= T)) return false;\n        out[id] = {L, B, R, T};\n        return true;\n    }\n\n    int W = R - L, H = T - B;\n    if (W <= 0 || H <= 0) return false;\n\n    vector<int> ox = ids, oy = ids;\n    sort(ox.begin(), ox.end(), [](int a, int b) {\n        if (C[a].x != C[b].x) return C[a].x < C[b].x;\n        return C[a].y < C[b].y;\n    });\n    sort(oy.begin(), oy.end(), [](int a, int b) {\n        if (C[a].y != C[b].y) return C[a].y < C[b].y;\n        return C[a].x < C[b].x;\n    });\n\n    vector<long long> px(m + 1, 0), py(m + 1, 0);\n    for (int i = 0; i < m; ++i) {\n        px[i + 1] = px[i] + C[ox[i]].r;\n        py[i + 1] = py[i] + C[oy[i]].r;\n    }\n    long long totalR = px[m];\n\n    vector<SplitCand> cands;\n    cands.reserve(2 * (m - 1));\n\n    // Vertical split\n    if (W >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int xl = C[ox[k - 1]].x;\n            int xr = C[ox[k]].x;\n            int low = max(L + 1, xl + 1);\n            int high = min(R - 1, xr);\n            if (low > high) continue;\n\n            long long leftR = px[k];\n            long long rightR = totalR - leftR;\n\n            int t = (int)llround(L + (double)leftR / (double)H);\n            t = max(low, min(high, t));\n\n            long long leftArea = 1LL * (t - L) * H;\n            long long rightArea = 1LL * (R - t) * H;\n\n            double cost = fabs((double)(leftArea - leftR)) + fabs((double)(rightArea - rightR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({0, k, t, cost});\n        }\n    }\n\n    // Horizontal split\n    if (H >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int yb = C[oy[k - 1]].y;\n            int yt = C[oy[k]].y;\n            int low = max(B + 1, yb + 1);\n            int high = min(T - 1, yt);\n            if (low > high) continue;\n\n            long long botR = py[k];\n            long long topR = totalR - botR;\n\n            int t = (int)llround(B + (double)botR / (double)W);\n            t = max(low, min(high, t));\n\n            long long botArea = 1LL * (t - B) * W;\n            long long topArea = 1LL * (T - t) * W;\n\n            double cost = fabs((double)(botArea - botR)) + fabs((double)(topArea - topR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({1, k, t, cost});\n        }\n    }\n\n    if (cands.empty()) return false;\n\n    sort(cands.begin(), cands.end(), [](const SplitCand& a, const SplitCand& b) {\n        return a.cost < b.cost;\n    });\n\n    int lim = min((int)cands.size(), 18);\n    for (int i = 0; i < lim; ++i) {\n        int span = min(3, lim - 1 - i);\n        if (span > 0) {\n            int j = i + rng.nextInt(0, span);\n            swap(cands[i], cands[j]);\n        }\n    }\n\n    for (int idx = 0; idx < lim; ++idx) {\n        const SplitCand& c = cands[idx];\n\n        if (c.ori == 0) {\n            long long areaL = 1LL * (c.t - L) * (T - B);\n            long long areaR = 1LL * (R - c.t) * (T - B);\n            if (areaL < c.k || areaR < (m - c.k)) continue;\n\n            vector<int> leftIds(ox.begin(), ox.begin() + c.k);\n            vector<int> rightIds(ox.begin() + c.k, ox.end());\n\n            if (buildPartitionRec(leftIds, L, B, c.t, T, out, rng) &&\n                buildPartitionRec(rightIds, c.t, B, R, T, out, rng)) {\n                return true;\n            }\n        } else {\n            long long areaB = 1LL * (R - L) * (c.t - B);\n            long long areaT = 1LL * (R - L) * (T - c.t);\n            if (areaB < c.k || areaT < (m - c.k)) continue;\n\n            vector<int> botIds(oy.begin(), oy.begin() + c.k);\n            vector<int> topIds(oy.begin() + c.k, oy.end());\n\n            if (buildPartitionRec(botIds, L, B, R, c.t, out, rng) &&\n                buildPartitionRec(topIds, L, c.t, R, T, out, rng)) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid addPool(vector<State>& pool, const State& st, int cap = 8) {\n    pool.push_back(st);\n    sort(pool.begin(), pool.end(), [](const State& a, const State& b) {\n        return a.total > b.total;\n    });\n    if ((int)pool.size() > cap) pool.resize(cap);\n}\n\nvoid anneal(State& cur, State& bestGlobal, RNG& rng,\n            double tEnd, double T0, double T1, bool allowKick) {\n    double tStart = elapsedSec();\n    if (tEnd <= tStart + 1e-4) return;\n    double span = tEnd - tStart;\n\n    State bestLocal = cur;\n    auto neighborPairs = buildNeighborPairs(cur);\n\n    double nextRebuild = tStart + 0.22;\n    double nextRefine = tStart + 0.58;\n    double lastImprove = tStart;\n\n    long long iter = 0;\n    double temp = T0;\n\n    while (true) {\n        double t = 0.0;\n        if ((iter & 255LL) == 0) {\n            t = elapsedSec();\n            if (t >= tEnd) break;\n\n            double prog = (t - tStart) / span;\n            if (prog < 0.0) prog = 0.0;\n            if (prog > 1.0) prog = 1.0;\n            temp = T0 * pow(T1 / T0, prog);\n\n            if (t >= nextRebuild) {\n                neighborPairs = buildNeighborPairs(cur);\n                nextRebuild = t + 0.22;\n            }\n\n            if (t >= nextRefine) {\n                pairGreedyOptimize(cur, rng, 1);\n                greedyOptimize(cur, rng, 2);\n\n                if (cur.total > bestLocal.total + 1e-15) {\n                    bestLocal = cur;\n                    if (bestLocal.total > bestGlobal.total) bestGlobal = bestLocal;\n                    lastImprove = t;\n                }\n\n                nextRefine = t + 0.58;\n            }\n\n            if (allowKick && t - lastImprove > 0.90) {\n                if (bestLocal.total > cur.total + 1e-12) cur = bestLocal;\n\n                // light random perturb\n                for (int z = 0; z < 3; ++z) {\n                    int i = pickRect(cur, rng);\n                    int side = rng.nextInt(0, 3);\n                    auto [L, U] = sideRange(cur, i, side);\n                    if (L <= U) {\n                        int v = rng.nextInt(L, U);\n                        if (v != getCoord(cur.rects[i], side)) applySingleSide(cur, i, side, v);\n                    }\n                }\n                neighborPairs = buildNeighborPairs(cur);\n                lastImprove = t;\n            }\n        }\n\n        double op = rng.nextDouble();\n\n        if (op < 0.56) {\n            // Single side move\n            int i = pickRect(cur, rng);\n            int side = rng.nextInt(0, 3);\n\n            auto [L, U] = sideRange(cur, i, side);\n            if (L > U) { ++iter; continue; }\n\n            int curV = getCoord(cur.rects[i], side);\n            int v = curV;\n\n            double mode = rng.nextDouble();\n            if (mode < 0.55) {\n                v = bestCoordForSide(cur, i, side, L, U);\n            } else if (mode < 0.85) {\n                int spanv = U - L;\n                int step = max(1, (int)(spanv * 0.35));\n                int d = rng.nextInt(-step, step);\n                v = curV + d;\n                if (v < L) v = L;\n                if (v > U) v = U;\n            } else {\n                v = rng.nextInt(L, U);\n            }\n\n            if (v != curV) {\n                long long newA = areaWithSide(cur.rects[i], side, v);\n                double newP = satisfaction(newA, C[i].r);\n                double delta = newP - cur.p[i];\n\n                if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                    cur.total += delta;\n                    cur.p[i] = newP;\n                    cur.area[i] = newA;\n                    setCoord(cur.rects[i], side, v);\n                }\n            }\n\n        } else if (op < 0.86) {\n            // Pair move\n            int i = -1, j = -1;\n            if (!neighborPairs.empty() && rng.nextDouble() < 0.86) {\n                auto pr = pickNeighborPair(cur, neighborPairs, rng);\n                i = pr.first; j = pr.second;\n            } else {\n                i = pickRect(cur, rng);\n                j = pickRect2(cur, rng, i);\n            }\n\n            if (i >= 0 && j >= 0 && i != j) {\n                PairMove mv;\n                bool greedySel = (rng.nextDouble() < 0.68);\n                if (proposePairMove(cur, i, j, rng, greedySel, mv)) {\n                    double delta = mv.delta;\n                    if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                        applyPairMove(cur, mv);\n                    }\n                }\n            }\n\n        } else if (op < 0.93) {\n            // Shift X\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeX(cur, i);\n            if (LB <= UB) {\n                int dx = 0;\n                if (LB == UB) dx = LB;\n                else if (rng.nextDouble() < 0.55) dx = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dx = rng.nextInt(LB, UB);\n\n                if (dx != 0) {\n                    cur.rects[i].l += dx;\n                    cur.rects[i].r += dx;\n                }\n            }\n\n        } else {\n            // Shift Y\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeY(cur, i);\n            if (LB <= UB) {\n                int dy = 0;\n                if (LB == UB) dy = LB;\n                else if (rng.nextDouble() < 0.55) dy = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dy = rng.nextInt(LB, UB);\n\n                if (dy != 0) {\n                    cur.rects[i].b += dy;\n                    cur.rects[i].t += dy;\n                }\n            }\n        }\n\n        if (cur.total > bestLocal.total + 1e-15) {\n            bestLocal = cur;\n            if (bestLocal.total > bestGlobal.total) bestGlobal = bestLocal;\n        }\n\n        ++iter;\n    }\n\n    cur = bestLocal;\n    if (cur.total > bestGlobal.total) bestGlobal = cur;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    C.resize(n);\n\n    uint64_t seed = 1469598103934665603ull ^ (uint64_t)n * 1000003ull;\n    for (int i = 0; i < n; ++i) {\n        cin >> C[i].x >> C[i].y >> C[i].r;\n        seed ^= (uint64_t)(C[i].x + 1) * 1000003ull;\n        seed ^= (uint64_t)(C[i].y + 1) * 1009837ull;\n        seed ^= (uint64_t)(C[i].r + 3) * 10000019ull;\n        seed *= 1099511628211ull;\n    }\n    RNG rng(seed);\n\n    gStart = chrono::steady_clock::now();\n\n    vector<State> pool;\n    pool.reserve(10);\n\n    // Base 1x1 state\n    vector<Rect> baseRects(n);\n    for (int i = 0; i < n; ++i) {\n        baseRects[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n    }\n    State base = makeState(baseRects);\n    addPool(pool, base, 8);\n\n    // Multiple 1x1-polished variants\n    for (int rep = 0; rep < 4; ++rep) {\n        if (elapsedSec() > 0.55) break;\n        State st = base;\n        greedyOptimize(st, rng, 32 + rep * 4);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 10);\n        addPool(pool, st, 8);\n    }\n\n    // Randomized guillotine initial states\n    const double INIT_END = 1.10;\n    int attempts = 0;\n    while (elapsedSec() < INIT_END && attempts < 26) {\n        ++attempts;\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n);\n\n        buildCallCount = 0;\n        bool ok = buildPartitionRec(ids, 0, 0, BOARD, BOARD, rects, rng);\n        if (!ok) continue;\n        if (!validateRects(rects)) continue;\n\n        State st = makeState(rects);\n        greedyOptimize(st, rng, 26);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 8);\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const State& a, const State& b) {\n        return a.total > b.total;\n    });\n\n    State bestInit = pool[0];\n    State bestGlobal = bestInit;\n\n    // Portfolio SA on top few candidates\n    const double PORT_END = 2.75;\n    int K = min((int)pool.size(), 3);\n    for (int idx = 0; idx < K; ++idx) {\n        double now = elapsedSec();\n        if (now >= PORT_END) break;\n        double end = now + (PORT_END - now) / (double)(K - idx);\n\n        State cur = pool[idx];\n        anneal(cur, bestGlobal, rng, end, 0.085, 0.0018, true);\n\n        if (elapsedSec() < PORT_END - 0.04) {\n            pairGreedyOptimize(cur, rng, 1);\n            greedyOptimize(cur, rng, 8);\n            if (cur.total > bestGlobal.total) bestGlobal = cur;\n        }\n    }\n\n    // Final intensification SA\n    State cur = bestGlobal;\n    const double FINAL_SA_END = 4.72;\n    if (elapsedSec() < FINAL_SA_END) {\n        anneal(cur, bestGlobal, rng, FINAL_SA_END, 0.045, 0.00005, true);\n    }\n\n    // Final polish\n    if (elapsedSec() < 4.82) {\n        pairGreedyOptimize(bestGlobal, rng, 2);\n        greedyOptimize(bestGlobal, rng, 24);\n    }\n    if (elapsedSec() < 4.90) {\n        pairGreedyOptimize(bestGlobal, rng, 1);\n        greedyOptimize(bestGlobal, rng, 12);\n    }\n\n    bestGlobal = makeState(bestGlobal.rects);\n\n    // Safety fallback\n    if (!validateRects(bestGlobal.rects)) {\n        if (validateRects(bestInit.rects)) {\n            bestGlobal = bestInit;\n        } else {\n            vector<Rect> safe(n);\n            for (int i = 0; i < n; ++i) safe[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n            bestGlobal = makeState(safe);\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& rc = bestGlobal.rects[i];\n        cout << rc.l << ' ' << rc.b << ' ' << rc.r << ' ' << rc.t << '\\n';\n    }\n\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 N = H * W;\nstatic constexpr int MAXT = 2500;\nstatic constexpr int WORDS = (MAXT + 63) / 64;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + int(next_u64() % uint64_t(r - l + 1));\n    }\n};\n\nstruct Policy {\n    double wVal = 1.0;\n    double wLook = 0.5;\n    double wDeg = 1.0;\n    double wPair = 0.3;\n    double wRand = 0.0;\n    double eps = 0.0;\n    double deadPenalty = 10.0;\n};\n\nstruct RunParam {\n    Policy pol; // rollout policy\n\n    // main-step pre-score\n    double wVal = 1.0, wLook = 0.5, wDeg = 1.0, wPair = 0.3, wMob2 = 0.4;\n    double wNoise = 0.0, epsMain = 0.0;\n    double deadMain = 10.0;\n    double onePenalty = 4.0;\n    int oneUntil = 700;\n\n    // rollout control\n    int evalRollouts = 1;\n    int evalBestExtra = 0;\n    int evalDepth = 0;      // 0 => full\n    int earlyExtra = 0;\n    int earlySteps = 220;\n    int earlyDepthBonus = 30;\n\n    int rollTopK = 2;       // rollout only for top-K pre candidates\n    int rollFreq2 = 1;      // for nc==2, rollout every rollFreq2-th branch\n\n    double mixBest = 0.7;   // blend avg and best rollout\n    double preCoef = 0.7;   // final EV adds preCoef*pre\n    double evalNoise = 0.0;\n\n    double skipGap = 200.0; // if pre-gap large, skip rollout probabilistically\n    double skipProb = 0.7;\n};\n\nstruct Result {\n    long long score = LLONG_MIN;\n    string path;\n};\n\nstruct ModeStat {\n    int n = 0;\n    double mean = 0.0;\n};\n\nenum Mode {\n    FAST = 0,\n    BAL = 1,\n    DEEP = 2,\n    MODE_N = 3\n};\n\nint tileId[N], pval[N], pairLoss[N];\nint degCell[N];\nint nxtCell[N][4];\nchar nxtDir[N][4];\nint nextAll[N][4];\nint startCell = 0, M = 0;\n\nint tmpTileSeen[MAXT];\nint tmpTileToken = 1;\n\ninline bool bit_get(const uint64_t* bs, int t) {\n    return (bs[t >> 6] >> (t & 63)) & 1ULL;\n}\ninline void bit_set(uint64_t* bs, int t) {\n    bs[t >> 6] |= 1ULL << (t & 63);\n}\ninline void bit_clear_all(uint64_t* bs) {\n    memset(bs, 0, sizeof(uint64_t) * WORDS);\n}\n\ninline int charToDir(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\ninline bool betterResult(const Result& a, const Result& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.path.size() > b.path.size();\n}\n\ninline int gatherMovesMain(int cur, const uint64_t* vis, int outCands[4], char outDirs[4]) {\n    int nc = 0;\n    for (int k = 0; k < degCell[cur]; k++) {\n        int to = nxtCell[cur][k];\n        if (!bit_get(vis, tileId[to])) {\n            outCands[nc] = to;\n            outDirs[nc] = nxtDir[cur][k];\n            nc++;\n        }\n    }\n    return nc;\n}\n\ninline int gatherMovesSimple(int cur, const uint64_t* vis, int outCands[4]) {\n    int nc = 0;\n    for (int k = 0; k < degCell[cur]; k++) {\n        int to = nxtCell[cur][k];\n        if (!bit_get(vis, tileId[to])) outCands[nc++] = to;\n    }\n    return nc;\n}\n\ninline int nextTmpToken() {\n    ++tmpTileToken;\n    if (tmpTileToken == INT_MAX) {\n        memset(tmpTileSeen, 0, sizeof(tmpTileSeen));\n        tmpTileToken = 1;\n    }\n    return tmpTileToken;\n}\n\n// Cheap local future-mobility feature:\n// count distinct unvisited tiles within <=2 steps from cand (excluding cand's tile).\nint countTwoStepTiles(int cand, const uint64_t* vis) {\n    int token = nextTmpToken();\n    int blocked = tileId[cand];\n    int cnt = 0;\n\n    auto addTile = [&](int t) {\n        if (t == blocked) return;\n        if (bit_get(vis, t)) return;\n        if (tmpTileSeen[t] != token) {\n            tmpTileSeen[t] = token;\n            cnt++;\n        }\n    };\n\n    for (int k = 0; k < degCell[cand]; k++) {\n        int u = nxtCell[cand][k];\n        int tu = tileId[u];\n        if (tu == blocked || bit_get(vis, tu)) continue;\n        addTile(tu);\n\n        for (int kk = 0; kk < degCell[u]; kk++) {\n            int w = nxtCell[u][kk];\n            int tw = tileId[w];\n            addTile(tw);\n        }\n    }\n    return cnt;\n}\n\ninline int selectByPolicy(const int cands[4], int nc, const uint64_t* vis, const Policy& pol, XorShift64& rng) {\n    if (nc == 1) return 0;\n    if (rng.next_double() < pol.eps) return rng.next_int(0, nc - 1);\n\n    double bestScore = -1e100;\n    int bestIdx = 0;\n\n    for (int i = 0; i < nc; i++) {\n        int v = cands[i];\n        int degNext = 0;\n        int bestNextVal = 0;\n\n        for (int k = 0; k < degCell[v]; k++) {\n            int u = nxtCell[v][k];\n            if (!bit_get(vis, tileId[u])) {\n                degNext++;\n                if (pval[u] > bestNextVal) bestNextVal = pval[u];\n            }\n        }\n\n        double s = pol.wVal * pval[v]\n                 + pol.wLook * bestNextVal\n                 - pol.wDeg * degNext\n                 - pol.wPair * pairLoss[v]\n                 + pol.wRand * rng.next_double();\n\n        if (degNext == 0) s -= pol.deadPenalty;\n\n        if (s > bestScore + 1e-12) {\n            bestScore = s;\n            bestIdx = i;\n        } else if (fabs(s - bestScore) <= 1e-12) {\n            if (rng.next_u64() & 1ULL) bestIdx = i;\n        }\n    }\n    return bestIdx;\n}\n\nint playoutGain(\n    int cur,\n    uint64_t* vis,\n    const Policy& pol,\n    XorShift64& rng,\n    int maxDepth, // 0 => full\n    const chrono::steady_clock::time_point& deadline\n) {\n    using Clock = chrono::steady_clock;\n    int gain = 0;\n    int step = 0;\n\n    while (true) {\n        if (maxDepth > 0 && step >= maxDepth) break;\n\n        int cands[4];\n        int nc = gatherMovesSimple(cur, vis, cands);\n        if (nc == 0) break;\n\n        int idx = selectByPolicy(cands, nc, vis, pol, rng);\n        int nxt = cands[idx];\n\n        bit_set(vis, tileId[nxt]);\n        cur = nxt;\n        gain += pval[cur];\n        step++;\n\n        if ((step & 63) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n    }\n    return gain;\n}\n\nResult simulate(\n    const RunParam& rp,\n    const string* basePath,\n    int cut,\n    XorShift64& rng,\n    const chrono::steady_clock::time_point& deadline\n) {\n    using Clock = chrono::steady_clock;\n    Result res;\n\n    uint64_t vis[WORDS];\n    bit_clear_all(vis);\n\n    string path;\n    path.reserve(2600);\n\n    int cur = startCell;\n    long long score = pval[cur];\n    bit_set(vis, tileId[cur]);\n\n    // Replay prefix\n    if (basePath && cut > 0) {\n        int L = min<int>(cut, basePath->size());\n        for (int i = 0; i < L; i++) {\n            int d = charToDir((*basePath)[i]);\n            if (d < 0) break;\n            int to = nextAll[cur][d];\n            if (to < 0) break;\n            if (bit_get(vis, tileId[to])) break;\n\n            path.push_back((*basePath)[i]);\n            cur = to;\n            bit_set(vis, tileId[cur]);\n            score += pval[cur];\n        }\n    }\n\n    int stepMain = (int)path.size();\n    int branchCnt = 0;\n\n    while (true) {\n        if ((stepMain & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int cands[4];\n        char dirs[4];\n        int nc = gatherMovesMain(cur, vis, cands, dirs);\n        if (nc == 0) break;\n\n        int pickIdx = 0;\n\n        if (nc == 1) {\n            pickIdx = 0;\n        } else if (rng.next_double() < rp.epsMain) {\n            pickIdx = rng.next_int(0, nc - 1);\n        } else {\n            branchCnt++;\n\n            double pre[4];\n            for (int i = 0; i < nc; i++) {\n                int cand = cands[i];\n\n                int degNext = 0;\n                int bestNextVal = 0;\n                for (int k = 0; k < degCell[cand]; k++) {\n                    int u = nxtCell[cand][k];\n                    if (!bit_get(vis, tileId[u])) {\n                        degNext++;\n                        bestNextVal = max(bestNextVal, pval[u]);\n                    }\n                }\n\n                int mob2 = 0;\n                if (rp.wMob2 > 1e-12) {\n                    mob2 = countTwoStepTiles(cand, vis);\n                }\n\n                double s = rp.wVal * pval[cand]\n                         + rp.wLook * bestNextVal\n                         - rp.wDeg * degNext\n                         - rp.wPair * pairLoss[cand]\n                         + rp.wMob2 * mob2\n                         + rp.wNoise * rng.next_double();\n\n                if (degNext == 0) s -= rp.deadMain;\n                else if (degNext == 1 && stepMain < rp.oneUntil) s -= rp.onePenalty;\n\n                pre[i] = s;\n            }\n\n            int ord[4] = {0, 1, 2, 3};\n            sort(ord, ord + nc, [&](int a, int b) { return pre[a] > pre[b]; });\n\n            bool doRoll = (rp.rollTopK > 0 &&\n                           (rp.evalRollouts + rp.evalBestExtra +\n                            (stepMain < rp.earlySteps ? rp.earlyExtra : 0)) > 0);\n\n            if (doRoll && nc == 2 && rp.rollFreq2 > 1) {\n                if ((branchCnt % rp.rollFreq2) != 0) doRoll = false;\n            }\n\n            if (doRoll && nc >= 2) {\n                double gap = pre[ord[0]] - pre[ord[1]];\n                if (gap > rp.skipGap && rng.next_double() < rp.skipProb) doRoll = false;\n            }\n\n            if (!doRoll || Clock::now() >= deadline) {\n                pickIdx = ord[0];\n            } else {\n                int rankPos[4];\n                for (int r = 0; r < nc; r++) rankPos[ord[r]] = r;\n\n                double ev[4];\n                for (int i = 0; i < nc; i++) ev[i] = rp.preCoef * pre[i];\n\n                for (int i = 0; i < nc; i++) {\n                    int rank = rankPos[i];\n                    if (rank >= rp.rollTopK) continue;\n\n                    int rnum = rp.evalRollouts;\n                    if (rank == 0) rnum += rp.evalBestExtra;\n                    if (stepMain < rp.earlySteps) rnum += rp.earlyExtra;\n                    if (stepMain > 1200 && rnum > 1) rnum--;\n                    if (stepMain > 1700 && rnum > 1) rnum--;\n\n                    if (rnum <= 0) continue;\n                    if (Clock::now() >= deadline) continue;\n\n                    int cand = cands[i];\n                    long long sumGain = 0;\n                    long long bestGain = LLONG_MIN;\n                    int done = 0;\n\n                    for (int r = 0; r < rnum; r++) {\n                        if ((r & 1) == 0 && Clock::now() >= deadline) break;\n\n                        uint64_t vis2[WORDS];\n                        memcpy(vis2, vis, sizeof(vis2));\n                        bit_set(vis2, tileId[cand]);\n\n                        uint64_t sd = rng.next_u64();\n                        sd ^= (uint64_t)(cand + 1) * 0x9e3779b97f4a7c15ULL;\n                        sd ^= (uint64_t)(r + 1) * 0xbf58476d1ce4e5b9ULL;\n                        XorShift64 rr(sd);\n\n                        int depth = rp.evalDepth;\n                        if (depth > 0 && stepMain < rp.earlySteps) depth += rp.earlyDepthBonus;\n\n                        long long g = pval[cand];\n                        g += playoutGain(cand, vis2, rp.pol, rr, depth, deadline);\n\n                        sumGain += g;\n                        bestGain = max(bestGain, g);\n                        done++;\n                    }\n\n                    if (done > 0) {\n                        double avg = (double)sumGain / done;\n                        double pilot = (1.0 - rp.mixBest) * avg + rp.mixBest * (double)bestGain;\n                        ev[i] = pilot + rp.preCoef * pre[i] + rp.evalNoise * rng.next_double();\n                    }\n                }\n\n                pickIdx = 0;\n                double bestEv = ev[0];\n                for (int i = 1; i < nc; i++) {\n                    if (ev[i] > bestEv + 1e-9) {\n                        bestEv = ev[i];\n                        pickIdx = i;\n                    } else if (fabs(ev[i] - bestEv) <= 1e-9) {\n                        if (rng.next_u64() & 1ULL) pickIdx = i;\n                    }\n                }\n            }\n        }\n\n        int nxt = cands[pickIdx];\n        path.push_back(dirs[pickIdx]);\n        cur = nxt;\n        bit_set(vis, tileId[cur]);\n        score += pval[cur];\n        stepMain++;\n    }\n\n    res.score = score;\n    res.path = std::move(path);\n    return res;\n}\n\nint chooseMode(double phase, XorShift64& rng, const array<ModeStat, MODE_N>& st, int totalRuns) {\n    auto weighted = [&]() -> int {\n        double u = rng.next_double();\n        if (phase < 0.28) {\n            if (u < 0.45) return FAST;\n            if (u < 0.83) return BAL;\n            return DEEP;\n        } else if (phase < 0.82) {\n            if (u < 0.15) return FAST;\n            if (u < 0.62) return BAL;\n            return DEEP;\n        } else {\n            if (u < 0.05) return FAST;\n            if (u < 0.30) return BAL;\n            return DEEP;\n        }\n    };\n\n    if (totalRuns >= 8 && rng.next_double() < 0.27) {\n        double logt = log((double)totalRuns + 1.0);\n        int bestM = BAL;\n        double bestS = -1e100;\n\n        for (int m = 0; m < MODE_N; m++) {\n            double mean = (st[m].n > 0 ? st[m].mean : 38000.0);\n            double bonus = 1100.0 * sqrt(logt / (st[m].n + 1.0));\n\n            double bias = 0.0;\n            if (m == FAST) {\n                if (phase < 0.30) bias += 260.0;\n                if (phase > 0.85) bias -= 250.0;\n            } else if (m == BAL) {\n                if (phase >= 0.25 && phase <= 0.85) bias += 120.0;\n            } else { // DEEP\n                if (phase > 0.78) bias += 420.0;\n                if (phase < 0.25) bias -= 180.0;\n            }\n\n            double s = mean + bonus + bias;\n            if (s > bestS) {\n                bestS = s;\n                bestM = m;\n            }\n        }\n        return bestM;\n    }\n\n    return weighted();\n}\n\nRunParam sampleParam(int mode, double phase, XorShift64& rng) {\n    auto R = [&](double l, double r) { return l + (r - l) * rng.next_double(); };\n    RunParam rp{};\n\n    if (mode == FAST) {\n        rp.wVal = R(1.0, 2.4);\n        rp.wLook = R(0.0, 1.4);\n        rp.wDeg = R(-0.3, 4.8);\n        rp.wPair = R(0.0, 1.4);\n        rp.wMob2 = R(0.0, 1.2);\n        rp.wNoise = R(3.0, 30.0);\n        rp.epsMain = R(0.01, 0.14);\n        rp.deadMain = R(0.0, 18.0);\n        rp.onePenalty = R(0.0, 6.0);\n        rp.oneUntil = rng.next_int(420, 760);\n\n        rp.evalRollouts = (rng.next_double() < 0.70 ? 0 : 1);\n        rp.evalBestExtra = (rng.next_double() < 0.35 ? 1 : 0);\n        rp.rollTopK = (rng.next_double() < 0.65 ? 1 : 2);\n        rp.rollFreq2 = (rng.next_double() < 0.60 ? 3 : 4);\n\n        rp.evalDepth = (rng.next_double() < 0.90 ? rng.next_int(120, 230) : 0);\n        rp.earlyExtra = 0;\n        rp.earlySteps = 170;\n        rp.earlyDepthBonus = 25;\n\n        rp.mixBest = R(0.45, 0.82);\n        rp.preCoef = R(0.80, 1.80);\n        rp.evalNoise = R(0.0, 18.0);\n\n        rp.skipGap = R(80.0, 220.0);\n        rp.skipProb = R(0.60, 0.92);\n\n        rp.pol.wVal = R(0.8, 2.3);\n        rp.pol.wLook = R(0.0, 1.4);\n        rp.pol.wDeg = R(-0.3, 4.8);\n        rp.pol.wPair = R(0.0, 1.6);\n        rp.pol.wRand = R(0.0, 14.0);\n        rp.pol.eps = R(0.0, 0.18);\n        rp.pol.deadPenalty = R(0.0, 24.0);\n    } else if (mode == BAL) {\n        rp.wVal = R(1.0, 2.0);\n        rp.wLook = R(0.0, 1.2);\n        rp.wDeg = R(0.0, 4.5);\n        rp.wPair = R(0.0, 1.2);\n        rp.wMob2 = R(0.2, 1.0);\n        rp.wNoise = R(0.0, 12.0);\n        rp.epsMain = R(0.0, 0.06);\n        rp.deadMain = R(4.0, 24.0);\n        rp.onePenalty = R(1.0, 8.0);\n        rp.oneUntil = rng.next_int(560, 900);\n\n        rp.evalRollouts = (rng.next_double() < 0.75 ? 1 : 2);\n        rp.evalBestExtra = (rng.next_double() < 0.45 ? 1 : 0);\n        rp.rollTopK = 2;\n        rp.rollFreq2 = 2;\n\n        rp.evalDepth = (rng.next_double() < 0.60 ? 0 : rng.next_int(150, 280));\n        rp.earlyExtra = (rng.next_double() < 0.40 ? 1 : 0);\n        rp.earlySteps = 220;\n        rp.earlyDepthBonus = 35;\n\n        rp.mixBest = R(0.55, 0.90);\n        rp.preCoef = R(0.40, 1.20);\n        rp.evalNoise = R(0.0, 10.0);\n\n        rp.skipGap = R(140.0, 380.0);\n        rp.skipProb = R(0.45, 0.78);\n\n        rp.pol.wVal = R(0.9, 2.1);\n        rp.pol.wLook = R(0.0, 1.2);\n        rp.pol.wDeg = R(0.0, 4.5);\n        rp.pol.wPair = R(0.0, 1.4);\n        rp.pol.wRand = R(0.0, 8.0);\n        rp.pol.eps = R(0.0, 0.10);\n        rp.pol.deadPenalty = R(1.0, 22.0);\n    } else { // DEEP\n        rp.wVal = R(1.0, 1.8);\n        rp.wLook = R(0.2, 1.0);\n        rp.wDeg = R(0.8, 3.5);\n        rp.wPair = R(0.1, 0.9);\n        rp.wMob2 = R(0.2, 0.9);\n        rp.wNoise = R(0.0, 3.0);\n        rp.epsMain = R(0.0, 0.03);\n        rp.deadMain = R(8.0, 24.0);\n        rp.onePenalty = R(2.0, 10.0);\n        rp.oneUntil = rng.next_int(780, 1100);\n\n        rp.evalRollouts = (rng.next_double() < (phase > 0.90 ? 0.40 : 0.70) ? 2 : 3);\n        rp.evalBestExtra = 1;\n        rp.rollTopK = (rng.next_double() < 0.70 ? 2 : 3);\n        rp.rollFreq2 = 1;\n\n        rp.evalDepth = 0; // full playout\n        rp.earlyExtra = 1;\n        rp.earlySteps = 260;\n        rp.earlyDepthBonus = 0;\n\n        rp.mixBest = R(0.65, 0.93);\n        rp.preCoef = R(0.25, 0.85);\n        rp.evalNoise = R(0.0, 4.0);\n\n        rp.skipGap = R(260.0, 850.0);\n        rp.skipProb = R(0.30, 0.62);\n\n        rp.pol.wVal = R(1.0, 1.9);\n        rp.pol.wLook = R(0.2, 1.1);\n        rp.pol.wDeg = R(0.8, 3.8);\n        rp.pol.wPair = R(0.1, 1.0);\n        rp.pol.wRand = R(0.0, 3.0);\n        rp.pol.eps = R(0.0, 0.05);\n        rp.pol.deadPenalty = R(4.0, 18.0);\n    }\n\n    return rp;\n}\n\nint pickCut(int L, double phase, bool intense, XorShift64& rng) {\n    if (L <= 1) return 0;\n    int hi = L - 1;\n    int lo = 0;\n    double r = rng.next_double();\n\n    if (intense) {\n        if (r < 0.78) lo = max(0, L - 180);\n        else if (r < 0.97) lo = max(0, L - 560);\n        else lo = 0;\n    } else if (phase < 0.35) {\n        if (r < 0.35) lo = max(0, L - 250);\n        else if (r < 0.75) lo = max(0, L - 850);\n        else lo = 0;\n    } else if (phase < 0.85) {\n        if (r < 0.62) lo = max(0, L - 250);\n        else if (r < 0.92) lo = max(0, L - 760);\n        else lo = 0;\n    } else {\n        if (r < 0.82) lo = max(0, L - 180);\n        else if (r < 0.98) lo = max(0, L - 560);\n        else lo = 0;\n    }\n\n    if (lo > hi) lo = hi;\n    return rng.next_int(lo, hi);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    if (!(cin >> si >> sj)) return 0;\n\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x;\n            cin >> x;\n            int v = i * W + j;\n            tileId[v] = x;\n            maxTile = max(maxTile, x);\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[i * W + j];\n        }\n    }\n\n    startCell = si * W + sj;\n\n    // pairLoss for domino tiles\n    fill(pairLoss, pairLoss + N, 0);\n    vector<int> c1(M, -1), c2(M, -1);\n    for (int v = 0; v < N; v++) {\n        int t = tileId[v];\n        if (c1[t] == -1) c1[t] = v;\n        else c2[t] = v;\n    }\n    for (int t = 0; t < M; t++) {\n        if (c1[t] != -1 && c2[t] != -1) {\n            int a = c1[t], b = c2[t];\n            pairLoss[a] = max(0, pval[b] - pval[a]);\n            pairLoss[b] = max(0, pval[a] - pval[b]);\n        }\n    }\n\n    // Build graph\n    for (int v = 0; v < N; v++) {\n        degCell[v] = 0;\n        for (int d = 0; d < 4; d++) nextAll[v][d] = -1;\n    }\n\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    const char dc[4] = {'U', 'D', 'L', 'R'};\n\n    auto inside = [&](int r, int c) {\n        return (0 <= r && r < H && 0 <= c && c < W);\n    };\n\n    for (int r = 0; r < H; r++) {\n        for (int c = 0; c < W; c++) {\n            int v = r * W + c;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + di[d], nc = c + dj[d];\n                if (!inside(nr, nc)) continue;\n                int to = nr * W + nc;\n                nextAll[v][d] = to;\n                if (tileId[to] != tileId[v]) {\n                    int k = degCell[v]++;\n                    nxtCell[v][k] = to;\n                    nxtDir[v][k] = dc[d];\n                }\n            }\n        }\n    }\n\n    // deterministic seed from input\n    uint64_t seed = 1469598103934665603ULL;\n    auto mixSeed = [&](uint64_t x) {\n        seed ^= x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed((uint64_t)(startCell + 1));\n    for (int v = 0; v < N; v++) {\n        uint64_t z = (uint64_t)(tileId[v] + 1) * 1315423911ULL\n                   ^ (uint64_t)(pval[v] + 1) * 2654435761ULL\n                   ^ (uint64_t)(v + 1) * 97531ULL;\n        mixSeed(z);\n    }\n    XorShift64 rng(seed);\n\n    using Clock = chrono::steady_clock;\n    auto t0 = Clock::now();\n    auto deadline = t0 + chrono::milliseconds(1910);\n    const double totalUs = (double)chrono::duration_cast<chrono::microseconds>(deadline - t0).count();\n\n    Result best;\n    vector<Result> elites;\n    const int ELITE_K = 8;\n\n    auto pushElite = [&](const Result& r) {\n        for (auto &e : elites) {\n            if (e.path == r.path) {\n                if (betterResult(r, e)) e = r;\n                sort(elites.begin(), elites.end(), betterResult);\n                if ((int)elites.size() > ELITE_K) elites.resize(ELITE_K);\n                return;\n            }\n        }\n        elites.push_back(r);\n        sort(elites.begin(), elites.end(), betterResult);\n        if ((int)elites.size() > ELITE_K) elites.resize(ELITE_K);\n    };\n\n    array<ModeStat, MODE_N> stats{};\n    int totalRuns = 0;\n    auto updateStat = [&](int mode, long long score) {\n        ModeStat &s = stats[mode];\n        s.n++;\n        s.mean += ((double)score - s.mean) / s.n;\n        totalRuns++;\n    };\n\n    // Initial runs\n    if (Clock::now() < deadline) {\n        RunParam rp = sampleParam(DEEP, 0.95, rng);\n        rp.wNoise = 0.0;\n        rp.epsMain = 0.0;\n        rp.evalNoise = 0.0;\n        rp.skipProb = 0.0;\n        rp.evalRollouts = max(rp.evalRollouts, 2);\n\n        Result r = simulate(rp, nullptr, 0, rng, deadline);\n        best = r;\n        pushElite(r);\n        updateStat(DEEP, r.score);\n    }\n\n    if (Clock::now() < deadline) {\n        RunParam rp = sampleParam(BAL, 0.20, rng);\n        Result r = simulate(rp, nullptr, 0, rng, deadline);\n        if (betterResult(r, best)) best = r;\n        pushElite(r);\n        updateStat(BAL, r.score);\n    }\n\n    // Start-prefix diversification (first move + best second move for each first)\n    vector<pair<int, string>> seedPref;\n    {\n        uint64_t vis0[WORDS];\n        bit_clear_all(vis0);\n        bit_set(vis0, tileId[startCell]);\n\n        int c1s[4];\n        char d1s[4];\n        int n1 = gatherMovesMain(startCell, vis0, c1s, d1s);\n\n        for (int i = 0; i < n1; i++) {\n            int a = c1s[i];\n            string s1(1, d1s[i]);\n            int sc1 = pval[a];\n            seedPref.push_back({sc1, s1});\n\n            uint64_t vis1[WORDS];\n            memcpy(vis1, vis0, sizeof(vis1));\n            bit_set(vis1, tileId[a]);\n\n            int c2s[4];\n            char d2s[4];\n            int n2 = gatherMovesMain(a, vis1, c2s, d2s);\n            if (n2 > 0) {\n                int best2 = 0;\n                for (int k = 1; k < n2; k++) {\n                    if (pval[c2s[k]] > pval[c2s[best2]]) best2 = k;\n                }\n                string s2 = s1;\n                s2.push_back(d2s[best2]);\n                seedPref.push_back({sc1 + pval[c2s[best2]], s2});\n            }\n        }\n    }\n\n    sort(seedPref.begin(), seedPref.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second.size() > b.second.size();\n    });\n\n    vector<string> prefixes;\n    for (auto &pr : seedPref) {\n        bool dup = false;\n        for (auto &s : prefixes) {\n            if (s == pr.second) { dup = true; break; }\n        }\n        if (!dup) prefixes.push_back(pr.second);\n        if ((int)prefixes.size() >= 6) break;\n    }\n\n    auto prefixBudgetEnd = t0 + chrono::milliseconds(340);\n    for (int i = 0; i < (int)prefixes.size(); i++) {\n        if (Clock::now() >= deadline || Clock::now() >= prefixBudgetEnd) break;\n        int mode = (i < 2 ? DEEP : BAL);\n        RunParam rp = sampleParam(mode, 0.20, rng);\n        if (mode == DEEP) rp.wNoise *= 0.3;\n        Result r = simulate(rp, &prefixes[i], (int)prefixes[i].size(), rng, deadline);\n        if (betterResult(r, best)) best = r;\n        pushElite(r);\n        updateStat(mode, r.score);\n    }\n\n    // Main loop\n    while (Clock::now() < deadline) {\n        double phase = (double)chrono::duration_cast<chrono::microseconds>(Clock::now() - t0).count() / totalUs;\n        phase = max(0.0, min(1.0, phase));\n\n        int mode = chooseMode(phase, rng, stats, totalRuns);\n        if (phase > 0.92 && rng.next_double() < 0.45) mode = DEEP;\n\n        RunParam rp = sampleParam(mode, phase, rng);\n\n        const string* basePath = nullptr;\n        int cut = 0;\n\n        double useEliteProb = (phase < 0.30 ? 0.62 : (phase < 0.85 ? 0.84 : 0.96));\n        if (!elites.empty() && rng.next_double() < useEliteProb) {\n            int top = (phase < 0.55 ? min<int>((int)elites.size(), 6) : min<int>((int)elites.size(), 4));\n            int idx = 0;\n            if (phase > 0.92 && rng.next_double() < 0.58) {\n                idx = 0;\n            } else {\n                double u = rng.next_double();\n                idx = (int)(u * u * top);\n                if (idx >= top) idx = top - 1;\n            }\n            basePath = &elites[idx].path;\n            bool intense = (mode == DEEP) && (phase > 0.86) && (idx == 0 || rng.next_double() < 0.55);\n            cut = pickCut((int)basePath->size(), phase, intense, rng);\n        } else if (phase < 0.25 && !prefixes.empty() && rng.next_double() < 0.18) {\n            int id = rng.next_int(0, (int)prefixes.size() - 1);\n            basePath = &prefixes[id];\n            cut = (int)prefixes[id].size();\n        }\n\n        Result cur = simulate(rp, basePath, cut, rng, deadline);\n        updateStat(mode, cur.score);\n\n        bool improved = betterResult(cur, best);\n        if (improved) best = cur;\n        pushElite(cur);\n\n        // Extra late intensification\n        if (Clock::now() < deadline) {\n            bool doExtra = false;\n            if (improved && phase > 0.50 && rng.next_double() < 0.35) doExtra = true;\n            else if (phase > 0.94 && rng.next_double() < 0.14) doExtra = true;\n\n            if (doExtra) {\n                RunParam ip = sampleParam(DEEP, 0.99, rng);\n                ip.wNoise *= 0.15;\n                ip.epsMain *= 0.20;\n                ip.evalNoise *= 0.20;\n\n                const string* bp = &best.path;\n                int cut2 = pickCut((int)bp->size(), 0.99, true, rng);\n                Result r2 = simulate(ip, bp, cut2, rng, deadline);\n                updateStat(DEEP, r2.score);\n\n                if (betterResult(r2, best)) best = r2;\n                pushElite(r2);\n            }\n        }\n    }\n\n    if (best.score == LLONG_MIN) cout << \"\\n\";\n    else cout << best.path << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr int Q = 1000;\n\n    static constexpr double COST_MIN = 1000.0;\n    static constexpr double COST_MAX = 9000.0;\n\n    static constexpr double PRIOR_CNT = 1.0;\n    static constexpr double DELTA_CLIP = 4200.0;\n\n    static constexpr int WARMUP_MONO = 45;\n    static constexpr int REFIT_INTERVAL = 20;\n\n    using HMatD = array<array<double, N - 1>, N>;\n    using VMatD = array<array<double, N>, N - 1>;\n    using HMatI = array<array<int, N - 1>, N>;\n    using VMatI = array<array<int, N>, N - 1>;\n\n    struct EdgeRef {\n        bool horiz; // true: H edge, false: V edge\n        int i, j;\n    };\n\n    struct FitInfo {\n        double mean1 = 5000.0;\n        int split = -1; // 1..28\n        double meanL = 5000.0;\n        double meanR = 5000.0;\n        double ratio = 0.0; // (sse1 - sse2) / sse1\n        double diff = 0.0;  // |meanL - meanR|\n        int cLeft = 0;\n        int cRight = 0;\n    };\n\n    // Base model (piecewise line parameters)\n    array<double, N> row0{}, row1{}, col0{}, col1{};\n    array<int, N> rowSplit{}, colSplit{}; // split=29 => effectively 1 segment\n\n    // Local residuals\n    HMatD deltaH{};\n    VMatD deltaV{};\n\n    // Visit counts\n    HMatI cntH{};\n    VMatI cntV{};\n\n    bool m2Likely = false;\n\n    mt19937 rng;\n    uniform_real_distribution<double> urd;\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 int vid(int i, int j) { return i * N + j; }\n\n    double rndSym() {\n        return urd(rng) * 2.0 - 1.0;\n    }\n\n    inline double baseH(int i, int j) const {\n        return (j < rowSplit[i]) ? row0[i] : row1[i];\n    }\n\n    inline double baseV(int i, int j) const {\n        return (i < colSplit[j]) ? col0[j] : col1[j];\n    }\n\n    inline double edgeEstH(int i, int j) const {\n        double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n        double c = baseH(i, j) + sh * deltaH[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    inline double edgeEstV(int i, int j) const {\n        double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n        double c = baseV(i, j) + sh * deltaV[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    string directPath(int si, int sj, int ti, int tj) const {\n        string p;\n        if (ti > si) p.append(ti - si, 'D');\n        else p.append(si - ti, 'U');\n        if (tj > sj) p.append(tj - sj, 'R');\n        else p.append(sj - tj, 'L');\n        return p;\n    }\n\n    void buildCostTables(int q, HMatD& baseHMat, VMatD& baseVMat, HMatD& searchHMat, VMatD& searchVMat) {\n        double stepPenalty = (q < 140) ? (180.0 * (140 - q) / 140.0) : 0.0;\n        double bonusCoef = (q < 240) ? (360.0 * (240 - q) / 240.0) : 0.0;\n        double jitter = (q < 220) ? (0.025 * (220 - q) / 220.0) : 0.0;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                double b = edgeEstH(i, j);\n                baseHMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntH[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchHMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                double b = edgeEstV(i, j);\n                baseVMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntV[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchVMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n    }\n\n    string dijkstraPath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        constexpr double INF = 1e100;\n        array<double, N * N> dist;\n        array<int, N * N> prv;\n        array<char, N * N> pmv;\n        dist.fill(INF);\n        prv.fill(-1);\n        pmv.fill(0);\n\n        int S = vid(si, sj), T = vid(ti, tj);\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[S] = 0.0;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == T) break;\n\n            int i = u / N, j = u % N;\n\n            if (i > 0) {\n                int to = vid(i - 1, j);\n                double nd = d + v[i - 1][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'U';\n                    pq.push({nd, to});\n                }\n            }\n            if (i + 1 < N) {\n                int to = vid(i + 1, j);\n                double nd = d + v[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'D';\n                    pq.push({nd, to});\n                }\n            }\n            if (j > 0) {\n                int to = vid(i, j - 1);\n                double nd = d + h[i][j - 1];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'L';\n                    pq.push({nd, to});\n                }\n            }\n            if (j + 1 < N) {\n                int to = vid(i, j + 1);\n                double nd = d + h[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'R';\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        if (prv[T] == -1) return directPath(si, sj, ti, tj);\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmv[cur]);\n            cur = prv[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Best among monotone-only paths (length = Manhattan)\n    string bestMonotoneDP(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        if (si == ti && sj == tj) return \"\";\n\n        int di = (ti > si) ? 1 : (ti < si ? -1 : 0);\n        int dj = (tj > sj) ? 1 : (tj < sj ? -1 : 0);\n\n        int R = abs(ti - si) + 1;\n        int C = abs(tj - sj) + 1;\n\n        const double INF = 1e100;\n        vector<vector<double>> dp(R, vector<double>(C, INF));\n        vector<vector<char>> pre(R, vector<char>(C, 0));\n        dp[0][0] = 0.0;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = 0; b < C; b++) {\n                if (dp[a][b] >= INF / 2) continue;\n                int i = si + di * a;\n                int j = sj + dj * b;\n\n                if (a + 1 < R) {\n                    double w = (di == 1) ? v[i][j] : v[i - 1][j];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a + 1][b]) {\n                        dp[a + 1][b] = nd;\n                        pre[a + 1][b] = 'V';\n                    }\n                }\n                if (b + 1 < C) {\n                    double w = (dj == 1) ? h[i][j] : h[i][j - 1];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a][b + 1]) {\n                        dp[a][b + 1] = nd;\n                        pre[a][b + 1] = 'H';\n                    }\n                }\n            }\n        }\n\n        string path;\n        int a = R - 1, b = C - 1;\n        while (a > 0 || b > 0) {\n            char p = pre[a][b];\n            if (p == 'V') {\n                path.push_back(di == 1 ? 'D' : 'U');\n                --a;\n            } else {\n                path.push_back(dj == 1 ? 'R' : 'L');\n                --b;\n            }\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Warmup monotone exploration\n    string biasedMonotonePath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) {\n        int i = si, j = sj;\n        string path;\n        path.reserve(abs(ti - si) + abs(tj - sj));\n\n        while (i != ti || j != tj) {\n            bool canV = (i != ti);\n            bool canH = (j != tj);\n\n            if (canV && canH) {\n                double cv, ch;\n                int nv, nh;\n\n                if (ti > i) { // D\n                    cv = v[i][j];\n                    nv = cntV[i][j];\n                } else {      // U\n                    cv = v[i - 1][j];\n                    nv = cntV[i - 1][j];\n                }\n\n                if (tj > j) { // R\n                    ch = h[i][j];\n                    nh = cntH[i][j];\n                } else {      // L\n                    ch = h[i][j - 1];\n                    nh = cntH[i][j - 1];\n                }\n\n                double sv = (1.0 / (cv + 1e-9)) * (1.0 + 1.2 / sqrt(nv + 1.0));\n                double sh = (1.0 / (ch + 1e-9)) * (1.0 + 1.2 / sqrt(nh + 1.0));\n\n                double r = urd(rng) * (sv + sh);\n                if (r < sv) {\n                    if (ti > i) { path.push_back('D'); ++i; }\n                    else { path.push_back('U'); --i; }\n                } else {\n                    if (tj > j) { path.push_back('R'); ++j; }\n                    else { path.push_back('L'); --j; }\n                }\n            } else if (canV) {\n                if (ti > i) { path.push_back('D'); ++i; }\n                else { path.push_back('U'); --i; }\n            } else {\n                if (tj > j) { path.push_back('R'); ++j; }\n                else { path.push_back('L'); --j; }\n            }\n        }\n\n        return path;\n    }\n\n    void pathToEdges(\n        int si, int sj, const string& path, vector<EdgeRef>& edges,\n        array<int, N>& row0Cnt, array<int, N>& row1Cnt,\n        array<int, N>& col0Cnt, array<int, N>& col1Cnt\n    ) const {\n        row0Cnt.fill(0);\n        row1Cnt.fill(0);\n        col0Cnt.fill(0);\n        col1Cnt.fill(0);\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int i = si, j = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                --i;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                ++i;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                --j;\n            } else { // 'R'\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                ++j;\n            }\n        }\n    }\n\n    FitInfo fitLine29(const array<double, N - 1>& val, const array<int, N - 1>& cnt) const {\n        const double W0 = 0.35;\n\n        array<double, N> pw{}, ps{}, ps2{};\n        array<int, N> pc{};\n        for (int k = 0; k < N - 1; k++) {\n            double w = cnt[k] + W0;\n            double x = val[k];\n            pw[k + 1] = pw[k] + w;\n            ps[k + 1] = ps[k] + w * x;\n            ps2[k + 1] = ps2[k] + w * x * x;\n            pc[k + 1] = pc[k] + cnt[k];\n        }\n\n        FitInfo f;\n\n        double W = pw[N - 1];\n        double S = ps[N - 1];\n        double Qv = ps2[N - 1];\n        if (W <= 1e-12) {\n            f.mean1 = 5000.0;\n            return f;\n        }\n\n        f.mean1 = S / W;\n        double sse1 = max(0.0, Qv - S * S / W);\n\n        double bestSSE = 1e100;\n        int bestS = -1;\n        double bestL = f.mean1, bestR = f.mean1;\n\n        for (int s = 1; s <= N - 2; s++) { // 1..28\n            double WL = pw[s], WR = pw[N - 1] - pw[s];\n            if (WL <= 1e-12 || WR <= 1e-12) continue;\n\n            double SL = ps[s], SR = ps[N - 1] - ps[s];\n            double QL = ps2[s], QR = ps2[N - 1] - ps2[s];\n\n            double mL = SL / WL, mR = SR / WR;\n            double sse = max(0.0, QL - SL * SL / WL) + max(0.0, QR - SR * SR / WR);\n\n            if (sse < bestSSE) {\n                bestSSE = sse;\n                bestS = s;\n                bestL = mL;\n                bestR = mR;\n            }\n        }\n\n        f.split = bestS;\n        if (bestS == -1) {\n            f.meanL = f.meanR = f.mean1;\n            f.ratio = 0.0;\n            f.diff = 0.0;\n            return f;\n        }\n\n        f.meanL = bestL;\n        f.meanR = bestR;\n        f.diff = fabs(bestL - bestR);\n        f.cLeft = pc[bestS];\n        f.cRight = pc[N - 1] - pc[bestS];\n        f.ratio = (sse1 - bestSSE) / max(1.0, sse1);\n        if (f.ratio < 0.0) f.ratio = 0.0;\n\n        return f;\n    }\n\n    void refitStructure(int q) {\n        // 1) Current effective estimates\n        HMatD effH;\n        VMatD effV;\n        for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) effH[i][j] = edgeEstH(i, j);\n        for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) effV[i][j] = edgeEstV(i, j);\n\n        // 2) Fit each row/column as 1-seg vs best 2-seg\n        array<FitInfo, N> rowFit, colFit;\n\n        for (int i = 0; i < N; i++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int j = 0; j < N - 1; j++) {\n                val[j] = effH[i][j];\n                cnt[j] = cntH[i][j];\n            }\n            rowFit[i] = fitLine29(val, cnt);\n        }\n\n        for (int j = 0; j < N; j++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int i = 0; i < N - 1; i++) {\n                val[i] = effV[i][j];\n                cnt[i] = cntV[i][j];\n            }\n            colFit[j] = fitLine29(val, cnt);\n        }\n\n        // 3) Infer whether M=2 is likely globally\n        int strong = 0, considered = 0;\n        auto countStrong = [&](const FitInfo& f) {\n            if (f.split < 1 || f.split > N - 2) return;\n            int mc = min(f.cLeft, f.cRight);\n            if (mc < 5) return;\n            considered++;\n            if (f.ratio > 0.09 && f.diff > 500.0) strong++;\n        };\n        for (int i = 0; i < N; i++) countStrong(rowFit[i]);\n        for (int j = 0; j < N; j++) countStrong(colFit[j]);\n\n        if (q >= 70 && considered >= 20) {\n            if (strong >= 18) m2Likely = true;\n            else if (strong <= 8) m2Likely = false;\n        }\n\n        auto useTwoSeg = [&](const FitInfo& f) -> bool {\n            if (f.split < 1 || f.split > N - 2) return false;\n            if (q < 55) return false;\n            int mc = min(f.cLeft, f.cRight);\n\n            if (m2Likely) {\n                double thrRatio = (q < 220) ? 0.07 : 0.045;\n                double thrDiff = (q < 220) ? 450.0 : 300.0;\n                int thrCnt = (q < 220) ? 5 : 3;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            } else {\n                // strict mode for likely M=1, but allow very strong evidence\n                if (f.ratio > 0.22 && f.diff > 1200.0 && mc >= 8) return true;\n                double thrRatio = (q < 320) ? 0.16 : 0.12;\n                double thrDiff = (q < 320) ? 800.0 : 650.0;\n                int thrCnt = (q < 320) ? 10 : 7;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            }\n        };\n\n        // 4) Update base model\n        for (int i = 0; i < N; i++) {\n            const auto& f = rowFit[i];\n            if (useTwoSeg(f)) {\n                rowSplit[i] = f.split;\n                row0[i] = clampd(f.meanL, COST_MIN, COST_MAX);\n                row1[i] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                rowSplit[i] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                row0[i] = m;\n                row1[i] = m;\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            const auto& f = colFit[j];\n            if (useTwoSeg(f)) {\n                colSplit[j] = f.split;\n                col0[j] = clampd(f.meanL, COST_MIN, COST_MAX);\n                col1[j] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                colSplit[j] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                col0[j] = m;\n                col1[j] = m;\n            }\n        }\n\n        // 5) Re-center local residuals around the new base\n        //    (trusted edges mostly preserved; low-count edges pulled to new base)\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                if (cntH[i][j] == 0) {\n                    deltaH[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseH(i, j);\n                double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaH[i][j] = clampd((effH[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                if (cntV[i][j] == 0) {\n                    deltaV[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseV(i, j);\n                double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaV[i][j] = clampd((effV[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n    }\n\npublic:\n    Solver() : rng(20240315), urd(0.0, 1.0) {\n        row0.fill(5000.0);\n        row1.fill(5000.0);\n        col0.fill(5000.0);\n        col1.fill(5000.0);\n        rowSplit.fill(N - 1);\n        colSplit.fill(N - 1);\n\n        for (auto& r : deltaH) r.fill(0.0);\n        for (auto& r : deltaV) r.fill(0.0);\n        for (auto& r : cntH) r.fill(0);\n        for (auto& r : cntV) r.fill(0);\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int q = 0; q < Q; q++) {\n            if (q > 0 && q % REFIT_INTERVAL == 0) {\n                refitStructure(q);\n            }\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            HMatD baseHMat, searchHMat;\n            VMatD baseVMat, searchVMat;\n            buildCostTables(q, baseHMat, baseVMat, searchHMat, searchVMat);\n\n            string path;\n            if (q < WARMUP_MONO) {\n                path = biasedMonotonePath(si, sj, ti, tj, baseHMat, baseVMat);\n            } else {\n                path = dijkstraPath(si, sj, ti, tj, searchHMat, searchVMat);\n\n                int md = abs(si - ti) + abs(sj - tj);\n                int detourLimit = (q < 200) ? 10 : 16;\n                if ((int)path.size() > md + detourLimit) {\n                    path = bestMonotoneDP(si, sj, ti, tj, baseHMat, baseVMat);\n                }\n            }\n\n            cout << path << '\\n' << flush;\n\n            int obsInt;\n            if (!(cin >> obsInt)) return;\n            if (obsInt < 0) return; // interactive guard\n            double obs = static_cast<double>(obsInt);\n\n            vector<EdgeRef> edges;\n            array<int, N> row0Cnt, row1Cnt, col0Cnt, col1Cnt;\n            pathToEdges(si, sj, path, edges, row0Cnt, row1Cnt, col0Cnt, col1Cnt);\n\n            if (edges.empty()) continue;\n\n            // Prediction before update\n            double pred = 0.0;\n            for (const auto& e : edges) {\n                pred += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double err = obs - pred;\n\n            // Segment-level base update\n            double norm = 1e-9;\n            for (int i = 0; i < N; i++) {\n                norm += 1.0 * row0Cnt[i] * row0Cnt[i];\n                norm += 1.0 * row1Cnt[i] * row1Cnt[i];\n            }\n            for (int j = 0; j < N; j++) {\n                norm += 1.0 * col0Cnt[j] * col0Cnt[j];\n                norm += 1.0 * col1Cnt[j] * col1Cnt[j];\n            }\n\n            double etaBase = 0.40 * exp(-0.0022 * q) + 0.06;\n\n            for (int i = 0; i < N; i++) {\n                if (row0Cnt[i]) {\n                    row0[i] += etaBase * err * row0Cnt[i] / norm;\n                    row0[i] = clampd(row0[i], COST_MIN, COST_MAX);\n                }\n                if (row1Cnt[i]) {\n                    row1[i] += etaBase * err * row1Cnt[i] / norm;\n                    row1[i] = clampd(row1[i], COST_MIN, COST_MAX);\n                }\n            }\n            for (int j = 0; j < N; j++) {\n                if (col0Cnt[j]) {\n                    col0[j] += etaBase * err * col0Cnt[j] / norm;\n                    col0[j] = clampd(col0[j], COST_MIN, COST_MAX);\n                }\n                if (col1Cnt[j]) {\n                    col1[j] += etaBase * err * col1Cnt[j] / norm;\n                    col1[j] = clampd(col1[j], COST_MIN, COST_MAX);\n                }\n            }\n\n            // Residual after base update\n            double pred2 = 0.0;\n            for (const auto& e : edges) {\n                pred2 += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double residual = obs - pred2;\n\n            // Local residual update (uncertainty weighted)\n            double etaDelta = 0.60 * exp(-0.0015 * q) + 0.18;\n\n            vector<double> w(edges.size());\n            double sw = 0.0;\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                int c = e.horiz ? cntH[e.i][e.j] : cntV[e.i][e.j];\n                w[idx] = 1.0 / sqrt(c + 1.0);\n                sw += w[idx];\n            }\n            if (sw < 1e-12) sw = 1.0;\n\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                double d = etaDelta * residual * w[idx] / sw;\n                if (e.horiz) {\n                    deltaH[e.i][e.j] = clampd(deltaH[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntH[e.i][e.j]++;\n                } else {\n                    deltaV[e.i][e.j] = clampd(deltaV[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntV[e.i][e.j]++;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M;\n    int CELL, PPS, P;\n\n    vector<vector<uint8_t>> strs;\n    vector<uint8_t> len;\n    vector<int> groupLen;\n\n    // For each cell, entries are grouped by sid.\n    // packed = (pid << 3) | req(0..7)\n    vector<vector<uint32_t>> cellEntries;\n\n    vector<int16_t> matchCount;       // per placement\n    vector<array<int,13>> hist;       // hist[sid][mc]\n    vector<uint8_t> best;             // best mc per sid\n\n    vector<int> fullCnt;              // #full placements per sid\n    int cCur = 0;                     // #sids with fullCnt>0\n\n    vector<uint8_t> grid;\n    vector<uint8_t> bestGrid;\n    vector<uint8_t> altGrid;          // second basin\n\n    int bestC = -1, bestSoft = -1;\n    int altC = -1, altSoft = -1;\n\n    int g1[13];\n    int scoreTbl[13][13];\n\n    int lenW[13];\n    vector<int> sidW;\n    bool curLenBias = false;\n\n    vector<int> order;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 2.92;\n\n    Solver(int N_, int M_, const vector<string>& S): N(N_), M(M_) {\n        CELL = N * N;\n        PPS = 2 * CELL;\n        P = M * PPS;\n\n        strs.resize(M);\n        len.resize(M);\n        groupLen.resize(M);\n\n        for (int i = 0; i < M; i++) {\n            len[i] = (uint8_t)S[i].size();\n            groupLen[i] = 2 * (int)len[i];\n            strs[i].resize(len[i]);\n            for (int j = 0; j < (int)len[i]; j++) strs[i][j] = (uint8_t)(S[i][j] - 'A');\n        }\n\n        // Mild length emphasis\n        for (int k = 0; k <= 12; k++) {\n            if (k <= 6) lenW[k] = 1;\n            else if (k <= 8) lenW[k] = 2;\n            else if (k <= 10) lenW[k] = 3;\n            else lenW[k] = 4;\n        }\n\n        cellEntries.assign(CELL, {});\n        buildEntries();\n\n        matchCount.assign(P, 0);\n\n        hist.resize(M);\n        for (auto &a : hist) a.fill(0);\n        best.assign(M, 0);\n\n        fullCnt.assign(M, 0);\n\n        grid.assign(CELL, 0);\n        bestGrid.assign(CELL, 0);\n        altGrid.assign(CELL, 0);\n\n        sidW.assign(M, 1);\n\n        order.resize(CELL);\n        iota(order.begin(), order.end(), 0);\n\n        g1[0] = 1;\n        for (int i = 1; i <= 12; i++) g1[i] = g1[i - 1] << 1;\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        seed ^= (uint64_t)P * 1009ULL;\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline int randInt(int l, int r) {\n        return l + (int)(rng() % (uint32_t)(r - l + 1));\n    }\n\n    void buildEntries() {\n        int perCell = 0;\n        for (int i = 0; i < M; i++) perCell += groupLen[i];\n        for (int c = 0; c < CELL; c++) cellEntries[c].reserve(perCell);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            int k = len[sid];\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    int start = r * N + c;\n                    int pidH = base + start;\n                    int pidV = base + CELL + start;\n                    for (int p = 0; p < k; p++) {\n                        uint32_t req = strs[sid][p];\n                        int ch = r * N + ((c + p) % N);\n                        int cv = ((r + p) % N) * N + c;\n                        cellEntries[ch].push_back((uint32_t(pidH) << 3) | req);\n                        cellEntries[cv].push_back((uint32_t(pidV) << 3) | req);\n                    }\n                }\n            }\n        }\n    }\n\n    inline bool betterPair(int c1, int s1, int c2, int s2) const {\n        return (c1 > c2) || (c1 == c2 && s1 > s2);\n    }\n\n    int hammingDist(const vector<uint8_t>& a, const vector<uint8_t>& b) const {\n        int d = 0;\n        for (int i = 0; i < CELL; i++) d += (a[i] != b[i]);\n        return d;\n    }\n\n    void considerAlt(const vector<uint8_t>& cand, int c, int s, const vector<uint8_t>& ref) {\n        if (c < 0) return;\n        if (hammingDist(cand, ref) < 20) return;\n        if (altC < 0 || betterPair(c, s, altC, altSoft)) {\n            altC = c;\n            altSoft = s;\n            altGrid = cand;\n        }\n    }\n\n    void prepareBias(bool lenBias) {\n        curLenBias = lenBias;\n        if (!lenBias) {\n            for (int i = 0; i < M; i++) sidW[i] = 1;\n        } else {\n            for (int i = 0; i < M; i++) sidW[i] = lenW[len[i]];\n        }\n    }\n\n    void initRandom() {\n        for (int i = 0; i < CELL; i++) grid[i] = (uint8_t)(rng() & 7);\n    }\n\n    void initFromBest() {\n        const vector<uint8_t>* src = &bestGrid;\n        if (altC >= 0 && randInt(0, 99) < 30) src = &altGrid;\n        grid = *src;\n\n        int mut;\n        if (bestC >= (int)(0.75 * M)) mut = randInt(6, 24);\n        else if (bestC >= (int)(0.60 * M)) mut = randInt(10, 40);\n        else mut = randInt(20, 80);\n\n        for (int i = 0; i < mut; i++) {\n            int cell = randInt(0, CELL - 1);\n            grid[cell] = (uint8_t)randInt(0, 7);\n        }\n\n        // Torus shift\n        if (randInt(0, 1)) {\n            int dr = randInt(0, N - 1), dc = randInt(0, N - 1);\n            vector<uint8_t> tmp = grid;\n            for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n                int nr = (r + dr) % N, nc = (c + dc) % N;\n                grid[nr * N + nc] = tmp[r * N + c];\n            }\n        }\n        // Occasional transpose\n        if (randInt(0, 9) == 0) {\n            vector<uint8_t> tmp = grid;\n            for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n                grid[c * N + r] = tmp[r * N + c];\n            }\n        }\n    }\n\n    void recomputeMatchCount() {\n        fill(matchCount.begin(), matchCount.end(), 0);\n        for (int cell = 0; cell < CELL; cell++) {\n            int ch = grid[cell];\n            if (ch > 7) continue;\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                if ((int)(x & 7u) == ch) {\n                    int pid = (int)(x >> 3);\n                    matchCount[pid]++;\n                }\n            }\n        }\n    }\n\n    int phase1Sweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 15) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            long long bonus[8] = {0,0,0,0,0,0,0,0};\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                int w = sidW[sid];\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n                    int mc = matchCount[pid];\n                    int base = mc - ((old == req) ? 1 : 0);\n                    bonus[req] += 1LL * w * (g1[base + 1] - g1[base]);\n                }\n                pos += gsz;\n            }\n\n            int nw = old;\n            long long bestV = bonus[old];\n            int tie = 1;\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                if (bonus[a] > bestV) {\n                    bestV = bonus[a];\n                    nw = a;\n                    tie = 1;\n                } else if (bonus[a] == bestV && bonus[a] > bonus[old]) {\n                    tie++;\n                    if ((int)(rng() % tie) == 0) nw = a;\n                }\n            }\n            if (nw == old) continue;\n\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                if (req == old) matchCount[pid]--;\n                else if (req == nw) matchCount[pid]++;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildHistBest() {\n        for (int sid = 0; sid < M; sid++) hist[sid].fill(0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            for (int t = 0; t < PPS; t++) {\n                int mc = matchCount[base + t];\n                hist[sid][mc]++;\n            }\n        }\n\n        for (int sid = 0; sid < M; sid++) {\n            int b = len[sid];\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    inline int calcC() const {\n        int c = 0;\n        for (int sid = 0; sid < M; sid++) if (best[sid] == len[sid]) c++;\n        return c;\n    }\n\n    inline int calcSoft() const {\n        int s = 0;\n        for (int sid = 0; sid < M; sid++) s += lenW[len[sid]] * (int)best[sid];\n        return s;\n    }\n\n    void updateGlobal() {\n        int c = calcC();\n        int soft = calcSoft();\n\n        if (betterPair(c, soft, bestC, bestSoft)) {\n            if (bestC >= 0) considerAlt(bestGrid, bestC, bestSoft, grid);\n            bestC = c;\n            bestSoft = soft;\n            bestGrid = grid;\n        } else {\n            considerAlt(grid, c, soft, bestGrid);\n        }\n    }\n\n    void updateGlobalByCOnly() {\n        if (cCur > bestC) {\n            if (bestC >= 0) considerAlt(bestGrid, bestC, bestSoft, grid);\n            bestC = cCur;\n            bestSoft = -1;\n            bestGrid = grid;\n        } else if (cCur == bestC) {\n            considerAlt(grid, cCur, -1, bestGrid);\n        }\n    }\n\n    void buildScoreTbl(int fullBonus) {\n        for (int k = 0; k <= 12; k++) {\n            int w = curLenBias ? lenW[k] : 1;\n            for (int b = 0; b <= 12; b++) {\n                if (b > k) scoreTbl[k][b] = -1000000000;\n                else scoreTbl[k][b] = w * b * b + ((b == k) ? fullBonus : 0);\n            }\n        }\n    }\n\n    pair<int, long long> chooseLetterPhase2(int cell) {\n        int old = grid[cell];\n        long long delta[8] = {0,0,0,0,0,0,0,0};\n\n        const auto &vec = cellEntries[cell];\n        int pos = 0;\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            int gsz = groupLen[sid];\n\n            int cnt[8][3];\n            memset(cnt, 0, sizeof(cnt));\n\n            for (int t = 0; t < gsz; t++) {\n                uint32_t x = vec[pos + t];\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n\n                if (b > 0 && mc == b - 1) cnt[req][0]++;\n                if (mc == b) cnt[req][1]++;\n                if (b < k && mc == b + 1) cnt[req][2]++;\n            }\n            pos += gsz;\n\n            int baseScore = scoreTbl[k][b];\n            int hb = hist[sid][b];\n            int hbp1 = (b < k ? hist[sid][b + 1] : 0);\n\n            int old0 = cnt[old][1];\n            int oldp1 = cnt[old][2];\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                int nb;\n\n                if (b < k) {\n                    int cb1 = hbp1 - oldp1 + cnt[a][1];\n                    if (cb1 > 0) {\n                        nb = b + 1;\n                    } else {\n                        int cb = hb - old0 + oldp1 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                        nb = (cb > 0 ? b : b - 1);\n                        if (nb < 0) nb = 0;\n                    }\n                } else {\n                    int cb = hb - old0 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                    nb = (cb > 0 ? b : b - 1);\n                    if (nb < 0) nb = 0;\n                }\n\n                delta[a] += (long long)scoreTbl[k][nb] - baseScore;\n            }\n        }\n\n        int nw = old;\n        long long bestD = 0;\n        int tie = 1;\n        for (int a = 0; a < 8; a++) {\n            if (a == old) continue;\n            if (delta[a] > bestD) {\n                bestD = delta[a];\n                nw = a;\n                tie = 1;\n            } else if (delta[a] == bestD && bestD > 0) {\n                tie++;\n                if ((int)(rng() % tie) == 0) nw = a;\n            }\n        }\n\n        return {nw, bestD};\n    }\n\n    int phase2Sweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 7) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            auto [nw, gain] = chooseLetterPhase2(cell);\n            if (nw == old || gain <= 0) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc + 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc + 1]++;\n                    }\n                }\n                pos += gsz;\n\n                int b = best[sid];\n                int k = len[sid];\n                if (b < k && hist[sid][b + 1] > 0) b++;\n                else if (b > 0 && hist[sid][b] == 0) b--;\n                best[sid] = (uint8_t)b;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildFullCnt() {\n        cCur = 0;\n        fill(fullCnt.begin(), fullCnt.end(), 0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int base = sid * PPS;\n            int cnt = 0;\n            for (int t = 0; t < PPS; t++) {\n                if (matchCount[base + t] == k) cnt++;\n            }\n            fullCnt[sid] = cnt;\n            if (cnt > 0) cCur++;\n        }\n    }\n\n    // Lexicographic: (deltaC, deltaSmoothRelative)\n    int exactSweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 7) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n\n            int deltaC[8] = {0,0,0,0,0,0,0,0};\n            long long sm[8] = {0,0,0,0,0,0,0,0};\n\n            int pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                int k = len[sid];\n                int fc = fullCnt[sid];\n                int was = (fc > 0);\n                int gsz = groupLen[sid];\n                int w = sidW[sid];\n\n                int cntF[8]  = {0,0,0,0,0,0,0,0};\n                int cntM1[8] = {0,0,0,0,0,0,0,0};\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n                    int mc = matchCount[pid];\n\n                    int base = mc - ((old == req) ? 1 : 0);\n                    sm[req] += 1LL * w * (g1[base + 1] - g1[base]);\n\n                    if (mc == k) cntF[req]++;\n                    else if (mc == k - 1) cntM1[req]++;\n                }\n                pos += gsz;\n\n                int oldLose = cntF[old];\n                for (int a = 0; a < 8; a++) {\n                    if (a == old) continue;\n                    int newFc = fc - oldLose + cntM1[a];\n                    int now = (newFc > 0);\n                    deltaC[a] += (now - was);\n                }\n            }\n\n            long long smOld = sm[old];\n\n            int nw = old;\n            int bestDC = 0;\n            long long bestDS = 0;\n            int tie = 1;\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                long long ds = sm[a] - smOld;\n\n                if (deltaC[a] > bestDC) {\n                    bestDC = deltaC[a];\n                    bestDS = ds;\n                    nw = a;\n                    tie = 1;\n                } else if (deltaC[a] == bestDC) {\n                    if (ds > bestDS) {\n                        bestDS = ds;\n                        nw = a;\n                        tie = 1;\n                    } else if (ds == bestDS && (bestDC > 0 || bestDS > 0)) {\n                        tie++;\n                        if ((int)(rng() % tie) == 0) nw = a;\n                    }\n                }\n            }\n\n            if (nw == old) continue;\n            if (bestDC == 0 && bestDS <= 0) continue;\n\n            // apply\n            pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                bool before = (fullCnt[sid] > 0);\n                int k = len[sid];\n                int gsz = groupLen[sid];\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        int mc = matchCount[pid];\n                        if (mc == k) fullCnt[sid]--;\n                        matchCount[pid] = (int16_t)(mc - 1);\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        if (mc == k - 1) fullCnt[sid]++;\n                        matchCount[pid] = (int16_t)(mc + 1);\n                    }\n                }\n                pos += gsz;\n\n                bool after = (fullCnt[sid] > 0);\n                if (before != after) cCur += after ? 1 : -1;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void runOne(double deadline, bool fromBest, bool lenBias) {\n        prepareBias(lenBias);\n\n        if (fromBest && bestC >= 0) initFromBest();\n        else initRandom();\n\n        recomputeMatchCount();\n\n        int p1 = fromBest ? 2 + randInt(0, 1) : 5 + randInt(0, 1);\n        if (lenBias && !fromBest) p1++;\n\n        for (int i = 0; i < p1; i++) {\n            if (elapsed() >= deadline) return;\n            int ch = phase1Sweep(deadline);\n            if (ch == 0) break;\n        }\n\n        if (elapsed() >= deadline) return;\n        buildHistBest();\n        updateGlobal();\n\n        array<int,4> bonus, sweeps;\n        if (lenBias) {\n            bonus = {0, 120, 2500, 100000};\n            sweeps = {2, 3, 3, 2};\n        } else {\n            bonus = {0, 180, 4000, 130000};\n            sweeps = {2, 2, 3, 2};\n        }\n\n        for (int st = 0; st < 4; st++) {\n            if (elapsed() >= deadline) return;\n            buildScoreTbl(bonus[st]);\n\n            int lim = sweeps[st];\n            if (fromBest && st == 0) lim = max(1, lim - 1);\n\n            for (int it = 0; it < lim; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n        }\n\n        // kick + recover\n        if (elapsed() < deadline - 0.07) {\n            int mut = fromBest ? randInt(6, 18) : randInt(12, 34);\n            for (int i = 0; i < mut; i++) {\n                int cell = randInt(0, CELL - 1);\n                grid[cell] = (uint8_t)randInt(0, 7);\n            }\n\n            recomputeMatchCount();\n            if (elapsed() < deadline - 0.05) phase1Sweep(deadline - 0.04);\n\n            if (elapsed() >= deadline) return;\n            buildHistBest();\n            updateGlobal();\n\n            buildScoreTbl(lenBias ? 7000 : 9000);\n            for (int it = 0; it < 2; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n\n            if (!lenBias && elapsed() < deadline - 0.02) {\n                buildScoreTbl(170000);\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                (void)ch;\n            }\n        }\n\n        // exact c polish\n        if (elapsed() < deadline - 0.02) {\n            buildFullCnt();\n            updateGlobalByCOnly();\n\n            int lim = fromBest ? 2 : 3;\n            if (lenBias && !fromBest) lim++;\n\n            for (int it = 0; it < lim; it++) {\n                if (elapsed() >= deadline) break;\n                int ch = exactSweep(deadline);\n                updateGlobalByCOnly();\n                if (ch == 0) break;\n            }\n\n            if (elapsed() < deadline - 0.003) {\n                buildHistBest();\n                updateGlobal();\n            }\n        }\n    }\n\n    void dotPostprocessIfPossible() {\n        if (bestC != M) return;\n        if (elapsed() > TL - 0.03) return;\n\n        grid = bestGrid;\n        recomputeMatchCount();\n        buildHistBest();\n        if (calcC() != M) return;\n\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 15) == 0 && elapsed() > TL - 0.005) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            bool touched = false;\n\n            // old -> '.'\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    if (req == old) {\n                        int pid = (int)(x >> 3);\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                        touched = true;\n                    }\n                }\n                pos += gsz;\n\n                int b = best[sid];\n                int k = len[sid];\n                if (b < k && hist[sid][b + 1] > 0) b++;\n                else if (b > 0 && hist[sid][b] == 0) b--;\n                best[sid] = (uint8_t)b;\n            }\n\n            if (!touched) {\n                grid[cell] = 8;\n                continue;\n            }\n\n            if (calcC() == M) {\n                grid[cell] = 8;\n            } else {\n                // revert\n                pos = 0;\n                for (int sid = 0; sid < M; sid++) {\n                    int gsz = groupLen[sid];\n                    for (int t = 0; t < gsz; t++) {\n                        uint32_t x = vec[pos + t];\n                        int req = (int)(x & 7u);\n                        if (req == old) {\n                            int pid = (int)(x >> 3);\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc + 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc + 1]++;\n                        }\n                    }\n                    pos += gsz;\n\n                    int b = best[sid];\n                    int k = len[sid];\n                    if (b < k && hist[sid][b + 1] > 0) b++;\n                    else if (b > 0 && hist[sid][b] == 0) b--;\n                    best[sid] = (uint8_t)b;\n                }\n            }\n        }\n\n        bestGrid = grid;\n        bestSoft = calcSoft();\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        int restart = 0;\n        while (true) {\n            double now = elapsed();\n            double rem = TL - now;\n            if (rem < 0.12) break;\n\n            double budget;\n            if (restart == 0) budget = min(1.05, rem - 0.03);\n            else if (restart < 4) budget = min(0.50, rem - 0.03);\n            else budget = min(0.30, rem - 0.02);\n\n            if (budget < 0.08) break;\n\n            bool fromBest = false;\n            bool lenBias = false;\n\n            if (restart == 0) {\n                fromBest = false;\n                lenBias = true;\n            } else if (restart == 1) {\n                fromBest = false;\n                lenBias = false;\n            } else {\n                if (bestC >= 0 && restart % 6 != 0) {\n                    int p = (bestC < (int)(0.55 * M)) ? 62 : 78;\n                    fromBest = (randInt(0, 99) < p);\n                } else {\n                    fromBest = false;\n                }\n\n                int q;\n                if (bestC < 0) q = 50;\n                else if (bestC < (int)(0.50 * M)) q = 58;\n                else if (bestC < (int)(0.70 * M)) q = 45;\n                else q = 30;\n\n                lenBias = (randInt(0, 99) < q);\n                if (restart % 4 == 0) lenBias = false;\n            }\n\n            runOne(now + budget, fromBest, lenBias);\n            restart++;\n        }\n\n        if (bestC < 0) {\n            initRandom();\n            bestGrid = grid;\n            bestC = 0;\n            bestSoft = 0;\n        }\n\n        // final polish\n        if (elapsed() < TL - 0.03) {\n            grid = bestGrid;\n\n            prepareBias(false);\n            recomputeMatchCount();\n            buildHistBest();\n            updateGlobal();\n\n            // brief long-bias shake only when still weak\n            if (elapsed() < TL - 0.09 && bestC < (int)(0.72 * M)) {\n                prepareBias(true);\n                buildScoreTbl(6000);\n                for (int it = 0; it < 2 && elapsed() < TL - 0.06; it++) {\n                    int ch = phase2Sweep(TL - 0.055);\n                    updateGlobal();\n                    if (ch == 0) break;\n                }\n                prepareBias(false);\n                recomputeMatchCount();\n                buildHistBest();\n                updateGlobal();\n            }\n\n            buildScoreTbl(280000);\n            bool kicked = false;\n            while (elapsed() < TL - 0.015) {\n                int ch = phase2Sweep(TL - 0.010);\n                updateGlobal();\n                if (ch == 0) {\n                    if (!kicked && elapsed() < TL - 0.05) {\n                        kicked = true;\n                        int mut = randInt(8, 24);\n                        for (int i = 0; i < mut; i++) {\n                            int cell = randInt(0, CELL - 1);\n                            grid[cell] = (uint8_t)randInt(0, 7);\n                        }\n                        recomputeMatchCount();\n                        buildHistBest();\n                        updateGlobal();\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (elapsed() < TL - 0.006) {\n                buildFullCnt();\n                updateGlobalByCOnly();\n                while (elapsed() < TL - 0.0032) {\n                    int ch = exactSweep(TL - 0.0028);\n                    updateGlobalByCOnly();\n                    if (ch == 0) break;\n                }\n            }\n\n            if (elapsed() < TL - 0.002) {\n                buildHistBest();\n                updateGlobal();\n            }\n        }\n\n        dotPostprocessIfPossible();\n    }\n\n    void output() const {\n        for (int r = 0; r < N; r++) {\n            string line(N, '.');\n            for (int c = 0; c < N; c++) {\n                int v = bestGrid[r * N + c];\n                line[c] = (0 <= v && v < 8) ? char('A' + v) : '.';\n            }\n            cout << line << '\\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<string> S(M);\n    for (int i = 0; i < M; i++) cin >> S[i];\n\n    Solver solver(N, M, S);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    using ull = unsigned long long;\n    static constexpr int INF = 1e9;\n\n    inline static constexpr int DI[4] = {-1, 1, 0, 0};\n    inline static constexpr int DJ[4] = {0, 0, -1, 1};\n    inline static constexpr char MV[4] = {'U', 'D', 'L', 'R'};\n    inline static constexpr int OPP[4] = {1, 0, 3, 2};\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0;\n    int startRid = -1;\n\n    vector<vector<int>> id;\n    vector<int> ri, rj;\n    vector<int> enterCost;\n    vector<array<int, 4>> nbr;\n\n    int B = 0;\n    vector<ull> allBits;\n    vector<vector<ull>> roadVisBits;\n    vector<int> roadVisCnt;\n\n    vector<int> candRid;              // candidate idx -> road id\n    vector<vector<ull>> candBits;     // candidate visibility bits\n    vector<vector<int>> candVisList;  // candidate visibility list\n    vector<char> inCand;\n\n    vector<vector<int>> distC;        // directed shortest distance among candidates\n    vector<vector<int>> prevFrom;     // source candidate idx -> prev road-id tree\n\n    // route-aware cache\n    vector<int> edgeCacheId;          // key = a*C+b\n    vector<vector<ull>> edgeCacheBits;\n\n    chrono::steady_clock::time_point t0;\n\n    long long elapsed_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - t0\n        ).count();\n    }\n\n    void read_input() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void build_graph() {\n        id.assign(N, vector<int>(N, -1));\n        ri.clear();\n        rj.clear();\n        enterCost.clear();\n\n        R = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    ri.push_back(i);\n                    rj.push_back(j);\n                    enterCost.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n        startRid = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        for (int u = 0; u < R; u++) {\n            int i = ri[u], j = rj[u];\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                    nbr[u][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void init_bits() {\n        B = (R + 63) >> 6;\n        allBits.assign(B, ~0ULL);\n        if (B > 0 && (R & 63)) {\n            allBits.back() = (1ULL << (R & 63)) - 1ULL;\n        }\n    }\n\n    void build_road_visibility() {\n        roadVisBits.assign(R, vector<ull>(B, 0ULL));\n        roadVisCnt.assign(R, 0);\n\n        for (int rid = 0; rid < R; rid++) {\n            auto &bits = roadVisBits[rid];\n            auto add = [&](int v) { bits[v >> 6] |= (1ULL << (v & 63)); };\n\n            int i = ri[rid], j = rj[rid];\n            add(rid);\n\n            for (int y = j - 1; y >= 0; y--) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int y = j + 1; y < N; y++) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i - 1; x >= 0; x--) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i + 1; x < N; x++) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n\n            int cnt = 0;\n            for (int b = 0; b < B; b++) cnt += __builtin_popcountll(bits[b]);\n            roadVisCnt[rid] = cnt;\n        }\n    }\n\n    vector<int> bits_to_list(const vector<ull>& bits) const {\n        vector<int> res;\n        for (int b = 0; b < B; b++) {\n            ull x = bits[b];\n            while (x) {\n                int t = __builtin_ctzll(x);\n                int v = (b << 6) + t;\n                if (v < R) res.push_back(v);\n                x &= (x - 1);\n            }\n        }\n        return res;\n    }\n\n    bool is_straight_2deg(int rid) const {\n        int deg = 0;\n        for (int d = 0; d < 4; d++) if (nbr[rid][d] != -1) deg++;\n        if (deg != 2) return false;\n        bool U = (nbr[rid][0] != -1);\n        bool D = (nbr[rid][1] != -1);\n        bool L = (nbr[rid][2] != -1);\n        bool Rr = (nbr[rid][3] != -1);\n        return (U && D) || (L && Rr);\n    }\n\n    void add_candidate(int rid) {\n        if (inCand[rid]) return;\n        inCand[rid] = 1;\n        candRid.push_back(rid);\n        candBits.push_back(roadVisBits[rid]);\n        candVisList.push_back(bits_to_list(roadVisBits[rid]));\n    }\n\n    void add_extra_candidates() {\n        int C0 = (int)candRid.size();\n        int addLimit = 0;\n        if (C0 < 220) addLimit = 24;\n        else if (C0 < 320) addLimit = 12;\n        else if (C0 < 400) addLimit = 6;\n        else addLimit = 0;\n\n        int maxC = 430;\n        addLimit = min(addLimit, max(0, maxC - C0));\n        if (addLimit <= 0) return;\n\n        vector<int> pool;\n        pool.reserve(R);\n        for (int rid = 0; rid < R; rid++) if (!inCand[rid]) pool.push_back(rid);\n\n        sort(pool.begin(), pool.end(), [&](int a, int b) {\n            if (roadVisCnt[a] != roadVisCnt[b]) return roadVisCnt[a] > roadVisCnt[b];\n            return enterCost[a] < enterCost[b];\n        });\n\n        int added = 0;\n        for (int pass = 0; pass < 2 && added < addLimit; pass++) {\n            for (int rid : pool) {\n                if (added >= addLimit) break;\n                if (inCand[rid]) continue;\n                if (pass == 0 && !is_straight_2deg(rid)) continue;\n                add_candidate(rid);\n                added++;\n            }\n        }\n    }\n\n    void build_candidates() {\n        candRid.clear();\n        candBits.clear();\n        candVisList.clear();\n        inCand.assign(R, 0);\n\n        add_candidate(startRid); // candidate[0]=start\n\n        for (int u = 0; u < R; u++) {\n            if (u == startRid) continue;\n\n            int deg = 0;\n            for (int d = 0; d < 4; d++) if (nbr[u][d] != -1) deg++;\n\n            bool isCand = false;\n            if (deg != 2) isCand = true;\n            else isCand = !is_straight_2deg(u);\n            if (isCand) add_candidate(u);\n        }\n\n        // safety completion\n        vector<ull> uni(B, 0ULL);\n        for (int c = 0; c < (int)candRid.size(); c++) {\n            for (int b = 0; b < B; b++) uni[b] |= candBits[c][b];\n        }\n        for (int b = 0; b < B; b++) {\n            ull miss = allBits[b] & (~uni[b]);\n            while (miss) {\n                int t = __builtin_ctzll(miss);\n                int rid = (b << 6) + t;\n                if (rid < R) add_candidate(rid);\n                miss &= (miss - 1);\n            }\n        }\n\n        add_extra_candidates();\n    }\n\n    void dijkstra_candidate(int sIdx, vector<int>& dist, vector<int>& prev) {\n        int src = candRid[sIdx];\n\n        dist.assign(R, INF);\n        prev.assign(R, -1);\n        vector<int> score(R, -1); // tie-break: higher visibility sum along shortest paths\n\n        using State = tuple<int, int, int>; // dist, -score, node\n        priority_queue<State, vector<State>, greater<State>> pq;\n\n        dist[src] = 0;\n        score[src] = roadVisCnt[src];\n        prev[src] = src;\n        pq.push({0, -score[src], src});\n\n        while (!pq.empty()) {\n            auto [du, negSc, u] = pq.top();\n            pq.pop();\n            int su = -negSc;\n            if (du != dist[u] || su != score[u]) continue;\n\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1) continue;\n\n                int nd = du + enterCost[v];\n                int ns = su + roadVisCnt[v];\n\n                if (nd < dist[v] ||\n                    (nd == dist[v] && (ns > score[v] ||\n                                       (ns == score[v] && (prev[v] == -1 || u < prev[v]))))) {\n                    dist[v] = nd;\n                    score[v] = ns;\n                    prev[v] = u;\n                    pq.push({nd, -ns, v});\n                }\n            }\n        }\n    }\n\n    void precompute_shortest_paths() {\n        int C = (int)candRid.size();\n\n        distC.assign(C, vector<int>(C, INF));\n        prevFrom.assign(C, vector<int>(R, -1));\n\n        vector<int> dist, prev;\n        for (int s = 0; s < C; s++) {\n            dijkstra_candidate(s, dist, prev);\n            prevFrom[s].swap(prev);\n            for (int t = 0; t < C; t++) {\n                distC[s][t] = dist[candRid[t]];\n            }\n        }\n\n        edgeCacheId.assign(C * C, -1);\n        edgeCacheBits.clear();\n        edgeCacheBits.reserve((size_t)min<long long>(1LL * C * C, 60000LL));\n    }\n\n    inline int edge_cost(int a, int b) const { return distC[a][b]; }\n\n    bool bits_empty(const vector<ull>& bits) const {\n        for (ull x : bits) if (x) return false;\n        return true;\n    }\n\n    int gain_of_candidate(int c, const vector<ull>& unc) const {\n        int g = 0;\n        for (int b = 0; b < B; b++) g += __builtin_popcountll(candBits[c][b] & unc[b]);\n        return g;\n    }\n\n    bool candidate_cover_full(const vector<int>& seq) const {\n        vector<ull> cov(B, 0ULL);\n        for (int c : seq) for (int b = 0; b < B; b++) cov[b] |= candBits[c][b];\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    struct Choice {\n        double score;\n        int cidx;\n        int pos;\n        int gain;\n        int inc;\n    };\n\n    void repair_cover(\n        vector<int>& seq,\n        vector<char>& used,\n        vector<ull>& unc,\n        double alpha,\n        double beta,\n        int topk,\n        double noise,\n        XorShift64& rng\n    ) {\n        int C = (int)candRid.size();\n\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            vector<Choice> top;\n            top.reserve(topk + 2);\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n\n                int gain = gain_of_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int bestInc = INF, bestPos = 0;\n                if (m == 1) {\n                    bestInc = edge_cost(seq[0], c) + edge_cost(c, seq[0]);\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < bestInc) {\n                            bestInc = inc;\n                            bestPos = p;\n                        }\n                    }\n                }\n                if (bestInc >= INF / 4) continue;\n\n                double num;\n                if (alpha == 1.0) num = (double)gain;\n                else if (alpha == 2.0) num = (double)gain * gain;\n                else num = pow((double)gain, alpha);\n\n                double den = (beta == 1.0 ? (double)(bestInc + 1)\n                                          : pow((double)(bestInc + 1), beta));\n                double sc = num / den;\n                if (noise > 0.0) {\n                    double z = rng.next_double() * 2.0 - 1.0;\n                    sc *= (1.0 + noise * z);\n                }\n\n                Choice ch{sc, c, bestPos, gain, bestInc};\n\n                if ((int)top.size() < topk) {\n                    top.push_back(ch);\n                    int z = (int)top.size() - 1;\n                    while (z > 0 && top[z].score > top[z - 1].score) {\n                        swap(top[z], top[z - 1]);\n                        --z;\n                    }\n                } else if (ch.score > top.back().score) {\n                    top.back() = ch;\n                    int z = (int)top.size() - 1;\n                    while (z > 0 && top[z].score > top[z - 1].score) {\n                        swap(top[z], top[z - 1]);\n                        --z;\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            int pick = 0;\n            if ((int)top.size() > 1) {\n                int sz = (int)top.size();\n                int total = sz * (sz + 1) / 2;\n                int r = rng.next_int(1, total);\n                for (int i = 0; i < sz; i++) {\n                    int w = sz - i;\n                    r -= w;\n                    if (r <= 0) {\n                        pick = i;\n                        break;\n                    }\n                }\n            }\n\n            auto ch = top[pick];\n            seq.insert(seq.begin() + ch.pos + 1, ch.cidx);\n            used[ch.cidx] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[ch.cidx][b];\n        }\n\n        // deterministic completion\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            int bestC = -1, bestPos = 0;\n            int bestGain = -1, bestInc = INF;\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n                int gain = gain_of_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int incMin = INF, pos = 0;\n                if (m == 1) {\n                    incMin = edge_cost(seq[0], c) + edge_cost(c, seq[0]);\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < incMin) {\n                            incMin = inc;\n                            pos = p;\n                        }\n                    }\n                }\n\n                if (gain > bestGain || (gain == bestGain && incMin < bestInc)) {\n                    bestGain = gain;\n                    bestInc = incMin;\n                    bestC = c;\n                    bestPos = pos;\n                }\n            }\n\n            if (bestC == -1) break;\n            seq.insert(seq.begin() + bestPos + 1, bestC);\n            used[bestC] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[bestC][b];\n        }\n    }\n\n    vector<int> build_cover(double alpha, double beta, int topk, double noise, XorShift64& rng) {\n        int C = (int)candRid.size();\n\n        vector<int> seq = {0};\n        vector<char> used(C, 0);\n        used[0] = 1;\n\n        vector<ull> unc = allBits;\n        for (int b = 0; b < B; b++) unc[b] &= ~candBits[0][b];\n\n        repair_cover(seq, used, unc, alpha, beta, topk, noise, rng);\n        return seq;\n    }\n\n    long long cycle_cost(const vector<int>& seq) const {\n        int m = (int)seq.size();\n        if (m <= 1) return 0;\n        long long c = 0;\n        for (int i = 0; i < m; i++) c += edge_cost(seq[i], seq[(i + 1) % m]);\n        return c;\n    }\n\n    void prune_waypoint_cost(vector<int>& seq) {\n        if (seq.size() <= 1) return;\n\n        vector<int> cnt(R, 0);\n        for (int x : seq) for (int rid : candVisList[x]) cnt[rid]++;\n\n        while (true) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestPos = -1;\n            long long bestSave = LLONG_MIN;\n\n            for (int p = 1; p < m; p++) {\n                int x = seq[p];\n\n                bool removable = true;\n                for (int rid : candVisList[x]) {\n                    if (cnt[rid] <= 1) {\n                        removable = false;\n                        break;\n                    }\n                }\n                if (!removable) continue;\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n                long long save =\n                    (long long)edge_cost(pr, x) + edge_cost(x, nx) - edge_cost(pr, nx);\n\n                if (save > bestSave) {\n                    bestSave = save;\n                    bestPos = p;\n                }\n            }\n\n            if (bestPos == -1 || bestSave < 0) break;\n\n            int x = seq[bestPos];\n            for (int rid : candVisList[x]) cnt[rid]--;\n            seq.erase(seq.begin() + bestPos);\n        }\n    }\n\n    bool improve_relocate1(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n\n            int x = seq[i];\n            int p = seq[(i - 1 + m) % m];\n            int n = seq[(i + 1) % m];\n\n            long long rem = -(long long)edge_cost(p, x) - edge_cost(x, n) + edge_cost(p, n);\n\n            for (int j = 0; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n                if (j == i) continue;\n                if (j == (i - 1 + m) % m) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n                long long delta = rem - (long long)edge_cost(a, b) + edge_cost(a, x) + edge_cost(x, b);\n\n                if (delta < 0) {\n                    int node = seq[i];\n                    seq.erase(seq.begin() + i);\n                    int jj = j;\n                    if (jj > i) jj--;\n                    seq.insert(seq.begin() + jj + 1, node);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool improve_swap(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n\n                long long delta = 0;\n                if (i + 1 == j) {\n                    int p = seq[i - 1], a = seq[i], b = seq[j], n = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(p, a) + edge_cost(a, b) + edge_cost(b, n);\n                    long long newc = (long long)edge_cost(p, b) + edge_cost(b, a) + edge_cost(a, n);\n                    delta = newc - oldc;\n                } else {\n                    int pi = seq[i - 1], a = seq[i], ni = seq[(i + 1) % m];\n                    int pj = seq[j - 1], b = seq[j], nj = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(pi, a) + edge_cost(a, ni)\n                                   + (long long)edge_cost(pj, b) + edge_cost(b, nj);\n                    long long newc = (long long)edge_cost(pi, b) + edge_cost(b, ni)\n                                   + (long long)edge_cost(pj, a) + edge_cost(a, nj);\n                    delta = newc - oldc;\n                }\n\n                if (delta < 0) {\n                    swap(seq[i], seq[j]);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    // exact directed 2-opt delta with O(1) segment reversal term\n    bool improve_2opt_directed(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 4) return false;\n\n        vector<long long> pf(m, 0), pr(m, 0);\n        for (int k = 0; k < m - 1; k++) {\n            pf[k + 1] = pf[k] + edge_cost(seq[k], seq[k + 1]);\n            pr[k + 1] = pr[k] + edge_cost(seq[k + 1], seq[k]);\n        }\n\n        for (int i = 1; i < m - 1; i++) {\n            if (elapsed_ms() > endMs) return false;\n\n            int a = seq[i - 1];\n            int b = seq[i];\n\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n\n                int c = seq[j];\n                int d = seq[(j + 1) % m];\n\n                long long forwardInternal = pf[j] - pf[i];\n                long long reverseInternal = pr[j] - pr[i];\n                long long oldBound = (long long)edge_cost(a, b) + edge_cost(c, d);\n                long long newBound = (long long)edge_cost(a, c) + edge_cost(b, d);\n\n                long long delta = newBound + reverseInternal - oldBound - forwardInternal;\n\n                if (delta < 0) {\n                    reverse(seq.begin() + i, seq.begin() + j + 1);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    void local_search(vector<int>& seq, long long& curCost, long long endMs) {\n        if (seq.size() <= 2) return;\n\n        int it = 0;\n        while (elapsed_ms() < endMs) {\n            bool imp = false;\n            if ((it % 3) == 0) {\n                if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_2opt_directed(seq, curCost, endMs)) imp = true;\n                else if (improve_swap(seq, curCost, endMs)) imp = true;\n            } else if ((it % 3) == 1) {\n                if (improve_2opt_directed(seq, curCost, endMs)) imp = true;\n                else if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_swap(seq, curCost, endMs)) imp = true;\n            } else {\n                if (improve_swap(seq, curCost, endMs)) imp = true;\n                else if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_2opt_directed(seq, curCost, endMs)) imp = true;\n            }\n\n            if (!imp) break;\n            if ((it & 31) == 31) curCost = cycle_cost(seq);\n            if (++it > 260000) break;\n        }\n        curCost = cycle_cost(seq);\n    }\n\n    bool replace_candidatewise(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 1) return false;\n        int C = (int)candRid.size();\n\n        vector<int> cnt(R, 0);\n        vector<char> used(C, 0);\n        for (int x : seq) {\n            used[x] = 1;\n            for (int rid : candVisList[x]) cnt[rid]++;\n        }\n\n        vector<ull> uniq(B, 0ULL);\n        bool improvedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            bool improved = false;\n\n            for (int p = 1; p < m; p++) {\n                if ((p & 7) == 0 && elapsed_ms() > endMs) break;\n\n                int old = seq[p];\n\n                fill(uniq.begin(), uniq.end(), 0ULL);\n                for (int rid : candVisList[old]) {\n                    if (cnt[rid] == 1) uniq[rid >> 6] |= (1ULL << (rid & 63));\n                }\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n\n                long long bestDelta = 0;\n                int bestQ = -1;\n\n                for (int q = 0; q < C; q++) {\n                    if (used[q]) continue;\n\n                    bool ok = true;\n                    for (int b = 0; b < B; b++) {\n                        if (uniq[b] & ~candBits[q][b]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) continue;\n\n                    int c1 = edge_cost(pr, q), c2 = edge_cost(q, nx);\n                    if (c1 >= INF / 4 || c2 >= INF / 4) continue;\n\n                    long long delta =\n                        -(long long)edge_cost(pr, old) - edge_cost(old, nx) + c1 + c2;\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestQ = q;\n                    }\n                }\n\n                if (bestQ != -1) {\n                    used[old] = 0;\n                    used[bestQ] = 1;\n                    for (int rid : candVisList[old]) cnt[rid]--;\n                    for (int rid : candVisList[bestQ]) cnt[rid]++;\n                    seq[p] = bestQ;\n                    curCost += bestDelta;\n                    improved = true;\n                    improvedAny = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        curCost = cycle_cost(seq);\n        return improvedAny;\n    }\n\n    vector<int> ruin_recreate(const vector<int>& base, XorShift64& rng) {\n        vector<int> seq = base;\n        int m = (int)seq.size();\n\n        if (m > 1) {\n            double ratio = 0.12 + 0.30 * rng.next_double();\n            int k = max(1, (int)((m - 1) * ratio));\n            k = min(k, m - 1);\n\n            vector<int> rem;\n            bool informed = (rng.next_double() < 0.70 && m >= 8);\n\n            if (informed) {\n                vector<int> cnt(R, 0);\n                for (int x : seq) for (int rid : candVisList[x]) cnt[rid]++;\n\n                struct Info { double key; int pos; };\n                vector<Info> info;\n                info.reserve(m - 1);\n\n                for (int p = 1; p < m; p++) {\n                    int x = seq[p];\n\n                    int uniq = 0;\n                    for (int rid : candVisList[x]) if (cnt[rid] == 1) uniq++;\n\n                    int pr = seq[(p - 1 + m) % m];\n                    int nx = seq[(p + 1) % m];\n                    long long save = (long long)edge_cost(pr, x) + edge_cost(x, nx) - edge_cost(pr, nx);\n\n                    double key = uniq * 900.0\n                               - 3.5 * max(0LL, save)\n                               + 1.2 * max(0LL, -save)\n                               + 10.0 * rng.next_double();\n\n                    info.push_back({key, p});\n                }\n\n                sort(info.begin(), info.end(), [](const Info& a, const Info& b) {\n                    return a.key < b.key;\n                });\n\n                vector<char> picked(m, 0);\n                int det = min((int)info.size(), max(1, (int)(k * 0.7)));\n\n                for (int i = 0; i < det; i++) {\n                    rem.push_back(info[i].pos);\n                    picked[info[i].pos] = 1;\n                }\n\n                vector<int> rest;\n                for (int i = det; i < (int)info.size(); i++) {\n                    if (!picked[info[i].pos]) rest.push_back(info[i].pos);\n                }\n\n                while ((int)rem.size() < k && !rest.empty()) {\n                    int idx = rng.next_int(0, (int)rest.size() - 1);\n                    rem.push_back(rest[idx]);\n                    rest[idx] = rest.back();\n                    rest.pop_back();\n                }\n            } else {\n                vector<int> pos(m - 1);\n                for (int i = 0; i < m - 1; i++) pos[i] = i + 1;\n                for (int i = (int)pos.size() - 1; i > 0; i--) {\n                    int j = rng.next_int(0, i);\n                    swap(pos[i], pos[j]);\n                }\n                pos.resize(k);\n                rem.swap(pos);\n            }\n\n            sort(rem.begin(), rem.end());\n            rem.erase(unique(rem.begin(), rem.end()), rem.end());\n            sort(rem.rbegin(), rem.rend());\n            for (int p : rem) seq.erase(seq.begin() + p);\n        }\n\n        int C = (int)candRid.size();\n        vector<char> used(C, 0);\n        for (int x : seq) used[x] = 1;\n\n        vector<ull> unc = allBits;\n        for (int x : seq) for (int b = 0; b < B; b++) unc[b] &= ~candBits[x][b];\n\n        static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.3};\n        static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n        static const int KS[] = {1, 2, 3, 4, 6};\n\n        double alpha = AS[rng.next_int(0, 5)];\n        double beta  = BS[rng.next_int(0, 3)];\n        int topk     = KS[rng.next_int(0, 4)];\n        double noise = 0.12;\n\n        repair_cover(seq, used, unc, alpha, beta, topk, noise, rng);\n        return seq;\n    }\n\n    const vector<ull>& get_edge_bits(int a, int b) {\n        int C = (int)candRid.size();\n        int key = a * C + b;\n        int cid = edgeCacheId[key];\n        if (cid != -1) return edgeCacheBits[cid];\n\n        vector<ull> bits(B, 0ULL);\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int bb = 0; bb < B; bb++) bits[bb] |= vb[bb];\n        };\n\n        int src = candRid[a];\n        int dst = candRid[b];\n\n        addRid(src);\n        int cur = dst;\n\n        while (cur != src) {\n            addRid(cur);\n            int p = prevFrom[a][cur];\n            if (p < 0) break;\n            cur = p;\n        }\n\n        edgeCacheId[key] = (int)edgeCacheBits.size();\n        edgeCacheBits.push_back(move(bits));\n        return edgeCacheBits.back();\n    }\n\n    bool coverage_full_sequence(const vector<int>& seq) {\n        if (seq.empty()) return false;\n\n        vector<ull> cov(B, 0ULL);\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            const auto &eb = get_edge_bits(seq[i], seq[(i + 1) % m]);\n            for (int b = 0; b < B; b++) cov[b] |= eb[b];\n        }\n\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    bool coverage_after_remove(const vector<int>& seq, int rm1, int rm2 = -1) {\n        vector<int> tmp;\n        tmp.reserve((int)seq.size() - (rm1 >= 0) - (rm2 >= 0 && rm2 != rm1));\n        for (int i = 0; i < (int)seq.size(); i++) {\n            if (i == rm1 || i == rm2) continue;\n            tmp.push_back(seq[i]);\n        }\n        return coverage_full_sequence(tmp);\n    }\n\n    bool route_aware_prune_combo(vector<int>& seq, long long endMs) {\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            vector<pair<long long, int>> cand; // save, pos\n            cand.reserve(max(0, m - 1));\n\n            for (int p = 1; p < m; p++) {\n                int pr = seq[(p - 1 + m) % m];\n                int cur = seq[p];\n                int nx = seq[(p + 1) % m];\n                long long save = (long long)edge_cost(pr, cur) + edge_cost(cur, nx) - edge_cost(pr, nx);\n                if (save >= 0) cand.push_back({save, p});\n            }\n            if (cand.empty()) break;\n\n            sort(cand.begin(), cand.end(), [](auto &a, auto &b) { return a.first > b.first; });\n\n            bool changedRound = false;\n\n            int K = min((m > 180 ? 12 : 20), (int)cand.size());\n            for (int i = 0; i < K; i++) {\n                if (elapsed_ms() > endMs) break;\n                int p = cand[i].second;\n                if (coverage_after_remove(seq, p)) {\n                    seq.erase(seq.begin() + p);\n                    changedRound = true;\n                    changedAny = true;\n                    break;\n                }\n            }\n            if (changedRound) continue;\n\n            int M = min((m > 180 ? 8 : 12), (int)cand.size());\n            long long baseCost = cycle_cost(seq);\n            long long bestSave = 0;\n            vector<int> bestTmp;\n\n            for (int i = 0; i < M; i++) {\n                if (elapsed_ms() > endMs) break;\n                for (int j = i + 1; j < M; j++) {\n                    if (elapsed_ms() > endMs) break;\n\n                    int p = cand[i].second;\n                    int q = cand[j].second;\n                    if (p == q) continue;\n\n                    vector<int> tmp;\n                    tmp.reserve(m - 2);\n                    for (int idx = 0; idx < m; idx++) {\n                        if (idx == p || idx == q) continue;\n                        tmp.push_back(seq[idx]);\n                    }\n                    if (tmp.empty()) continue;\n\n                    long long newCost = cycle_cost(tmp);\n                    long long save = baseCost - newCost;\n                    if (save <= bestSave) continue;\n\n                    if (coverage_full_sequence(tmp)) {\n                        bestSave = save;\n                        bestTmp.swap(tmp);\n                    }\n                }\n            }\n\n            if (bestSave > 0 && !bestTmp.empty()) {\n                seq.swap(bestTmp);\n                changedAny = true;\n                changedRound = true;\n            }\n\n            if (!changedRound) break;\n        }\n\n        return changedAny;\n    }\n\n    bool route_aware_replace(vector<int>& seq, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 1) return false;\n        int C = (int)candRid.size();\n\n        vector<char> used(C, 0);\n        for (int x : seq) used[x] = 1;\n\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            m = (int)seq.size();\n            if (m <= 1) break;\n\n            vector<pair<int, int>> posOrder; // local old cost, pos\n            posOrder.reserve(max(0, m - 1));\n            for (int p = 1; p < m; p++) {\n                int pr = seq[(p - 1 + m) % m];\n                int cur = seq[p];\n                int nx = seq[(p + 1) % m];\n                int oldL = edge_cost(pr, cur) + edge_cost(cur, nx);\n                posOrder.push_back({oldL, p});\n            }\n            sort(posOrder.begin(), posOrder.end(),\n                 [](const auto& a, const auto& b) { return a.first > b.first; });\n\n            int P = min(14, (int)posOrder.size());\n            bool improved = false;\n\n            for (int ii = 0; ii < P && elapsed_ms() < endMs; ii++) {\n                int p = posOrder[ii].second;\n                int old = seq[p];\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n                int oldL = edge_cost(pr, old) + edge_cost(old, nx);\n\n                struct Cand { int delta; int q; };\n                vector<Cand> top;\n                const int Q = 8;\n\n                for (int q = 0; q < C; q++) {\n                    if (used[q]) continue;\n                    int newL = edge_cost(pr, q) + edge_cost(q, nx);\n                    int delta = newL - oldL;\n                    if (delta >= 0) continue;\n\n                    int ins = (int)top.size();\n                    while (ins > 0 && top[ins - 1].delta > delta) ins--;\n                    if ((int)top.size() < Q) {\n                        top.insert(top.begin() + ins, Cand{delta, q});\n                    } else if (ins < Q) {\n                        top.insert(top.begin() + ins, Cand{delta, q});\n                        top.pop_back();\n                    }\n                }\n\n                for (auto &c : top) {\n                    int q = c.q;\n                    seq[p] = q;\n                    used[old] = 0;\n                    used[q] = 1;\n\n                    if (coverage_full_sequence(seq)) {\n                        improved = true;\n                        changedAny = true;\n                        break;\n                    }\n\n                    used[q] = 0;\n                    used[old] = 1;\n                    seq[p] = old;\n                }\n                if (improved) break;\n            }\n\n            if (!improved) break;\n        }\n\n        return changedAny;\n    }\n\n    bool route_aware_2opt(vector<int>& seq, long long endMs) {\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 4) break;\n\n            vector<long long> pf(m, 0), pr(m, 0);\n            for (int k = 0; k < m - 1; k++) {\n                pf[k + 1] = pf[k] + edge_cost(seq[k], seq[k + 1]);\n                pr[k + 1] = pr[k] + edge_cost(seq[k + 1], seq[k]);\n            }\n\n            struct Move { long long delta; int i, j; };\n            vector<Move> top;\n            const int KEEP = (m > 180 ? 12 : 20);\n\n            for (int i = 1; i < m - 1; i++) {\n                if (elapsed_ms() > endMs) break;\n                int a = seq[i - 1];\n                int b = seq[i];\n\n                for (int j = i + 1; j < m; j++) {\n                    if ((j & 63) == 0 && elapsed_ms() > endMs) break;\n\n                    int c = seq[j];\n                    int d = seq[(j + 1) % m];\n\n                    long long forwardInternal = pf[j] - pf[i];\n                    long long reverseInternal = pr[j] - pr[i];\n                    long long oldBound = (long long)edge_cost(a, b) + edge_cost(c, d);\n                    long long newBound = (long long)edge_cost(a, c) + edge_cost(b, d);\n                    long long delta = newBound + reverseInternal - oldBound - forwardInternal;\n\n                    if (delta >= 0) continue;\n\n                    Move mv{delta, i, j};\n                    if ((int)top.size() < KEEP) {\n                        top.push_back(mv);\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    } else if (mv.delta < top.back().delta) {\n                        top.back() = mv;\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            bool improved = false;\n            for (auto &mv : top) {\n                if (elapsed_ms() > endMs) break;\n                reverse(seq.begin() + mv.i, seq.begin() + mv.j + 1);\n                if (coverage_full_sequence(seq)) {\n                    improved = true;\n                    changedAny = true;\n                    break;\n                }\n                reverse(seq.begin() + mv.i, seq.begin() + mv.j + 1);\n            }\n\n            if (!improved) break;\n        }\n\n        return changedAny;\n    }\n\n    bool route_aware_relocate(vector<int>& seq, long long endMs) {\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 2) break;\n\n            struct Move { long long delta; int i, j; };\n            vector<Move> top;\n            const int KEEP = (m > 180 ? 10 : 16);\n\n            for (int i = 1; i < m; i++) {\n                if (elapsed_ms() > endMs) break;\n\n                int x = seq[i];\n                int p = seq[(i - 1 + m) % m];\n                int n = seq[(i + 1) % m];\n\n                long long rem = -(long long)edge_cost(p, x) - edge_cost(x, n) + edge_cost(p, n);\n\n                for (int j = 0; j < m; j++) {\n                    if ((j & 63) == 0 && elapsed_ms() > endMs) break;\n                    if (j == i) continue;\n                    if (j == (i - 1 + m) % m) continue;\n\n                    int a = seq[j];\n                    int b = seq[(j + 1) % m];\n                    long long delta = rem - (long long)edge_cost(a, b) + edge_cost(a, x) + edge_cost(x, b);\n                    if (delta >= 0) continue;\n\n                    Move mv{delta, i, j};\n                    if ((int)top.size() < KEEP) {\n                        top.push_back(mv);\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    } else if (mv.delta < top.back().delta) {\n                        top.back() = mv;\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            bool improved = false;\n            for (auto &mv : top) {\n                if (elapsed_ms() > endMs) break;\n\n                vector<int> tmp = seq;\n                int i = mv.i, j = mv.j;\n                int node = tmp[i];\n                tmp.erase(tmp.begin() + i);\n                int jj = j;\n                if (jj > i) jj--;\n                tmp.insert(tmp.begin() + jj + 1, node);\n\n                if (coverage_full_sequence(tmp)) {\n                    seq.swap(tmp);\n                    improved = true;\n                    changedAny = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return changedAny;\n    }\n\n    char move_char(int u, int v) const {\n        if (ri[v] == ri[u] - 1 && rj[v] == rj[u]) return 'U';\n        if (ri[v] == ri[u] + 1 && rj[v] == rj[u]) return 'D';\n        if (ri[v] == ri[u] && rj[v] == rj[u] - 1) return 'L';\n        if (ri[v] == ri[u] && rj[v] == rj[u] + 1) return 'R';\n        return '?';\n    }\n\n    string build_answer(const vector<int>& seq) const {\n        string ans;\n        int m = (int)seq.size();\n        if (m <= 1) return ans;\n\n        long long c = cycle_cost(seq);\n        ans.reserve((size_t)(max(1LL, c / 6) + 64));\n\n        vector<int> rev;\n        rev.reserve(256);\n\n        for (int i = 0; i < m; i++) {\n            int sCand = seq[i];\n            int tCand = seq[(i + 1) % m];\n            int src = candRid[sCand];\n            int dst = candRid[tCand];\n            if (src == dst) continue;\n\n            rev.clear();\n            int cur = dst;\n            while (cur != src) {\n                rev.push_back(cur);\n                cur = prevFrom[sCand][cur];\n                if (cur < 0) return \"\";\n            }\n\n            int u = src;\n            for (int k = (int)rev.size() - 1; k >= 0; k--) {\n                int v = rev[k];\n                char ch = move_char(u, v);\n                if (ch == '?') return \"\";\n                ans.push_back(ch);\n                u = v;\n            }\n        }\n\n        return ans;\n    }\n\n    int dir_id(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    bool validate_ans(const string& ans) const {\n        if (startRid < 0) return false;\n\n        vector<ull> cov(B, 0ULL);\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int b = 0; b < B; b++) cov[b] |= vb[b];\n        };\n\n        int cur = startRid;\n        addRid(cur);\n\n        for (char ch : ans) {\n            int d = dir_id(ch);\n            if (d < 0) return false;\n            int nx = nbr[cur][d];\n            if (nx == -1) return false;\n            cur = nx;\n            addRid(cur);\n        }\n\n        if (cur != startRid) return false;\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    string fallback_dfs_tour() const {\n        vector<char> vis(R, 0);\n        string out;\n        out.reserve(max(0, 2 * R + 8));\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1 || vis[v]) continue;\n                out.push_back(MV[d]);\n                dfs(v);\n                out.push_back(MV[OPP[d]]);\n            }\n        };\n\n        dfs(startRid);\n        return out;\n    }\n\n    uint64_t calc_seed() const {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)si);\n        mix((uint64_t)sj);\n        mix((uint64_t)R);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                mix((uint64_t)(unsigned char)grid[i][j]\n                    + ((uint64_t)i << 8)\n                    + ((uint64_t)j << 16));\n            }\n        }\n        return h;\n    }\n\n    string solve() {\n        t0 = chrono::steady_clock::now();\n\n        build_graph();\n        if (R == 0) return \"\";\n\n        init_bits();\n        build_road_visibility();\n        build_candidates();\n        precompute_shortest_paths();\n\n        XorShift64 rng(calc_seed());\n\n        const long long TL = 2940;\n\n        vector<int> bestSeq = {0};\n        long long bestCost = (1LL << 60);\n\n        auto update_best = [&](const vector<int>& seq, long long c) {\n            if (seq.empty()) return;\n            if (!candidate_cover_full(seq)) return;\n            if (c < bestCost) {\n                bestCost = c;\n                bestSeq = seq;\n            }\n        };\n\n        // Baseline deterministic\n        {\n            auto seq = build_cover(2.0, 1.0, 1, 0.0, rng);\n            prune_waypoint_cost(seq);\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(TL - 30, elapsed_ms() + 140));\n            if (elapsed_ms() < TL - 80) {\n                replace_candidatewise(seq, c, min(TL - 60, elapsed_ms() + 35));\n            }\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n        }\n\n        // light diversified start\n        if (elapsed_ms() < TL - 500) {\n            auto seq = build_cover(1.4, 1.0, 3, 0.06, rng);\n            prune_waypoint_cost(seq);\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(TL - 300, elapsed_ms() + 80));\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n        }\n\n        vector<int> curSeq = bestSeq;\n        long long curCost = bestCost;\n\n        // dynamic phase split\n        long long now = elapsed_ms();\n        long long rem = max(0LL, TL - now);\n\n        long long tConstruct = now + rem * 22 / 100;\n        long long tRR        = now + rem * 72 / 100;\n        long long tPolish    = now + rem * 88 / 100;\n        long long tRoute     = TL - 5;\n\n        if (tConstruct > tRR) tConstruct = tRR;\n        if (tRR > tPolish) tRR = tPolish;\n\n        // constructive multi-start\n        while (elapsed_ms() < tConstruct) {\n            static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.3};\n            static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n            static const int KS[] = {1, 2, 3, 4, 6};\n\n            double alpha = AS[rng.next_int(0, 5)];\n            double beta  = BS[rng.next_int(0, 3)];\n            int topk     = KS[rng.next_int(0, 4)];\n            double noise = 0.12;\n\n            auto seq = build_cover(alpha, beta, topk, noise, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(tConstruct, elapsed_ms() + 55));\n\n            if (elapsed_ms() < tConstruct - 20 && rng.next_double() < 0.55) {\n                replace_candidatewise(seq, c, min(tConstruct, elapsed_ms() + 20));\n            }\n\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n        }\n\n        curSeq = bestSeq;\n        curCost = bestCost;\n\n        // ruin & recreate + SA-like acceptance\n        while (elapsed_ms() < tRR) {\n            vector<int> base = (rng.next_double() < 0.65 ? bestSeq : curSeq);\n\n            auto seq = ruin_recreate(base, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(tRR, elapsed_ms() + 70));\n\n            if (elapsed_ms() < tRR - 20 && rng.next_double() < 0.65) {\n                replace_candidatewise(seq, c, min(tRR, elapsed_ms() + 22));\n            }\n\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n\n            double prog = (double)(elapsed_ms() - tConstruct) / (double)max(1LL, tRR - tConstruct);\n            prog = max(0.0, min(1.0, prog));\n            double temp = 16.0 * (1.0 - prog) + 1.0;\n\n            long long delta = c - curCost;\n            if (delta <= 0 || rng.next_double() < exp(-(double)delta / temp)) {\n                curSeq = seq;\n                curCost = c;\n            }\n        }\n\n        // final candidate-level polish\n        if (elapsed_ms() < tPolish && !bestSeq.empty()) {\n            auto seq = bestSeq;\n            long long c = bestCost;\n\n            while (elapsed_ms() < tPolish) {\n                long long before = c;\n\n                local_search(seq, c, min(tPolish, elapsed_ms() + 60));\n                if (elapsed_ms() < tPolish - 20) {\n                    replace_candidatewise(seq, c, min(tPolish, elapsed_ms() + 25));\n                }\n\n                prune_waypoint_cost(seq);\n                c = cycle_cost(seq);\n\n                if (c < bestCost && candidate_cover_full(seq)) {\n                    bestCost = c;\n                    bestSeq = seq;\n                }\n                if (c >= before) break;\n            }\n        }\n\n        vector<int> finalSeq = bestSeq;\n\n        // route-aware phase (may break candidate-level full but keep real full coverage)\n        if (elapsed_ms() < tRoute && finalSeq.size() > 1) {\n            while (elapsed_ms() < tRoute) {\n                bool changed = false;\n\n                changed |= route_aware_prune_combo(finalSeq, min(tRoute, elapsed_ms() + 85));\n                if (elapsed_ms() < tRoute) {\n                    changed |= route_aware_replace(finalSeq, min(tRoute, elapsed_ms() + 85));\n                }\n                if (elapsed_ms() < tRoute) {\n                    changed |= route_aware_2opt(finalSeq, min(tRoute, elapsed_ms() + 85));\n                }\n                if (elapsed_ms() < tRoute) {\n                    changed |= route_aware_relocate(finalSeq, min(tRoute, elapsed_ms() + 85));\n                }\n\n                if (!changed) break;\n            }\n\n            // keep only if valid and no worse\n            if (!coverage_full_sequence(finalSeq) || cycle_cost(finalSeq) > bestCost) {\n                finalSeq = bestSeq;\n            }\n        }\n\n        string ans = build_answer(finalSeq);\n\n        // safety fallback\n        if ((finalSeq.size() > 1 && ans.empty()) || !validate_ans(ans)) {\n            string alt = build_answer(bestSeq);\n            if (validate_ans(alt)) {\n                ans = alt;\n            } else {\n                ans = fallback_dfs_tour();\n            }\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\nusing namespace std;\nusing namespace atcoder;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n\n    int N, M, K, R;\n    vector<vector<int>> d;\n    vector<vector<int>> succ;\n    vector<int> indeg0, indegRem, outdeg;\n    vector<int> sumd;\n    vector<int> lp;          // dynamic remaining longest path (among unfinished tasks)\n    vector<int> descCnt;     // static descendant count\n    vector<int> taskState;   // 0:not started, 1:in progress, 2:done\n\n    vector<int> ready, readyPos, readySince;\n    int day = 1;\n    int stallDays = 0;\n\n    struct Member {\n        bool busy = false;\n        int task = -1;\n        int startDay = 0;\n        vector<int> s;\n        vector<int> histTask;\n        vector<int> histDur;\n        bool dirty = false;\n        int doneCount = 0;\n    };\n    vector<Member> members;\n\n    // ---- parameters ----\n    static constexpr int INIT_SKILL = 8;\n    static constexpr int SKILL_MAX = 80;\n    static constexpr int MAX_HIST = 120;\n\n    static constexpr int MAX_CAND = 180;\n    static constexpr int BASE_CAND = 110;\n    static constexpr int AGE_CAND = 40;\n\n    static constexpr int LP_W = 100;\n    static constexpr int DESC_W = 2;\n    static constexpr int UNLOCK_W = 70;\n    static constexpr int AGE_W = 6;\n\n    static constexpr double PRED_W = 40.0;\n    static constexpr double CRIT_MARGIN = 2.0;\n    static constexpr double CRIT_EXCESS_W = 220.0;\n    static constexpr double NEWBIE_CRIT_PEN = 120.0;\n\n    static constexpr double IDLE_UTILITY = -1800.0;\n    static constexpr long long COST_SHIFT = 1'000'000LL;\n\n    static inline double expected_time_from_w(int w) {\n        if (w <= 0) return 1.0;\n        if (w == 1) return 13.0 / 7.0;\n        if (w == 2) return 17.0 / 7.0;\n        if (w == 3) return 22.0 / 7.0;\n        return (double)w;\n    }\n\n    static inline long long utility_to_cost(double util) {\n        long long u10 = llround(util * 10.0);\n        long long c = COST_SHIFT - u10;\n        if (c < 0) c = 0;\n        return c;\n    }\n\n    double sample_loss(int w, int obs) const {\n        const double pred = expected_time_from_w(w);\n        const double e = pred - (double)obs;\n        const double ae = fabs(e);\n\n        // robust / noise-tolerant loss\n        double l;\n        if (ae <= 2.0) {\n            l = 0.25 * ae * ae;\n        } else {\n            const double z = ae - 2.0;\n            l = 1.0 + z * z;\n        }\n\n        // short tasks are less informative (especially obs=1 due clipping)\n        const double wt = (obs <= 1 ? 0.30 : (obs <= 3 ? 0.70 : 1.00));\n        return wt * l;\n    }\n\n    inline int calc_w(const vector<int>& s, int task) const {\n        int w = 0;\n        for (int k = 0; k < K; k++) {\n            if (d[task][k] > s[k]) w += d[task][k] - s[k];\n        }\n        return w;\n    }\n\n    inline double predict_time_exp(int member, int task) const {\n        int w = calc_w(members[member].s, task);\n        return expected_time_from_w(w);\n    }\n\n    void add_ready(int t, int availDay) {\n        if (t < 0 || t >= N) return;\n        if (taskState[t] != 0) return;\n        if (indegRem[t] != 0) return;\n        if (readyPos[t] != -1) return;\n        readyPos[t] = (int)ready.size();\n        ready.push_back(t);\n        readySince[t] = availDay;\n    }\n\n    void remove_ready(int t) {\n        int p = readyPos[t];\n        if (p == -1) return;\n        int last = ready.back();\n        ready[p] = last;\n        readyPos[last] = p;\n        ready.pop_back();\n        readyPos[t] = -1;\n        readySince[t] = -1;\n    }\n\n    void compute_static_descendants() {\n        descCnt.assign(N, 0);\n        if (N <= MAXN) {\n            vector<bitset<MAXN>> reach(N);\n            for (int i = N - 1; i >= 0; i--) {\n                for (int to : succ[i]) {\n                    reach[i] |= reach[to];\n                    reach[i].set(to);\n                }\n                descCnt[i] = (int)reach[i].count();\n            }\n        } else {\n            // fallback (shouldn't be used in official generator)\n            for (int i = 0; i < N; i++) descCnt[i] = outdeg[i];\n        }\n    }\n\n    void update_remaining_lp() {\n        if ((int)lp.size() != N) lp.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            if (taskState[i] == 2) {\n                lp[i] = 0;\n                continue;\n            }\n            int best = 1;\n            for (int to : succ[i]) {\n                if (taskState[to] != 2) best = max(best, lp[to] + 1);\n            }\n            lp[i] = best;\n        }\n    }\n\n    int task_base(int t) const {\n        int unlock = 0;\n        for (int ch : succ[t]) {\n            if (taskState[ch] == 0 && indegRem[ch] == 1) unlock++;\n        }\n        int age = 0;\n        if (readySince[t] >= 0) age = max(0, day - readySince[t]);\n\n        int base = 0;\n        base += LP_W * lp[t];\n        base += DESC_W * descCnt[t];\n        base += UNLOCK_W * unlock;\n        base += AGE_W * age;\n        base += outdeg[t]; // tiny tie-break\n        return base;\n    }\n\n    vector<int> make_candidates() const {\n        if ((int)ready.size() <= MAX_CAND) return ready;\n\n        vector<pair<int, int>> byBase; // (-base, t)\n        vector<pair<int, int>> byAge;  // (-age, t)\n        byBase.reserve(ready.size());\n        byAge.reserve(ready.size());\n\n        for (int t : ready) {\n            byBase.push_back({-task_base(t), t});\n            int age = max(0, day - readySince[t]);\n            byAge.push_back({-age, t});\n        }\n\n        sort(byBase.begin(), byBase.end());\n        sort(byAge.begin(), byAge.end());\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(MAX_CAND);\n\n        int t1 = min(BASE_CAND, (int)byBase.size());\n        for (int i = 0; i < t1; i++) {\n            int t = byBase[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        int t2 = min(AGE_CAND, (int)byAge.size());\n        for (int i = 0; i < t2 && (int)cand.size() < MAX_CAND; i++) {\n            int t = byAge[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        if ((int)cand.size() < MAX_CAND) {\n            vector<pair<int, int>> byEasy; // (sumd, t)\n            byEasy.reserve(ready.size());\n            for (int t : ready) {\n                if (!used[t]) byEasy.push_back({sumd[t], t});\n            }\n            sort(byEasy.begin(), byEasy.end());\n            for (auto &p : byEasy) {\n                if ((int)cand.size() >= MAX_CAND) break;\n                cand.push_back(p.second);\n            }\n        }\n        return cand;\n    }\n\n    void optimize_member(int j) {\n        Member &mb = members[j];\n        int total = (int)mb.histTask.size();\n        if (total == 0) {\n            mb.dirty = false;\n            return;\n        }\n\n        int st = max(0, total - MAX_HIST);\n        int h = total - st;\n\n        vector<int> tasks(h), obs(h), w(h);\n        for (int i = 0; i < h; i++) {\n            tasks[i] = mb.histTask[st + i];\n            obs[i] = mb.histDur[st + i];\n        }\n\n        for (int i = 0; i < h; i++) {\n            w[i] = calc_w(mb.s, tasks[i]);\n        }\n\n        const double reg = 0.30 / (h + 3.0); // stronger when data is scarce\n\n        double loss = 0.0;\n        for (int i = 0; i < h; i++) loss += sample_loss(w[i], obs[i]);\n        for (int k = 0; k < K; k++) {\n            double diff = (double)mb.s[k] - INIT_SKILL;\n            loss += reg * diff * diff;\n        }\n\n        static const int deltas_small[] = {-2, -1, 1, 2};\n        static const int deltas_large[] = {-8, -4, -2, -1, 1, 2, 4, 8};\n        const int *deltas = (h < 5 ? deltas_small : deltas_large);\n        int nd = (h < 5 ? 4 : 8);\n\n        int passes = (h < 8 ? 6 : (h < 20 ? 5 : 4));\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            bool improved = false;\n            if (pass & 1) reverse(order.begin(), order.end());\n\n            for (int idx = 0; idx < K; idx++) {\n                int k = order[idx];\n                int curS = mb.s[k];\n                double bestLoss = loss;\n                int bestS = curS;\n\n                for (int di = 0; di < nd; di++) {\n                    int ns = curS + deltas[di];\n                    if (ns < 0 || ns > SKILL_MAX || ns == curS) continue;\n\n                    double newLoss = loss;\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)ns - INIT_SKILL;\n                        newLoss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > ns ? dval - ns : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n\n                        newLoss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                    }\n\n                    if (newLoss + 1e-9 < bestLoss) {\n                        bestLoss = newLoss;\n                        bestS = ns;\n                    }\n                }\n\n                if (bestS != curS) {\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)bestS - INIT_SKILL;\n                        loss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > bestS ? dval - bestS : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n                        loss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                        w[i] = nw;\n                    }\n\n                    mb.s[k] = bestS;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        mb.dirty = false;\n    }\n\n    vector<pair<int, int>> decide_assignments(bool force) {\n        vector<pair<int, int>> ret;\n\n        vector<int> freeMembers;\n        freeMembers.reserve(M);\n        for (int j = 0; j < M; j++) {\n            if (!members[j].busy) freeMembers.push_back(j);\n        }\n        if (freeMembers.empty() || ready.empty()) return ret;\n\n        vector<int> cand = make_candidates();\n        int F = (int)freeMembers.size();\n        int T = (int)cand.size();\n        if (T == 0) return ret;\n\n        vector<int> base(T);\n        int maxReadyLp = 0, maxReadyDesc = 0;\n        for (int t : ready) {\n            maxReadyLp = max(maxReadyLp, lp[t]);\n            maxReadyDesc = max(maxReadyDesc, descCnt[t]);\n        }\n\n        vector<char> critical(T, 0);\n        for (int ti = 0; ti < T; ti++) {\n            int t = cand[ti];\n            base[ti] = task_base(t);\n            if (lp[t] >= maxReadyLp - 1) critical[ti] = 1;\n            if (descCnt[t] >= maxReadyDesc - 20) critical[ti] = 1;\n        }\n\n        vector<vector<double>> predAll(M, vector<double>(T));\n        vector<double> bestAllPred(T, 1e100);\n        for (int m = 0; m < M; m++) {\n            for (int ti = 0; ti < T; ti++) {\n                double p = predict_time_exp(m, cand[ti]);\n                predAll[m][ti] = p;\n                if (p < bestAllPred[ti]) bestAllPred[ti] = p;\n            }\n        }\n\n        int S = F + T;\n        int G = S + 1;\n        mcf_graph<int, long long> g(G + 1);\n\n        for (int fi = 0; fi < F; fi++) g.add_edge(S, fi, 1, 0);\n        for (int ti = 0; ti < T; ti++) g.add_edge(F + ti, G, 1, 0);\n\n        if (!force) {\n            long long idleCost = utility_to_cost(IDLE_UTILITY);\n            for (int fi = 0; fi < F; fi++) {\n                g.add_edge(fi, G, 1, idleCost);\n            }\n        }\n\n        vector<int> eid(F * T, -1);\n\n        for (int fi = 0; fi < F; fi++) {\n            int m = freeMembers[fi];\n            for (int ti = 0; ti < T; ti++) {\n                double pred = predAll[m][ti];\n                double util = (double)base[ti] - PRED_W * pred;\n\n                if (critical[ti]) {\n                    double excess = pred - bestAllPred[ti];\n                    if (excess > CRIT_MARGIN) {\n                        util -= CRIT_EXCESS_W * (excess - CRIT_MARGIN);\n                    }\n                    if (members[m].doneCount < 2) {\n                        util -= NEWBIE_CRIT_PEN;\n                    }\n                }\n\n                long long cost = utility_to_cost(util);\n                eid[fi * T + ti] = g.add_edge(fi, F + ti, 1, cost);\n            }\n        }\n\n        if (force) {\n            int L = min(T, max(1, F / 2)); // conservative forced progress\n            g.flow(S, G, L);\n        } else {\n            g.flow(S, G, F); // each free member: task or idle\n        }\n\n        for (int fi = 0; fi < F; fi++) {\n            for (int ti = 0; ti < T; ti++) {\n                auto e = g.get_edge(eid[fi * T + ti]);\n                if (e.flow > 0) {\n                    ret.push_back({freeMembers[fi], cand[ti]});\n                }\n            }\n        }\n\n        for (auto [m, t] : ret) {\n            members[m].busy = true;\n            members[m].task = t;\n            members[m].startDay = day;\n\n            taskState[t] = 1;\n            remove_ready(t);\n        }\n\n        return ret;\n    }\n\n    void read_initial() {\n        cin >> N >> M >> K >> R;\n\n        d.assign(N, vector<int>(K));\n        sumd.assign(N, 0);\n        for (int i = 0; i < N; i++) {\n            int s = 0;\n            for (int k = 0; k < K; k++) {\n                cin >> d[i][k];\n                s += d[i][k];\n            }\n            sumd[i] = s;\n        }\n\n        succ.assign(N, {});\n        indeg0.assign(N, 0);\n\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            succ[u].push_back(v);\n            indeg0[v]++;\n        }\n\n        outdeg.assign(N, 0);\n        for (int i = 0; i < N; i++) outdeg[i] = (int)succ[i].size();\n\n        compute_static_descendants();\n\n        indegRem = indeg0;\n        taskState.assign(N, 0);\n\n        ready.clear();\n        readyPos.assign(N, -1);\n        readySince.assign(N, -1);\n\n        day = 1;\n        for (int i = 0; i < N; i++) {\n            if (indegRem[i] == 0) add_ready(i, 1);\n        }\n\n        members.assign(M, Member());\n        for (int j = 0; j < M; j++) {\n            members[j].s.assign(K, INIT_SKILL);\n        }\n\n        lp.assign(N, 1);\n        update_remaining_lp();\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        read_initial();\n\n        while (true) {\n            update_remaining_lp();\n\n            int freeCntBefore = 0;\n            for (int j = 0; j < M; j++) if (!members[j].busy) freeCntBefore++;\n            bool hadReady = !ready.empty();\n\n            bool force = (stallDays >= 2);\n            auto assignments = decide_assignments(force);\n\n            if (hadReady && freeCntBefore > 0 && assignments.empty()) {\n                stallDays++;\n            } else if (!assignments.empty()) {\n                stallDays = 0;\n            } else if (!hadReady || freeCntBefore == 0) {\n                stallDays = 0;\n            }\n\n            cout << assignments.size();\n            for (auto [m, t] : assignments) {\n                cout << ' ' << (m + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int n;\n            if (!(cin >> n)) return;\n            if (n == -1) return;\n\n            vector<int> finished(n);\n            for (int i = 0; i < n; i++) {\n                cin >> finished[i];\n                --finished[i];\n            }\n\n            for (int m : finished) {\n                if (m < 0 || m >= M) continue;\n                Member &mb = members[m];\n                if (!mb.busy) continue;\n\n                int task = mb.task;\n                int duration = day - mb.startDay + 1;\n\n                mb.busy = false;\n                mb.task = -1;\n                mb.doneCount++;\n                mb.histTask.push_back(task);\n                mb.histDur.push_back(duration);\n                mb.dirty = true;\n\n                taskState[task] = 2;\n\n                for (int ch : succ[task]) {\n                    indegRem[ch]--;\n                    if (indegRem[ch] == 0 && taskState[ch] == 0) {\n                        add_ready(ch, day + 1);\n                    }\n                }\n            }\n\n            for (int m : finished) {\n                if (0 <= m && m < M && members[m].dirty) {\n                    optimize_member(m);\n                }\n            }\n\n            day++;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic uint16_t DISTMAT[2001][2001];\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t nextU32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(nextU32() % (uint32_t)n); }\n    double nextDouble() { return (nextU32() + 0.5) / 4294967296.0; }\n};\n\nclass Solver {\n    static constexpr int N = 1000;\n    static constexpr int M = 50;\n    static constexpr int DEP = 2000;\n    static constexpr int TOT = 2001;\n    static constexpr int K_NEAR = 24;\n\n    struct Insertion {\n        int delta;\n        int i, j; // insert pickup at i, delivery at j (after pickup insertion)\n    };\n\n    struct Cand {\n        int delta;\n        int id;\n        Insertion ins;\n    };\n\n    struct State {\n        vector<int> route; // pickup [0..999], delivery [1000..1999]\n        vector<int> sel;   // selected order IDs [0..999], size 50\n        array<int, N> pos; // -1 if unselected\n        int len;\n        State() : len(INT_MAX) {\n            route.reserve(2 * M);\n            sel.reserve(M);\n            pos.fill(-1);\n        }\n    };\n\n    int a[N], b[N], c[N], d[N];\n    int nodeX[TOT], nodeY[TOT];\n\n    array<int, N> baseCost{};\n    vector<int> sortedBase;\n\n    int nearOrders[TOT][K_NEAR];\n    array<unsigned char, TOT> nearBuilt{};\n\n    array<int, N> seen{};\n    int seenStamp = 1;\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n    double TL = 1.93;\n\n    vector<int> tmp1, tmp2, tmp3, ord, candIds;\n    vector<pair<int, int>> gains; // (removal gain, oid), descending\n\npublic:\n    Solver()\n        : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        tmp1.reserve(2 * M);\n        tmp2.reserve(2 * M);\n        tmp3.reserve(2 * M);\n        ord.reserve(M);\n        candIds.reserve(700);\n        gains.reserve(M);\n        nearBuilt.fill(0);\n        seen.fill(0);\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline void nextSeenStamp() {\n        ++seenStamp;\n        if (seenStamp == INT_MAX) {\n            seen.fill(0);\n            seenStamp = 1;\n        }\n    }\n\n    template <class T>\n    inline void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    inline int calcLen(const vector<int>& route) const {\n        int prev = DEP;\n        int len = 0;\n        for (int v : route) {\n            len += DISTMAT[prev][v];\n            prev = v;\n        }\n        len += DISTMAT[prev][DEP];\n        return len;\n    }\n\n    // O(n) exact best insertion for pair (pickup=oid, delivery=oid+N)\n    Insertion bestInsertPair(const vector<int>& route, int oid) const {\n        const int p = oid;\n        const int q = oid + N;\n        const int n = (int)route.size();\n\n        int U[105], V[105], dQ[105];\n        int sufVal[107], sufIdx[107];\n\n        const uint16_t* rowP = DISTMAT[p];\n        const uint16_t* rowQ = DISTMAT[q];\n        const int pq = rowP[q];\n\n        for (int t = 0; t <= n; ++t) {\n            U[t] = (t == 0 ? DEP : route[t - 1]);\n            V[t] = (t == n ? DEP : route[t]);\n            dQ[t] = (int)DISTMAT[U[t]][q] + (int)rowQ[V[t]] - (int)DISTMAT[U[t]][V[t]];\n        }\n\n        const int INF = 1e9;\n        sufVal[n + 1] = INF;\n        sufIdx[n + 1] = -1;\n        for (int t = n; t >= 0; --t) {\n            if (dQ[t] <= sufVal[t + 1]) {\n                sufVal[t] = dQ[t];\n                sufIdx[t] = t;\n            } else {\n                sufVal[t] = sufVal[t + 1];\n                sufIdx[t] = sufIdx[t + 1];\n            }\n        }\n\n        Insertion best{INF, 0, 1};\n\n        for (int i = 0; i <= n; ++i) {\n            int A = U[i];\n            int B = V[i];\n\n            // pickup insertion on edge i\n            int baseP = (int)DISTMAT[A][p] + (int)rowP[B] - (int)DISTMAT[A][B];\n\n            // adjacent delivery: A->p->q->B\n            int bestExtra = pq + (int)rowQ[B] - (int)rowP[B];\n            int bestJ = i + 1;\n\n            // separated delivery on original edge t >= i+1\n            if (i + 1 <= n && sufVal[i + 1] < bestExtra) {\n                bestExtra = sufVal[i + 1];\n                bestJ = sufIdx[i + 1] + 1;\n            }\n\n            int delta = baseP + bestExtra;\n            if (delta < best.delta) best = {delta, i, bestJ};\n        }\n\n        return best;\n    }\n\n    inline void insertPair(vector<int>& route, const Insertion& ins, int oid) const {\n        route.insert(route.begin() + ins.i, oid);\n        route.insert(route.begin() + ins.j, oid + N);\n    }\n\n    inline void removeOrder(const vector<int>& route, int oid, vector<int>& out) const {\n        out.clear();\n        const int p = oid;\n        const int q = oid + N;\n        for (int v : route) {\n            if (v == p || v == q) continue;\n            out.push_back(v);\n        }\n    }\n\n    inline void removeTwoOrders(const vector<int>& route, int o1, int o2, vector<int>& out) const {\n        out.clear();\n        int p1 = o1, q1 = o1 + N;\n        int p2 = o2, q2 = o2 + N;\n        for (int v : route) {\n            if (v == p1 || v == q1 || v == p2 || v == q2) continue;\n            out.push_back(v);\n        }\n    }\n\n    inline void pushTopCand(vector<Cand>& top, const Cand& c, int lim) const {\n        if ((int)top.size() < lim) {\n            top.push_back(c);\n            for (int i = (int)top.size() - 1; i > 0; --i) {\n                if (top[i].delta < top[i - 1].delta) swap(top[i], top[i - 1]);\n                else break;\n            }\n        } else if (c.delta < top.back().delta) {\n            top.back() = c;\n            for (int i = (int)top.size() - 1; i > 0; --i) {\n                if (top[i].delta < top[i - 1].delta) swap(top[i], top[i - 1]);\n                else break;\n            }\n        }\n    }\n\n    void buildNearForNode(int node) {\n        if (nearBuilt[node]) return;\n\n        static vector<pair<int, int>> cand;\n        cand.resize(N);\n\n        for (int id = 0; id < N; ++id) {\n            int sc = (int)DISTMAT[node][id]\n                   + (int)DISTMAT[id][id + N]\n                   + ((int)DISTMAT[id + N][DEP] >> 2);\n            cand[id] = {sc, id};\n        }\n\n        nth_element(cand.begin(), cand.begin() + K_NEAR, cand.end(),\n                    [](const auto& L, const auto& R) { return L.first < R.first; });\n        sort(cand.begin(), cand.begin() + K_NEAR,\n             [](const auto& L, const auto& R) { return L.first < R.first; });\n\n        for (int k = 0; k < K_NEAR; ++k) {\n            nearOrders[node][k] = cand[k].second;\n        }\n        nearBuilt[node] = 1;\n    }\n\n    void buildReplaceCandidates(const State& s, int oldId, int target, vector<int>& out) {\n        out.clear();\n        nextSeenStamp();\n\n        auto add = [&](int id) {\n            if (id < 0 || id >= N) return;\n            if (id == oldId) return;\n            if (s.pos[id] != -1) return;    // already selected\n            if (seen[id] == seenStamp) return;\n            seen[id] = seenStamp;\n            out.push_back(id);\n        };\n\n        buildNearForNode(DEP);\n        for (int k = 0; k < min(12, K_NEAR) && (int)out.size() < target; ++k) {\n            add(nearOrders[DEP][k]);\n        }\n\n        int nearTarget = target * 3 / 4;\n        int stride = 2 + rng.nextInt(2); // 2 or 3\n        int offset = rng.nextInt(stride);\n        int perNode = 4;\n\n        for (int idx = offset; idx < (int)s.route.size() && (int)out.size() < nearTarget; idx += stride) {\n            int node = s.route[idx];\n            buildNearForNode(node);\n            for (int k = 0; k < perNode && (int)out.size() < nearTarget; ++k) {\n                add(nearOrders[node][k]);\n            }\n        }\n\n        int baseTake = 320;\n        for (int i = 0; i < baseTake && i < N && (int)out.size() < target; ++i) {\n            add(sortedBase[i]);\n        }\n\n        int tries = 0;\n        while ((int)out.size() < target && tries < 5000) {\n            ++tries;\n            add(rng.nextInt(N));\n        }\n\n        if ((int)out.size() < target) {\n            for (int id = 0; id < N && (int)out.size() < target; ++id) {\n                add(id);\n            }\n        }\n    }\n\n    State buildGRASP(int rcl, int poolBase, int randExtra) {\n        rcl = max(1, rcl);\n        poolBase = max(80, min(poolBase, N));\n\n        State s;\n        s.len = 0;\n\n        vector<Cand> top;\n        top.reserve(rcl + 1);\n\n        for (int step = 0; step < M; ++step) {\n            candIds.clear();\n            nextSeenStamp();\n\n            auto addCand = [&](int id) {\n                if (s.pos[id] != -1) return;\n                if (seen[id] == seenStamp) return;\n                seen[id] = seenStamp;\n                candIds.push_back(id);\n            };\n\n            int lim = min(N, poolBase + step * 8);\n            for (int i = 0; i < lim; ++i) addCand(sortedBase[i]);\n\n            int target = min(N, lim + randExtra);\n            int tries = 0;\n            while ((int)candIds.size() < target && tries < 5000) {\n                ++tries;\n                addCand(rng.nextInt(N));\n            }\n            if ((int)candIds.size() < target) {\n                for (int id = 0; id < N && (int)candIds.size() < target; ++id) addCand(id);\n            }\n\n            top.clear();\n            for (int id : candIds) {\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTopCand(top, Cand{ins.delta, id, ins}, rcl);\n            }\n\n            if (top.empty()) {\n                Cand best{INT_MAX, -1, {INT_MAX, 0, 1}};\n                for (int id = 0; id < N; ++id) {\n                    if (s.pos[id] != -1) continue;\n                    Insertion ins = bestInsertPair(s.route, id);\n                    if (ins.delta < best.delta) best = Cand{ins.delta, id, ins};\n                }\n                top.push_back(best);\n            }\n\n            int pick = ((int)top.size() == 1 ? 0 : rng.nextInt((int)top.size()));\n            const Cand& ch = top[pick];\n\n            insertPair(s.route, ch.ins, ch.id);\n            s.len += ch.delta;\n            s.pos[ch.id] = (int)s.sel.size();\n            s.sel.push_back(ch.id);\n        }\n\n        s.len = calcLen(s.route);\n        return s;\n    }\n\n    bool relocateOrder(State& s, int oid) {\n        removeOrder(s.route, oid, tmp1);\n        int base = calcLen(tmp1);\n        Insertion ins = bestInsertPair(tmp1, oid);\n        int nlen = base + ins.delta;\n\n        if (nlen < s.len) {\n            tmp2 = tmp1;\n            insertPair(tmp2, ins, oid);\n            s.route.swap(tmp2);\n            s.len = nlen;\n            return true;\n        }\n        return false;\n    }\n\n    bool relocatePass(State& s, double deadline) {\n        ord = s.sel;\n        shuffleVec(ord);\n\n        bool improved = false;\n        for (int oid : ord) {\n            if (elapsed() >= deadline) break;\n            if (relocateOrder(s, oid)) improved = true;\n        }\n        return improved;\n    }\n\n    // Swap adjacent events if precedence remains valid.\n    bool adjacentSwapPass(State& s, int maxPass, double deadline) {\n        bool any = false;\n        int L = (int)s.route.size();\n\n        for (int pass = 0; pass < maxPass && elapsed() < deadline; ++pass) {\n            bool improved = false;\n            for (int i = 0; i + 1 < L; ++i) {\n                if ((i & 63) == 0 && elapsed() >= deadline) break;\n\n                int x = s.route[i];\n                int y = s.route[i + 1];\n\n                // forbidden: pickup directly before its own delivery\n                if (x < N && y == x + N) continue;\n\n                int A = (i == 0 ? DEP : s.route[i - 1]);\n                int B = (i + 2 == L ? DEP : s.route[i + 2]);\n\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\n                if (newCost < oldCost) {\n                    swap(s.route[i], s.route[i + 1]);\n                    s.len += newCost - oldCost;\n                    improved = true;\n                    any = true;\n                }\n            }\n            if (!improved) break;\n        }\n        return any;\n    }\n\n    // exact removal gain for each selected order\n    void computeRemovalGainsFast(const State& s) {\n        static int posNode[2 * N];\n        fill(posNode, posNode + 2 * N, -1);\n\n        const auto& r = s.route;\n        int L = (int)r.size();\n        for (int i = 0; i < L; ++i) posNode[r[i]] = i;\n\n        gains.clear();\n        gains.reserve(M);\n\n        for (int oid : s.sel) {\n            int p = oid;\n            int q = oid + N;\n            int ip = posNode[p];\n            int iq = posNode[q];\n            if (ip < 0 || iq < 0) continue;\n\n            int gain = 0;\n            if (iq == ip + 1) {\n                int A = (ip == 0 ? DEP : r[ip - 1]);\n                int B = (iq + 1 == L ? DEP : r[iq + 1]);\n                gain = (int)DISTMAT[A][p] + (int)DISTMAT[p][q] + (int)DISTMAT[q][B] - (int)DISTMAT[A][B];\n            } else {\n                int A = (ip == 0 ? DEP : r[ip - 1]);\n                int B = r[ip + 1];\n                int C = r[iq - 1];\n                int D = (iq + 1 == L ? DEP : r[iq + 1]);\n\n                gain =\n                    ((int)DISTMAT[A][p] + (int)DISTMAT[p][B] - (int)DISTMAT[A][B]) +\n                    ((int)DISTMAT[C][q] + (int)DISTMAT[q][D] - (int)DISTMAT[C][D]);\n            }\n\n            gains.emplace_back(gain, oid);\n        }\n\n        sort(gains.begin(), gains.end(),\n             [](const auto& L, const auto& R) { return L.first > R.first; });\n    }\n\n    int pickGainIndexForSA() {\n        int gs = (int)gains.size();\n        if (gs == 0) return -1;\n        int r = rng.nextInt(100);\n        if (r < 45) return 0;\n        if (r < 75) return rng.nextInt(min(gs, 4));\n        if (r < 93) return rng.nextInt(min(gs, 12));\n        return rng.nextInt(gs);\n    }\n\n    bool tryReplaceSampledSA(State& s, double temp, int candTarget) {\n        computeRemovalGainsFast(s);\n        int gi = pickGainIndexForSA();\n        if (gi < 0) return false;\n\n        int oldGain = gains[gi].first;\n        int oldId = gains[gi].second;\n\n        removeOrder(s.route, oldId, tmp1);\n        int base = s.len - oldGain; // exact\n\n        buildReplaceCandidates(s, oldId, candTarget, candIds);\n        if (candIds.empty()) return false;\n\n        struct RCand {\n            int nlen;\n            int id;\n            Insertion ins;\n        };\n\n        array<RCand, 6> top{};\n        int tsz = 0;\n\n        auto pushTop = [&](const RCand& c) {\n            if (tsz < 6) {\n                top[tsz++] = c;\n                for (int i = tsz - 1; i > 0; --i) {\n                    if (top[i].nlen < top[i - 1].nlen) swap(top[i], top[i - 1]);\n                    else break;\n                }\n            } else if (c.nlen < top[tsz - 1].nlen) {\n                top[tsz - 1] = c;\n                for (int i = tsz - 1; i > 0; --i) {\n                    if (top[i].nlen < top[i - 1].nlen) swap(top[i], top[i - 1]);\n                    else break;\n                }\n            }\n        };\n\n        for (int id : candIds) {\n            Insertion ins = bestInsertPair(tmp1, id);\n            int nlen = base + ins.delta;\n            pushTop(RCand{nlen, id, ins});\n        }\n\n        if (tsz == 0) return false;\n\n        int rr = rng.nextInt(100);\n        int choose = 0;\n        if (rr < 65) choose = 0;\n        else if (rr < 90) choose = rng.nextInt(min(tsz, 3));\n        else choose = rng.nextInt(tsz);\n\n        RCand ch = top[choose];\n        int diff = ch.nlen - s.len;\n        if (diff > 0) {\n            double prob = exp(-double(diff) / temp);\n            if (rng.nextDouble() >= prob) return false;\n        }\n\n        tmp2 = tmp1;\n        insertPair(tmp2, ch.ins, ch.id);\n\n        int idx = s.pos[oldId];\n        s.pos[oldId] = -1;\n        s.pos[ch.id] = idx;\n        s.sel[idx] = ch.id;\n\n        s.route.swap(tmp2);\n        s.len = ch.nlen;\n        return true;\n    }\n\n    bool tryBestReplaceImprovement(State& s, int topOldLimit, double deadline) {\n        computeRemovalGainsFast(s);\n        topOldLimit = min(topOldLimit, (int)gains.size());\n\n        for (int t = 0; t < topOldLimit; ++t) {\n            if (elapsed() >= deadline) return false;\n\n            int oldGain = gains[t].first;\n            int oldId = gains[t].second;\n\n            removeOrder(s.route, oldId, tmp1);\n            int base = s.len - oldGain;\n\n            int bestLen = s.len;\n            int bestId = -1;\n            Insertion bestIns{INT_MAX, 0, 1};\n\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                if ((id & 63) == 0 && elapsed() >= deadline) break;\n\n                Insertion ins = bestInsertPair(tmp1, id);\n                int nlen = base + ins.delta;\n                if (nlen < bestLen) {\n                    bestLen = nlen;\n                    bestId = id;\n                    bestIns = ins;\n                }\n            }\n\n            if (bestId != -1) {\n                tmp2 = tmp1;\n                insertPair(tmp2, bestIns, bestId);\n\n                int idx = s.pos[oldId];\n                s.pos[oldId] = -1;\n                s.pos[bestId] = idx;\n                s.sel[idx] = bestId;\n\n                s.route.swap(tmp2);\n                s.len = bestLen;\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void ruinRecreate(State& s, int k, int rcl, bool targeted) {\n        if (k <= 0) return;\n        rcl = max(1, rcl);\n\n        array<char, N> removed{};\n        removed.fill(0);\n\n        if (targeted) {\n            computeRemovalGainsFast(s);\n            int topRange = min((int)gains.size(), k + 12);\n            int cnt = 0;\n            while (cnt < k) {\n                int oid;\n                int rr = rng.nextInt(100);\n                if (rr < 50) oid = gains[cnt % topRange].second;\n                else oid = gains[rng.nextInt(topRange)].second;\n\n                if (removed[oid]) continue;\n                removed[oid] = 1;\n                ++cnt;\n            }\n        } else {\n            int cnt = 0;\n            while (cnt < k) {\n                int oid = s.sel[rng.nextInt((int)s.sel.size())];\n                if (removed[oid]) continue;\n                removed[oid] = 1;\n                ++cnt;\n            }\n        }\n\n        tmp1.clear();\n        tmp1.reserve((int)s.route.size() - 2 * k);\n        for (int v : s.route) {\n            int oid = (v < N ? v : v - N);\n            if (!removed[oid]) tmp1.push_back(v);\n        }\n        s.route.swap(tmp1);\n\n        vector<int> nsel;\n        nsel.reserve(M);\n        s.pos.fill(-1);\n        for (int oid : s.sel) {\n            if (!removed[oid]) {\n                s.pos[oid] = (int)nsel.size();\n                nsel.push_back(oid);\n            }\n        }\n        s.sel.swap(nsel);\n        s.len = calcLen(s.route);\n\n        vector<Cand> top;\n        top.reserve(rcl + 1);\n\n        for (int step = 0; step < k; ++step) {\n            top.clear();\n\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                if (removed[id]) continue; // force set change\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTopCand(top, Cand{ins.delta, id, ins}, rcl);\n            }\n\n            if (top.empty()) {\n                for (int id = 0; id < N; ++id) {\n                    if (s.pos[id] == -1) {\n                        Insertion ins = bestInsertPair(s.route, id);\n                        top.push_back(Cand{ins.delta, id, ins});\n                        break;\n                    }\n                }\n            }\n\n            int pick = ((int)top.size() == 1 ? 0 : rng.nextInt((int)top.size()));\n            const Cand& ch = top[pick];\n\n            insertPair(s.route, ch.ins, ch.id);\n            s.len += ch.delta;\n            s.pos[ch.id] = (int)s.sel.size();\n            s.sel.push_back(ch.id);\n        }\n\n        s.len = calcLen(s.route);\n    }\n\n    void finalImprove(State& s, double deadline) {\n        int stall = 0;\n        while (elapsed() < deadline && stall < 4) {\n            bool improved = false;\n\n            double d1 = min(deadline, elapsed() + 0.035);\n            while (elapsed() < d1) {\n                bool imp = false;\n                if (adjacentSwapPass(s, 2, d1)) imp = true;\n                if (relocatePass(s, d1)) imp = true;\n                if (!imp) break;\n                improved = true;\n            }\n\n            int rep = 0;\n            while (elapsed() < deadline && rep < 8) {\n                if (!tryBestReplaceImprovement(s, 12, deadline)) break;\n                improved = true;\n                ++rep;\n                double d2 = min(deadline, elapsed() + 0.010);\n                adjacentSwapPass(s, 2, d2);\n                relocatePass(s, d2);\n            }\n\n            if (!improved) ++stall;\n            else stall = 0;\n        }\n        s.len = calcLen(s.route);\n    }\n\n    void output(const State& s) const {\n        cout << M;\n        for (int id : s.sel) cout << ' ' << (id + 1);\n        cout << '\\n';\n\n        int n = (int)s.route.size() + 2;\n        cout << n << ' ' << 400 << ' ' << 400;\n        for (int v : s.route) {\n            if (v < N) {\n                cout << ' ' << a[v] << ' ' << b[v];\n            } else {\n                int id = v - N;\n                cout << ' ' << c[id] << ' ' << d[id];\n            }\n        }\n        cout << ' ' << 400 << ' ' << 400 << '\\n';\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        t0 = chrono::steady_clock::now();\n\n        for (int i = 0; i < N; ++i) {\n            if (!(cin >> a[i] >> b[i] >> c[i] >> d[i])) return;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            nodeX[i] = a[i];\n            nodeY[i] = b[i];\n            nodeX[i + N] = c[i];\n            nodeY[i + N] = d[i];\n\n            baseCost[i] =\n                abs(400 - a[i]) + abs(400 - b[i]) +\n                abs(a[i] - c[i]) + abs(b[i] - d[i]) +\n                abs(c[i] - 400) + abs(d[i] - 400);\n        }\n        nodeX[DEP] = 400;\n        nodeY[DEP] = 400;\n\n        for (int i = 0; i < TOT; ++i) {\n            for (int j = 0; j < TOT; ++j) {\n                DISTMAT[i][j] = (uint16_t)(abs(nodeX[i] - nodeX[j]) + abs(nodeY[i] - nodeY[j]));\n            }\n        }\n\n        sortedBase.resize(N);\n        iota(sortedBase.begin(), sortedBase.end(), 0);\n        sort(sortedBase.begin(), sortedBase.end(), [&](int l, int r) {\n            return baseCost[l] < baseCost[r];\n        });\n\n        buildNearForNode(DEP);\n\n        // ----- Multi-start initialization -----\n        State best;\n        best.len = INT_MAX;\n\n        vector<int> rcls = {1, 2, 3, 5, 8};\n        int rp = 0;\n\n        double initEnd = min(TL * 0.22, elapsed() + 0.30);\n        while (elapsed() < initEnd) {\n            int rcl = rcls[rp % (int)rcls.size()];\n            ++rp;\n\n            int poolBase = 300 + rng.nextInt(280); // 300..579\n            int randExtra = 36 + rng.nextInt(48);  // 36..83\n\n            State s = buildGRASP(rcl, poolBase, randExtra);\n\n            double d = min(initEnd, elapsed() + 0.012);\n            adjacentSwapPass(s, 1, d);\n            relocatePass(s, d);\n\n            if (s.len < best.len) best = std::move(s);\n        }\n\n        if (best.len == INT_MAX) best = buildGRASP(2, 420, 60);\n\n        State cur = best;\n\n        // ----- Main search -----\n        int iter = 0;\n        int noBest = 0;\n        double mainEnd = TL - 0.22;\n        if (mainEnd < elapsed() + 0.18) mainEnd = TL - 0.12;\n\n        while (elapsed() < mainEnd) {\n            ++iter;\n\n            if ((iter & 127) == 0) {\n                cur.len = calcLen(cur.route); // safety recalibration\n            }\n\n            double prog = elapsed() / max(0.1, mainEnd);\n            if (prog > 1.0) prog = 1.0;\n\n            double temp = 32.0 * (1.0 - prog) + 0.9;\n            if (noBest > 70) temp *= 1.35;\n\n            bool moved = false;\n            int mv = rng.nextInt(100);\n\n            if (mv < 72) {\n                int candTarget = (prog < 0.55 ? 240 : (prog < 0.85 ? 190 : 150));\n                moved = tryReplaceSampledSA(cur, temp, candTarget);\n            } else if (mv < 86) {\n                int oid = cur.sel[rng.nextInt(M)];\n                moved = relocateOrder(cur, oid);\n            } else {\n                double d = min(mainEnd, elapsed() + 0.0015);\n                moved = adjacentSwapPass(cur, 1, d);\n            }\n\n            if (!moved && rng.nextInt(100) < 28) {\n                int oid = cur.sel[rng.nextInt(M)];\n                relocateOrder(cur, oid);\n            }\n\n            if ((iter & 47) == 0) {\n                double d = min(mainEnd, elapsed() + 0.007);\n                adjacentSwapPass(cur, 2, d);\n                relocatePass(cur, d);\n                if (rng.nextInt(100) < 40) {\n                    tryBestReplaceImprovement(cur, 3, d);\n                }\n            }\n\n            if (cur.len < best.len) {\n                best = cur;\n                noBest = 0;\n            } else {\n                ++noBest;\n            }\n\n            if (noBest > 95 && elapsed() < mainEnd - 0.05) {\n                bool escaped = false;\n\n                // quick deterministic intensification\n                double d1 = min(mainEnd, elapsed() + 0.018);\n                for (int t = 0; t < 2 && elapsed() < d1; ++t) {\n                    if (!tryBestReplaceImprovement(cur, 5, d1)) break;\n                    escaped = true;\n                    double d2 = min(mainEnd, elapsed() + 0.004);\n                    adjacentSwapPass(cur, 1, d2);\n                    relocatePass(cur, d2);\n                }\n\n                if (cur.len < best.len) {\n                    best = cur;\n                    escaped = true;\n                }\n\n                // targeted destroy-repair from elite\n                if (!escaped || rng.nextInt(100) < 75) {\n                    State cand = best;\n                    int k = (rng.nextInt(100) < 75 ? 2 : 3);\n                    ruinRecreate(cand, k, (k == 2 ? 4 : 3), true);\n\n                    double d = min(mainEnd, elapsed() + 0.040);\n                    while (elapsed() < d) {\n                        bool imp = false;\n                        if (adjacentSwapPass(cand, 2, d)) imp = true;\n                        if (relocatePass(cand, d)) imp = true;\n                        if (!imp) break;\n                    }\n                    if (elapsed() < d) {\n                        tryBestReplaceImprovement(cand, 6, d);\n                    }\n\n                    if (cand.len < cur.len || rng.nextInt(100) < 35) cur = cand;\n                    if (cand.len < best.len) best = cand;\n                }\n\n                noBest = 0;\n            }\n\n            if ((iter & 255) == 0 && cur.len > best.len + 340) {\n                cur = best;\n            }\n        }\n\n        // ----- Final intensification -----\n        State ans = best;\n        double finalEnd = TL - 0.001;\n\n        finalImprove(ans, finalEnd);\n\n        // one last small perturb+polish\n        if (elapsed() < finalEnd - 0.06) {\n            State cand = ans;\n            ruinRecreate(cand, 2, 3, true);\n\n            double d = min(finalEnd, elapsed() + 0.055);\n            while (elapsed() < d) {\n                bool imp = false;\n                if (adjacentSwapPass(cand, 2, d)) imp = true;\n                if (relocatePass(cand, d)) imp = true;\n                if (!imp) break;\n            }\n            if (elapsed() < d) tryBestReplaceImprovement(cand, 8, d);\n\n            if (cand.len < ans.len) ans = cand;\n        }\n\n        ans.len = calcLen(ans.route);\n        output(ans);\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int MC = 56;          // keep near previous best regime\nstatic constexpr int HALF = MC / 2;\nstatic constexpr int INF = 1e9;\nstatic_assert(MC % 2 == 0);\n\nstruct DSU {\n    int16_t par[N]; // root: -size, else parent index\n\n    inline void init() {\n        for (int i = 0; i < N; ++i) par[i] = -1;\n    }\n\n    inline int find(int x) {\n        while (par[x] >= 0) {\n            int p = par[x];\n            if (par[p] >= 0) par[x] = par[p];\n            x = p;\n        }\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n\n    inline bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (par[a] > par[b]) swap(a, b); // a has larger size (more negative)\n        par[a] += par[b];\n        par[b] = (int16_t)a;\n        return true;\n    }\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nint EU[M], EV[M], ED[M];\narray<uint16_t, M> ORDER_D;\narray<array<uint16_t, M>, MC> SCEN_W, SCEN_ORD, SCEN_SW;\n\n// deterministic bottleneck using d-weights on future edges only\ninline int det_bottleneck_d(const DSU& base, int idx, int u, int v) {\n    DSU uf = base;\n    int cu = uf.find(u), cv = uf.find(v);\n\n    for (int k = 0; k < M; ++k) {\n        int eid = ORDER_D[k];\n        if (eid <= idx) continue; // future edges only\n\n        int ra = uf.find(EU[eid]);\n        int rb = uf.find(EV[eid]);\n        if (ra == rb) continue;\n\n        bool touch_u = (ra == cu || rb == cu);\n        bool touch_v = (ra == cv || rb == cv);\n\n        if (uf.par[ra] > uf.par[rb]) swap(ra, rb);\n        uf.par[ra] += uf.par[rb];\n        uf.par[rb] = (int16_t)ra;\n\n        if (touch_u) cu = ra;\n        if (touch_v) cv = ra;\n\n        if (cu == cv) return ED[eid];\n    }\n    return INF; // cannot connect by future edges\n}\n\n// one-scenario gain = bottleneck(sample) - li\ninline int scen_gain(const DSU& base, int idx, int u, int v, int li, int ub, int s) {\n    DSU uf = base;\n    int cu = uf.find(u), cv = uf.find(v);\n\n    const auto& ord = SCEN_ORD[s];\n    const auto& sw = SCEN_SW[s];\n\n    int lim = (int)(upper_bound(sw.begin(), sw.end(), (uint16_t)ub) - sw.begin());\n\n    for (int k = 0; k < lim; ++k) {\n        int eid = ord[k];\n        if (eid <= idx) continue; // future only\n\n        int ra = uf.find(EU[eid]);\n        int rb = uf.find(EV[eid]);\n        if (ra == rb) continue;\n\n        bool touch_u = (ra == cu || rb == cu);\n        bool touch_v = (ra == cv || rb == cv);\n\n        if (uf.par[ra] > uf.par[rb]) swap(ra, rb);\n        uf.par[ra] += uf.par[rb];\n        uf.par[rb] = (int16_t)ra;\n\n        if (touch_u) cu = ra;\n        if (touch_v) cv = ra;\n\n        if (cu == cv) return (int)sw[k] - li;\n    }\n\n    // Should be rare when L is finite; safe fallback.\n    return ub - li;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int xs[N], ys[N];\n    for (int i = 0; i < N; ++i) {\n        if (!(cin >> xs[i] >> ys[i])) return 0;\n    }\n\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        EU[i] = u;\n        EV[i] = v;\n\n        long long dx = (long long)xs[u] - xs[v];\n        long long dy = (long long)ys[u] - ys[v];\n        ED[i] = (int)llround(sqrt((long double)dx * dx + (long double)dy * dy));\n    }\n\n    // order by d\n    for (int i = 0; i < M; ++i) ORDER_D[i] = (uint16_t)i;\n    sort(ORDER_D.begin(), ORDER_D.end(), [](uint16_t a, uint16_t b) {\n        if (ED[a] != ED[b]) return ED[a] < ED[b];\n        return a < b;\n    });\n\n    // stratified + antithetic scenario generation\n    XorShift64 rng(0x123456789ABCDEFULL);\n\n    for (int i = 0; i < M; ++i) {\n        int d = ED[i];\n        int n = 2 * d + 1; // number of integer values in [d, 3d]\n\n        array<int, HALF> q{};\n        for (int t = 0; t < HALF; ++t) {\n            int lo = (int)((1LL * t * n) / HALF);\n            int hi = (int)((1LL * (t + 1) * n) / HALF - 1);\n            if (hi < lo) hi = lo;\n            q[t] = rng.next_int(lo, hi);\n        }\n\n        // shuffle to decorrelate across scenarios\n        for (int t = HALF - 1; t >= 1; --t) {\n            int j = (int)(rng.next_u32() % (uint32_t)(t + 1));\n            swap(q[t], q[j]);\n        }\n\n        for (int t = 0; t < HALF; ++t) {\n            int w1 = d + q[t];\n            int w2 = d + ((n - 1) - q[t]); // antithetic around center\n            SCEN_W[t][i] = (uint16_t)w1;\n            SCEN_W[t + HALF][i] = (uint16_t)w2;\n        }\n    }\n\n    // sort each scenario by sampled weight\n    for (int s = 0; s < MC; ++s) {\n        for (int i = 0; i < M; ++i) SCEN_ORD[s][i] = (uint16_t)i;\n        auto& ord = SCEN_ORD[s];\n        auto& w = SCEN_W[s];\n\n        sort(ord.begin(), ord.end(), [&](uint16_t a, uint16_t b) {\n            if (w[a] != w[b]) return w[a] < w[b];\n            return a < b;\n        });\n\n        for (int k = 0; k < M; ++k) SCEN_SW[s][k] = w[ord[k]];\n    }\n\n    DSU uf_selected;\n    uf_selected.init();\n\n    constexpr long long TIE_EPS_SUM = MC / 2; // mean gain <= 0.5\n\n    for (int i = 0; i < M; ++i) {\n        int li;\n        if (!(cin >> li)) return 0;\n\n        int u = EU[i], v = EV[i];\n        int ans = 0;\n\n        // cycle edge in selected forest is always useless\n        if (!uf_selected.same(u, v)) {\n            int L = det_bottleneck_d(uf_selected, i, u, v);\n\n            if (L == INF) {\n                ans = 1; // mandatory\n            } else if (li <= L) {\n                ans = 1; // always beneficial in this model\n            } else if (li >= 3 * L) {\n                ans = 0; // always non-beneficial in this model\n            } else {\n                long long sum = 0;\n                int ub = 3 * L;\n\n                for (int s = 0; s < MC; ++s) {\n                    sum += scen_gain(uf_selected, i, u, v, li, ub, s);\n                }\n\n                if (llabs(sum) <= TIE_EPS_SUM) {\n                    // very close: deterministic fallback\n                    ans = (li <= 2 * L) ? 1 : 0;\n                } else {\n                    ans = (sum > 0) ? 1 : 0;\n                }\n            }\n        } else {\n            ans = 0;\n        }\n\n        if (ans == 1) uf_selected.unite(u, v);\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int r, c; };\nbool operator==(const Pos& a, const Pos& b){ return a.r == b.r && a.c == b.c; }\n\nstatic constexpr int BOARD = 30;\nstatic constexpr int BASE = 31;\nstatic constexpr int SZ = BASE * BASE;\nstatic constexpr long long INF64 = (1LL << 60);\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\ninline bool inBoard(int r, int c){ return 1 <= r && r <= BOARD && 1 <= c && c <= BOARD; }\ninline bool inBoard(const Pos& p){ return inBoard(p.r, p.c); }\ninline int pid(int r, int c){ return r * BASE + c; }\ninline int pid(const Pos& p){ return pid(p.r, p.c); }\nint manhattan(const Pos& a, const Pos& b){ return abs(a.r - b.r) + abs(a.c - b.c); }\n\nint dirFromUpper(char ch){\n    if(ch == 'U') return 0;\n    if(ch == 'D') return 1;\n    if(ch == 'L') return 2;\n    if(ch == 'R') return 3;\n    return -1;\n}\nint dirFromLower(char ch){\n    if(ch == 'u') return 0;\n    if(ch == 'd') return 1;\n    if(ch == 'l') return 2;\n    if(ch == 'r') return 3;\n    return -1;\n}\nchar lowerFromDelta(int dr, int dc){\n    if(dr == -1 && dc == 0) return 'u';\n    if(dr == 1 && dc == 0) return 'd';\n    if(dr == 0 && dc == -1) return 'l';\n    if(dr == 0 && dc == 1) return 'r';\n    return '.';\n}\nPos moved(const Pos& p, int d){ return Pos{p.r + DR[d], p.c + DC[d]}; }\n\nint petWeight(int t){\n    if(t == 1) return 1; // cow\n    if(t == 2) return 2; // pig\n    if(t == 3) return 3; // rabbit\n    if(t == 4) return 2; // dog\n    return 2;            // cat\n}\n\nstruct WallTask {\n    Pos target;\n    Pos standOut;\n    Pos standIn;\n    char buildOut;\n    char buildIn;\n};\n\nstruct RegionPlan {\n    int corner = 0; // 0:TL 1:TR 2:BL 3:BR\n    int s = 6;\n    vector<WallTask> tasks;\n    int gateIdx = 0;\n    Pos safeCell{1,1};\n    Pos decoyCell{30,30};\n\n    bool inRegion(const Pos& p) const {\n        if(corner == 0){\n            return (1 <= p.r && p.r <= s && 1 <= p.c && p.c <= s);\n        }else if(corner == 1){\n            int cL = 31 - s;\n            return (1 <= p.r && p.r <= s && cL <= p.c && p.c <= 30);\n        }else if(corner == 2){\n            int rT = 31 - s;\n            return (rT <= p.r && p.r <= 30 && 1 <= p.c && p.c <= s);\n        }else{\n            int rT = 31 - s;\n            int cL = 31 - s;\n            return (rT <= p.r && p.r <= 30 && cL <= p.c && p.c <= 30);\n        }\n    }\n};\n\nclass Solver {\npublic:\n    void run();\n\nprivate:\n    int N = 0, M = 0;\n    vector<Pos> pets;\n    vector<int> petType;\n    vector<Pos> humans;\n    bool passable[31][31]{};\n\n    RegionPlan plan;\n\n    enum Phase { BUILD, ENTER, CLOSE, DONE };\n    Phase phase = BUILD;\n\n    int gateCloser = -1;\n    int attemptCnt = 0;\n    int lastReplanTurn = -1000;\n    int lastBuiltCnt = 0;\n    int stallTurns = 0;\n    int closeStartTurn = -1;\n    int targetInside = 1;\n\n    // basics\n    void buildCounts(int humanCnt[31][31], int petCnt[31][31]) const;\n    bool canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const;\n\n    // path\n    void runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const;\n    void computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const;\n    char moveToward(int i, const Pos& target,\n                    const vector<array<int,SZ>>& dist,\n                    const vector<array<int,SZ>>& first) const;\n\n    // planning\n    RegionPlan generatePlan(int corner, int s) const;\n    void computeComponents(int compId[31][31], vector<int>& humCompCnt) const;\n    bool reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const;\n    long long evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                const int compId[31][31], const vector<int>& humCompCnt) const;\n    RegionPlan choosePlan(bool emergency, int avoidCorner) const;\n\n    // plan stats\n    int countInsideHumans(const RegionPlan& p) const;\n    int countInsidePets(const RegionPlan& p) const;\n    int builtNonGateWalls(const RegionPlan& p) const;\n    int remainingNonGateWalls(const RegionPlan& p) const;\n\n    // phase / replan\n    bool isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const;\n    int computeTargetInside(int turn, int insidePets, bool pressure) const;\n    void updatePhase(int turn, const int petCnt[31][31]);\n    bool shouldReplan(int turn, const int petCnt[31][31]) const;\n    bool replan(int turn);\n\n    // action generation\n    vector<char> decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]);\n\n    // simulation\n    void sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const;\n    void applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]);\n    void applyPetMoves(const vector<string>& pMoves);\n};\n\nvoid Solver::buildCounts(int humanCnt[31][31], int petCnt[31][31]) const {\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            humanCnt[r][c] = 0;\n            petCnt[r][c] = 0;\n        }\n    }\n    for(const auto& h: humans) humanCnt[h.r][h.c]++;\n    for(const auto& p: pets) petCnt[p.r][p.c]++;\n}\n\nbool Solver::canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    if(!inBoard(t)) return false;\n    if(humanCnt[t.r][t.c] > 0) return false;\n    if(petCnt[t.r][t.c] > 0) return false;\n    for(int d=0; d<4; d++){\n        int nr = t.r + DR[d], nc = t.c + DC[d];\n        if(!inBoard(nr, nc)) continue;\n        if(petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nvoid Solver::runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const {\n    dist.fill(-1);\n    first.fill(-1);\n    queue<Pos> q;\n    dist[pid(st)] = 0;\n    q.push(st);\n\n    while(!q.empty()){\n        Pos cur = q.front(); q.pop();\n        int cid = pid(cur);\n        for(int d=0; d<4; d++){\n            Pos nx{cur.r + DR[d], cur.c + DC[d]};\n            if(!inBoard(nx)) continue;\n            if(!passable[nx.r][nx.c]) continue;\n            int nid = pid(nx);\n            if(dist[nid] != -1) continue;\n            dist[nid] = dist[cid] + 1;\n            first[nid] = (cur == st ? d : first[cid]);\n            q.push(nx);\n        }\n    }\n}\n\nvoid Solver::computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const {\n    dist.resize(M);\n    first.resize(M);\n    for(int i=0; i<M; i++) runBFS(humans[i], dist[i], first[i]);\n}\n\nchar Solver::moveToward(int i, const Pos& target,\n                        const vector<array<int,SZ>>& dist,\n                        const vector<array<int,SZ>>& first) const {\n    if(!inBoard(target) || !passable[target.r][target.c]) return '.';\n    if(humans[i] == target) return '.';\n    int d = dist[i][pid(target)];\n    if(d <= 0) return '.';\n    int fd = first[i][pid(target)];\n    if(fd < 0) return '.';\n    return MOVE_CH[fd];\n}\n\nRegionPlan Solver::generatePlan(int corner, int s) const {\n    RegionPlan p;\n    p.corner = corner;\n    p.s = s;\n    p.tasks.clear();\n\n    auto addTask = [&](Pos target, Pos standOut, Pos standIn){\n        WallTask t;\n        t.target = target;\n        t.standOut = standOut;\n        t.standIn = standIn;\n        t.buildOut = lowerFromDelta(target.r - standOut.r, target.c - standOut.c);\n        t.buildIn = lowerFromDelta(target.r - standIn.r, target.c - standIn.c);\n        p.tasks.push_back(t);\n    };\n\n    Pos gate{-1,-1};\n\n    if(corner == 0){\n        for(int c=1; c<=s; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{s+1,1};\n        p.safeCell = Pos{1,1};\n        p.decoyCell = Pos{30,30};\n    }else if(corner == 1){\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{s+1,30};\n        p.safeCell = Pos{1,30};\n        p.decoyCell = Pos{30,1};\n    }else if(corner == 2){\n        int rT = 30 - s;\n        for(int c=1; c<=s; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{rT,1};\n        p.safeCell = Pos{30,1};\n        p.decoyCell = Pos{1,30};\n    }else{\n        int rT = 30 - s;\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{rT,30};\n        p.safeCell = Pos{30,30};\n        p.decoyCell = Pos{1,1};\n    }\n\n    p.gateIdx = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(p.tasks[i].target == gate){\n            p.gateIdx = i;\n            break;\n        }\n    }\n    return p;\n}\n\nvoid Solver::computeComponents(int compId[31][31], vector<int>& humCompCnt) const {\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) compId[r][c] = 0;\n\n    int cid = 0;\n    queue<Pos> q;\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            if(!passable[r][c] || compId[r][c] != 0) continue;\n            cid++;\n            compId[r][c] = cid;\n            q.push(Pos{r,c});\n            while(!q.empty()){\n                Pos cur = q.front(); q.pop();\n                for(int d=0; d<4; d++){\n                    int nr = cur.r + DR[d], nc = cur.c + DC[d];\n                    if(!inBoard(nr,nc) || !passable[nr][nc] || compId[nr][nc] != 0) continue;\n                    compId[nr][nc] = cid;\n                    q.push(Pos{nr,nc});\n                }\n            }\n        }\n    }\n\n    humCompCnt.assign(cid + 1, 0);\n    for(const auto& h: humans){\n        if(!passable[h.r][h.c]) continue;\n        int id = compId[h.r][h.c];\n        if(id >= 1 && id < (int)humCompCnt.size()) humCompCnt[id]++;\n    }\n}\n\nbool Solver::reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(!inBoard(p) || !passable[p.r][p.c]) return false;\n    int id = compId[p.r][p.c];\n    if(id <= 0 || id >= (int)humCompCnt.size()) return false;\n    return humCompCnt[id] > 0;\n}\n\nlong long Solver::evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                    const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(p.tasks.empty()) return INF64/2;\n    const WallTask& gate = p.tasks[p.gateIdx];\n\n    if(!inBoard(gate.target) || !passable[gate.target.r][gate.target.c]) return INF64/2;\n    if(!(reachableByHuman(gate.standIn, compId, humCompCnt) ||\n         reachableByHuman(gate.standOut, compId, humCompCnt))) return INF64/2;\n\n    int insidePets = 0, insidePetsW = 0;\n    int nearBoundary = 0, nearGate = 0;\n\n    for(int i=0; i<N; i++){\n        const Pos& pet = pets[i];\n        int w = petWeight(petType[i]);\n\n        if(p.inRegion(pet)){\n            insidePets++;\n            insidePetsW += w;\n        }\n\n        int md = 100;\n        for(const auto& t: p.tasks) md = min(md, manhattan(pet, t.target));\n        if(md <= 1) nearBoundary += 2*w;\n        else if(md == 2) nearBoundary += w;\n\n        if(manhattan(pet, gate.target) <= 2) nearGate += w;\n    }\n\n    int remaining = 0, impossible = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i];\n        if(!passable[t.target.r][t.target.c]) continue;\n        remaining++;\n        bool okOut = reachableByHuman(t.standOut, compId, humCompCnt);\n        bool okIn  = reachableByHuman(t.standIn, compId, humCompCnt);\n        if(!okOut && !okIn) impossible++;\n    }\n\n    int interiorWalls = 0;\n    if(p.corner == 0){\n        for(int r=1; r<=p.s; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 1){\n        int cL = 31 - p.s;\n        for(int r=1; r<=p.s; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 2){\n        int rT = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else{\n        int rT = 31 - p.s, cL = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }\n\n    long long humDist = 0;\n    for(const auto& h: humans) humDist += manhattan(h, gate.standOut);\n\n    long long score = 0;\n    score += 300000000LL * insidePets;\n    score +=  50000000LL * insidePetsW;\n    score +=    900000LL * nearGate;\n    score +=    250000LL * nearBoundary;\n    score +=  40000000LL * impossible;\n    score +=      4000LL * remaining;\n    score +=       120LL * humDist;\n    score +=    350000LL * interiorWalls;\n    score -= (emergency ? 1700LL : 3000LL) * p.s * p.s;\n\n    if(!passable[p.safeCell.r][p.safeCell.c]) score += 8000000LL;\n    if(avoidCorner >= 0 && p.corner == avoidCorner){\n        score += (emergency ? 300000LL : 1200000LL);\n    }\n    return score;\n}\n\nRegionPlan Solver::choosePlan(bool emergency, int avoidCorner) const {\n    int compId[31][31];\n    vector<int> humCompCnt;\n    computeComponents(compId, humCompCnt);\n\n    int sL = emergency ? 4 : 6;\n    int sR = emergency ? 7 : 10;\n\n    long long bestScore = INF64;\n    RegionPlan bestPlan;\n    bool found = false;\n\n    for(int corner=0; corner<4; corner++){\n        for(int s=sL; s<=sR; s++){\n            RegionPlan cand = generatePlan(corner, s);\n            long long sc = evaluateCandidate(cand, emergency, avoidCorner, compId, humCompCnt);\n            if(sc >= INF64/4) continue;\n            if(!found || sc < bestScore){\n                found = true;\n                bestScore = sc;\n                bestPlan = cand;\n            }\n        }\n    }\n\n    if(found) return bestPlan;\n    if(!plan.tasks.empty()) return plan;\n    return generatePlan(0, emergency ? 4 : 6);\n}\n\nint Solver::countInsideHumans(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& h: humans) if(p.inRegion(h)) cnt++;\n    return cnt;\n}\n\nint Solver::countInsidePets(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& x: pets) if(p.inRegion(x)) cnt++;\n    return cnt;\n}\n\nint Solver::builtNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int b = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(!passable[t.r][t.c]) b++;\n    }\n    return b;\n}\n\nint Solver::remainingNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int rem = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(passable[t.r][t.c]) rem++;\n    }\n    return rem;\n}\n\nbool Solver::isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const {\n    const Pos& g = p.tasks[p.gateIdx].target;\n    for(int r=max(1, g.r-2); r<=min(30, g.r+2); r++){\n        for(int c=max(1, g.c-2); c<=min(30, g.c+2); c++){\n            if(abs(r-g.r) + abs(c-g.c) > 2) continue;\n            if(petCnt[r][c] > 0) return true;\n        }\n    }\n    return false;\n}\n\nint Solver::computeTargetInside(int turn, int insidePets, bool pressure) const {\n    int t = max(1, M-1);\n    if(pressure) t = max(1, M-2);\n    if(insidePets >= 1) t = max(1, M-2);\n    if(turn >= 240) t = max(1, M-2);\n    if(turn >= 270) t = max(1, M-3);\n    if(turn >= 290) t = 1;\n    return min(t, M);\n}\n\nvoid Solver::updatePhase(int turn, const int petCnt[31][31]) {\n    if(phase == BUILD){\n        if(remainingNonGateWalls(plan) == 0){\n            phase = ENTER;\n            gateCloser = -1;\n            targetInside = max(1, M-1);\n        }\n    }\n\n    if(phase == ENTER){\n        int insideHum = countInsideHumans(plan);\n        int insidePets = countInsidePets(plan);\n        bool pressure = isGatePressured(plan, petCnt) || (insidePets > 0);\n        targetInside = computeTargetInside(turn, insidePets, pressure);\n\n        if(insideHum >= targetInside || (turn >= 289 && insideHum >= 1)){\n            phase = CLOSE;\n            closeStartTurn = turn;\n        }\n    }\n\n    if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(!passable[gt.r][gt.c]) phase = DONE;\n    }\n}\n\nbool Solver::shouldReplan(int turn, const int petCnt[31][31]) const {\n    if(phase == DONE) return false;\n    if(attemptCnt >= 2) return false;\n    if(turn - lastReplanTurn < 20) return false;\n\n    int rem = remainingNonGateWalls(plan);\n    int insidePets = countInsidePets(plan);\n    bool pressure = isGatePressured(plan, petCnt);\n\n    if(phase == BUILD){\n        if(rem > 0 && turn >= 190) return true;\n        if(rem > 0 && stallTurns >= 30 && turn <= 245) return true;\n        if(insidePets >= 2 && turn <= 175) return true;\n    }else if(phase == ENTER){\n        if(insidePets >= 2 && turn <= 220) return true;\n        if(turn >= 250 && countInsideHumans(plan) < max(1, M-2)) return true;\n    }else if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(passable[gt.r][gt.c] && closeStartTurn >= 0 &&\n           (turn - closeStartTurn) >= 40 && pressure && turn <= 245){\n            return true;\n        }\n    }\n    return false;\n}\n\nbool Solver::replan(int turn) {\n    bool emergency = (turn >= 140 || attemptCnt >= 1);\n    int avoid = plan.corner;\n    RegionPlan np = choosePlan(emergency, avoid);\n\n    if(np.corner == plan.corner && np.s == plan.s){\n        lastReplanTurn = turn; // cooldown\n        return false;\n    }\n\n    plan = np;\n    phase = BUILD;\n    gateCloser = -1;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n\n    attemptCnt++;\n    lastReplanTurn = turn;\n\n    if(remainingNonGateWalls(plan) == 0) phase = ENTER;\n    return true;\n}\n\nvector<char> Solver::decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n\n    vector<int> remaining;\n    for(int i=0; i<(int)plan.tasks.size(); i++){\n        if(i == plan.gateIdx) continue;\n        const Pos& t = plan.tasks[i].target;\n        if(passable[t.r][t.c]) remaining.push_back(i);\n    }\n    if(remaining.empty()) return act;\n\n    vector<char> isBuildable(plan.tasks.size(), 0);\n    vector<int> buildable;\n    for(int idx: remaining){\n        if(canBuildCell(plan.tasks[idx].target, humanCnt, petCnt)){\n            isBuildable[idx] = 1;\n            buildable.push_back(idx);\n        }\n    }\n\n    const vector<int>& cand = (!buildable.empty() ? buildable : remaining);\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    bool reserved[31][31]{};\n    vector<int> useCnt(plan.tasks.size(), 0);\n\n    // immediate build\n    for(int i=0; i<M; i++){\n        for(int idx: cand){\n            if(!isBuildable[idx]) continue;\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n\n            if(humans[i] == t.standOut){\n                act[i] = t.buildOut;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n            if(humans[i] == t.standIn){\n                act[i] = t.buildIn;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(act[i] != '.') continue;\n\n        int bestCost = 1e9;\n        int bestIdx = -1, bestMode = 0, bestD = -1;\n\n        for(int idx: cand){\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n            bool buildNow = isBuildable[idx];\n\n            for(int mode=0; mode<2; mode++){\n                Pos st = (mode == 0 ? t.standOut : t.standIn);\n                if(!inBoard(st) || !passable[st.r][st.c]) continue;\n                int d = dist[i][pid(st)];\n                if(d < 0) continue;\n                if(d == 0 && !buildNow) continue;\n\n                int cost = d*10 + useCnt[idx]*18 + (mode==1 ? 8 : 0) + (buildNow ? 0 : 30);\n                if(cost < bestCost){\n                    bestCost = cost;\n                    bestIdx = idx;\n                    bestMode = mode;\n                    bestD = d;\n                }\n            }\n        }\n\n        if(bestIdx == -1) continue;\n\n        useCnt[bestIdx]++;\n        const auto& t = plan.tasks[bestIdx];\n        bool buildNow = isBuildable[bestIdx];\n\n        if(bestD == 0 && buildNow && !reserved[t.target.r][t.target.c]){\n            act[i] = (bestMode == 0 ? t.buildOut : t.buildIn);\n            reserved[t.target.r][t.target.c] = true;\n        }else if(bestD > 0){\n            Pos st = (bestMode == 0 ? t.standOut : t.standIn);\n            int fd = first[i][pid(st)];\n            if(fd >= 0) act[i] = MOVE_CH[fd];\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)humanCnt;\n    (void)petCnt;\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        int da = dist[a][pid(gate.standIn)];\n        int db = dist[b][pid(gate.standIn)];\n        bool ra = (da >= 0), rb = (db >= 0);\n        if(ra != rb) return ra > rb;\n\n        bool ia = plan.inRegion(humans[a]);\n        bool ib = plan.inRegion(humans[b]);\n        if(ia != ib) return ia > ib;\n\n        int ka = ra ? da : 1000000;\n        int kb = rb ? db : 1000000;\n        if(ka != kb) return ka < kb;\n        return a < b;\n    });\n\n    vector<char> insideSet(M, 0);\n    int need = max(1, min(targetInside, M));\n    int got = 0;\n    for(int id: ord){\n        int d = dist[id][pid(gate.standIn)];\n        bool can = (d >= 0) || plan.inRegion(humans[id]);\n        if(!can) continue;\n        insideSet[id] = 1;\n        got++;\n        if(got >= need) break;\n    }\n\n    if(got == 0){\n        int fb = -1, best = 1e9;\n        for(int i=0; i<M; i++){\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; fb = i; }\n        }\n        if(fb == -1) fb = 0;\n        insideSet[fb] = 1;\n    }\n\n    gateCloser = -1;\n    int best = 1e9;\n    for(int i=0; i<M; i++){\n        if(!insideSet[i]) continue;\n        int d = dist[i][pid(gate.standIn)];\n        if(d >= 0 && d < best){ best = d; gateCloser = i; }\n    }\n    if(gateCloser == -1){\n        best = 1e9;\n        for(int i=0; i<M; i++){\n            if(!insideSet[i]) continue;\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; gateCloser = i; }\n        }\n    }\n    if(gateCloser == -1){\n        for(int i=0; i<M; i++) if(insideSet[i]) { gateCloser = i; break; }\n        if(gateCloser == -1) gateCloser = 0;\n    }\n\n    for(int i=0; i<M; i++){\n        if(insideSet[i]){\n            Pos tgt;\n            if(i == gateCloser){\n                tgt = gate.standIn;\n                if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n            }else{\n                if(plan.inRegion(humans[i])) tgt = plan.safeCell;\n                else{\n                    tgt = gate.standIn;\n                    if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n                }\n            }\n            act[i] = moveToward(i, tgt, dist, first);\n        }else{\n            act[i] = moveToward(i, plan.decoyCell, dist, first);\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    int builder = -1;\n    int buildSide = 0; // 0=in 1=out\n    int bestCost = 1e9;\n\n    for(int i=0; i<M; i++){\n        for(int side=0; side<2; side++){\n            Pos st = (side == 0 ? gate.standIn : gate.standOut);\n            if(!inBoard(st) || !passable[st.r][st.c]) continue;\n            int d = dist[i][pid(st)];\n            if(d < 0) continue;\n\n            int cost = d*10 + (side==1 ? 4 : 0);\n            if(gateCloser >= 0 && i != gateCloser) cost += 2;\n            if(!plan.inRegion(humans[i])) cost += 1;\n            if(d == 0 && canBuildCell(gate.target, humanCnt, petCnt)) cost -= 1000;\n\n            if(cost < bestCost){\n                bestCost = cost;\n                builder = i;\n                buildSide = side;\n            }\n        }\n    }\n\n    if(builder != -1){\n        Pos st = (buildSide == 0 ? gate.standIn : gate.standOut);\n        if(humans[builder] == st){\n            if(canBuildCell(gate.target, humanCnt, petCnt)){\n                act[builder] = (buildSide == 0 ? gate.buildIn : gate.buildOut);\n            }\n        }else{\n            act[builder] = moveToward(builder, st, dist, first);\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(i == builder) continue;\n        Pos tgt = plan.inRegion(humans[i]) ? plan.safeCell : plan.decoyCell;\n        act[i] = moveToward(i, tgt, dist, first);\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)turn;\n    if(phase == DONE) return vector<char>(M, '.');\n    if(phase == BUILD) return decideBuildActions(humanCnt, petCnt);\n    if(phase == ENTER) return decideEnterActions(humanCnt, petCnt);\n    return decideCloseActions(humanCnt, petCnt);\n}\n\nvoid Solver::sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    bool buildNow[31][31]{};\n\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }else{\n            act[i] = '.';\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to) || !passable[to.r][to.c] || buildNow[to.r][to.c]){\n            act[i] = '.';\n        }\n    }\n}\n\nvoid Solver::applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) {\n    bool passBefore[31][31];\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passBefore[r][c] = passable[r][c];\n\n    bool buildNow[31][31]{};\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }\n    }\n\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) if(buildNow[r][c]) passable[r][c] = false;\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to)) continue;\n        if(!passBefore[to.r][to.c]) continue;\n        if(buildNow[to.r][to.c]) continue;\n        humans[i] = to;\n    }\n}\n\nvoid Solver::applyPetMoves(const vector<string>& pMoves) {\n    for(int i=0; i<N; i++){\n        if(pMoves[i] == \".\") continue;\n        for(char ch: pMoves[i]){\n            int d = dirFromUpper(ch);\n            if(d < 0) continue;\n            pets[i].r += DR[d];\n            pets[i].c += DC[d];\n        }\n    }\n}\n\nvoid Solver::run() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if(!(cin >> N)) return;\n    pets.resize(N);\n    petType.resize(N);\n    for(int i=0; i<N; i++) cin >> pets[i].r >> pets[i].c >> petType[i];\n    cin >> M;\n    humans.resize(M);\n    for(int i=0; i<M; i++) cin >> humans[i].r >> humans[i].c;\n\n    for(int r=0; r<=BOARD; r++) for(int c=0; c<=BOARD; c++) passable[r][c] = false;\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passable[r][c] = true;\n\n    plan = choosePlan(false, -1);\n\n    phase = BUILD;\n    gateCloser = -1;\n    attemptCnt = 0;\n    lastReplanTurn = -1000;\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n\n    for(int turn=0; turn<300; turn++){\n        int humanCnt[31][31], petCnt[31][31];\n        buildCounts(humanCnt, petCnt);\n\n        if(phase == BUILD){\n            int b = builtNonGateWalls(plan);\n            if(b > lastBuiltCnt){\n                lastBuiltCnt = b;\n                stallTurns = 0;\n            }else{\n                stallTurns++;\n            }\n        }else{\n            stallTurns = 0;\n        }\n\n        updatePhase(turn, petCnt);\n\n        if(shouldReplan(turn, petCnt)){\n            bool changed = replan(turn);\n            if(changed) updatePhase(turn, petCnt);\n        }\n\n        vector<char> actions = decideActions(turn, humanCnt, petCnt);\n        sanitizeActions(actions, humanCnt, petCnt);\n\n        string out;\n        out.reserve(M);\n        for(char ch: actions) out.push_back(ch);\n        cout << out << '\\n';\n        cout.flush();\n\n        applyActions(actions, humanCnt, petCnt);\n\n        vector<string> pMoves(N);\n        for(int i=0; i<N; i++){\n            if(!(cin >> pMoves[i])) return;\n        }\n        applyPetMoves(pMoves);\n    }\n}\n\nint main(){\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    void reseed(uint64_t seed) { x = seed ? seed : 88172645463325252ull; }\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\nclass Solver {\n    static constexpr int H = 20;\n    static constexpr int W = 20;\n    static constexpr int N = 400;\n    static constexpr int L = 200;\n\n    int si, sj, ti, tj;\n    int start, target;\n    double p, q;\n    string h[H], v[H - 1];\n\n    int to_raw[N][4];\n    int to_eval[N][4];\n    double isTar[N];\n\n    vector<array<double, N>> fw, bw, ub;\n    array<double, L + 1> pref{};\n\n    vector<uint8_t> seq, bestSeq;\n    double curScore = -1e100, bestScore = -1e100;\n\n    vector<pair<double, vector<uint8_t>>> elite;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver() : fw(L + 1), bw(L + 1), ub(L + 1), seq(L), bestSeq(L) {}\n\n    void solve() {\n        readInput();\n        buildTransitions();\n        precomputeUB();\n\n        st = chrono::steady_clock::now();\n\n        vector<vector<uint8_t>> cands;\n        buildCandidates(cands);\n\n        elite.clear();\n        bestScore = -1e100;\n\n        for (auto &c : cands) {\n            seq = c;\n            curScore = recompute();\n            addElite(seq, curScore);\n        }\n\n        const double TL = 1.93;\n\n        // Initial refinement on top seeds\n        {\n            int use = min<int>(4, elite.size());\n            for (int i = 0; i < use && now() < 0.95; i++) {\n                seq = elite[i].second;\n                curScore = recompute();\n                updateBest();\n                double dl = min(TL, now() + 0.13);\n                localSearch(dl, 1);\n                if (now() < dl && rng.nextInt(100) < 50) {\n                    int w = 8 + rng.nextInt(8);\n                    int l = rng.nextInt(L - w + 1);\n                    beamPatch(l, w, 30, dl);\n                }\n                addElite(seq, curScore);\n            }\n        }\n\n        // Iterated local search\n        while (now() < TL - 0.08) {\n            int m = min<int>(6, elite.size());\n            int pick = 0;\n            int r = rng.nextInt(100);\n            if (m >= 2) {\n                if (r < 55) pick = 0;\n                else if (r < 85) pick = rng.nextInt(min(3, m));\n                else pick = rng.nextInt(m);\n            }\n\n            seq = elite[pick].second;\n            curScore = recompute();\n            updateBest();\n\n            int op = rng.nextInt(100);\n            if (op < 45) {\n                mutateCurrent();\n                curScore = recompute();\n                updateBest();\n            } else if (op < 75) {\n                int cut = rng.nextInt(L - 2);\n                regrowSuffixFromCut(cut, 0.12);\n                curScore = recompute();\n                updateBest();\n            } else {\n                bool ok = false;\n                for (int z = 0; z < 2 && now() < TL - 0.08; z++) {\n                    int w = 8 + rng.nextInt(9);\n                    int l = rng.nextInt(L - w + 1);\n                    int B = 24 + rng.nextInt(16);\n                    if (beamPatch(l, w, B, TL - 0.05)) {\n                        ok = true;\n                        break;\n                    }\n                }\n                if (!ok) {\n                    mutateCurrent();\n                    curScore = recompute();\n                    updateBest();\n                }\n            }\n\n            double dl = min(TL - 0.03, now() + 0.05);\n            localSearch(dl, 1);\n\n            if (now() < TL - 0.03 && rng.nextInt(100) < 35) {\n                int w = 7 + rng.nextInt(10);\n                int l = rng.nextInt(L - w + 1);\n                beamPatch(l, w, 30, TL - 0.02);\n            }\n\n            addElite(seq, curScore);\n        }\n\n        // Final polish from best\n        seq = bestSeq;\n        curScore = recompute();\n        updateBest();\n\n        while (now() < TL) {\n            bool imp = false;\n            imp |= singleSweep(TL);\n            if (now() < TL) imp |= pairSweep(TL);\n\n            if (!imp) {\n                bool pImp = false;\n                for (int z = 0; z < 3 && now() < TL; z++) {\n                    int w = 7 + rng.nextInt(10);\n                    int l = rng.nextInt(L - w + 1);\n                    if (beamPatch(l, w, 36, TL)) {\n                        pImp = true;\n                        break;\n                    }\n                }\n                if (!pImp) break;\n            }\n        }\n\n        const char mp[4] = {'U', 'D', 'L', 'R'};\n        string ans(L, 'U');\n        for (int i = 0; i < L; i++) ans[i] = mp[bestSeq[i]];\n        cout << ans << '\\n';\n    }\n\nprivate:\n    inline int id(int i, int j) const { return i * W + j; }\n\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void readInput() {\n        cin >> si >> sj >> ti >> tj >> p;\n        for (int i = 0; i < H; i++) cin >> h[i];\n        for (int i = 0; i < H - 1; i++) cin >> v[i];\n\n        start = id(si, sj);\n        target = id(ti, tj);\n        q = 1.0 - p;\n\n        uint64_t seed = 1469598103934665603ull;\n        auto mix = [&](uint64_t x) {\n            seed ^= x + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n        };\n        mix(si); mix(sj); mix(ti); mix(tj);\n        mix((uint64_t)llround(p * 1000.0));\n        for (int i = 0; i < H; i++) for (char c : h[i]) mix((uint64_t)c);\n        for (int i = 0; i < H - 1; i++) for (char c : v[i]) mix((uint64_t)c);\n        rng.reseed(seed);\n    }\n\n    void buildTransitions() {\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                int s = id(i, j);\n\n                // U\n                if (i == 0 || v[i - 1][j] == '1') to_raw[s][0] = s;\n                else to_raw[s][0] = id(i - 1, j);\n\n                // D\n                if (i == H - 1 || v[i][j] == '1') to_raw[s][1] = s;\n                else to_raw[s][1] = id(i + 1, j);\n\n                // L\n                if (j == 0 || h[i][j - 1] == '1') to_raw[s][2] = s;\n                else to_raw[s][2] = id(i, j - 1);\n\n                // R\n                if (j == W - 1 || h[i][j] == '1') to_raw[s][3] = s;\n                else to_raw[s][3] = id(i, j + 1);\n            }\n        }\n\n        for (int s = 0; s < N; s++) {\n            for (int a = 0; a < 4; a++) to_eval[s][a] = to_raw[s][a];\n            isTar[s] = (s == target ? 1.0 : 0.0);\n        }\n        // target absorbing\n        for (int a = 0; a < 4; a++) to_eval[target][a] = target;\n    }\n\n    inline void stepDist(const array<double, N>& cur, int a, array<double, N>& nxt) const {\n        nxt.fill(0.0);\n        for (int s = 0; s < N; s++) {\n            double pr = cur[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            if (n == s) {\n                nxt[s] += pr;\n            } else {\n                double mv = pr * q;\n                nxt[s] += pr - mv;\n                nxt[n] += mv;\n            }\n        }\n    }\n\n    inline double dotDouble(const array<double, N>& x, const array<double, N>& y) const {\n        double r = 0.0;\n        for (int s = 0; s < N; s++) r += x[s] * y[s];\n        return r;\n    }\n\n    inline double dotFloatDouble(const array<float, N>& x, const array<double, N>& y) const {\n        double r = 0.0;\n        for (int s = 0; s < N; s++) r += (double)x[s] * y[s];\n        return r;\n    }\n\n    void precomputeUB() {\n        ub[0].fill(0.0);\n        for (int rem = 1; rem <= L; rem++) {\n            int coef = (rem == 1 ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                double rs = isTar[s] * coef;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double cand;\n                    if (n == s) {\n                        cand = rs + ub[rem - 1][s];\n                    } else {\n                        double rn = isTar[n] * coef;\n                        cand = p * (rs + ub[rem - 1][s]) + q * (rn + ub[rem - 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                ub[rem][s] = best;\n            }\n        }\n    }\n\n    int bestActionUB1(const array<double, N>& dist, int t) const {\n        int rem = L - t;\n        int coef = (t + 1 == L ? 201 : 1);\n        const auto &U = ub[rem - 1];\n\n        int bestA = 0;\n        double bestV = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n            for (int s = 0; s < N; s++) {\n                double pr = dist[s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                double rs = isTar[s] * coef;\n                if (n == s) {\n                    val += pr * (rs + U[s]);\n                } else {\n                    double rn = isTar[n] * coef;\n                    val += pr * (p * (rs + U[s]) + q * (rn + U[n]));\n                }\n            }\n            if (val > bestV) {\n                bestV = val;\n                bestA = a;\n            }\n        }\n        return bestA;\n    }\n\n    int bestActionUB2(const array<double, N>& dist, int t) const {\n        int rem = L - t;\n        if (rem <= 1) return bestActionUB1(dist, t);\n\n        int c1 = (t + 1 == L ? 201 : 1);\n        int c2 = (t + 2 == L ? 201 : 1);\n        const auto &U = ub[rem - 2];\n\n        array<array<double, N>, 4> d1;\n        array<double, 4> v1{};\n        array<double, N> d2;\n\n        for (int a = 0; a < 4; a++) {\n            stepDist(dist, a, d1[a]);\n            v1[a] = c1 * d1[a][target];\n        }\n\n        int bestA = 0;\n        double bestV = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                stepDist(d1[a], b, d2);\n                double val = v1[a] + c2 * d2[target] + dotDouble(d2, U);\n                if (val > bestV) {\n                    bestV = val;\n                    bestA = a;\n                }\n            }\n        }\n        return bestA;\n    }\n\n    vector<int> shortestPath() {\n        vector<int> dist(N, -1), par(N, -1), pdir(N, -1);\n        queue<int> qu;\n        dist[start] = 0;\n        qu.push(start);\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            if (s == target) break;\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (dist[n] != -1) continue;\n                dist[n] = dist[s] + 1;\n                par[n] = s;\n                pdir[n] = a;\n                qu.push(n);\n            }\n        }\n\n        vector<int> path;\n        if (dist[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> weightedPath(double penUL, double noise) {\n        const double INF = 1e100;\n        vector<double> dist(N, INF);\n        vector<int> par(N, -1), pdir(N, -1);\n\n        array<array<double, 4>, N> rnd{};\n        for (int s = 0; s < N; s++) for (int a = 0; a < 4; a++) rnd[s][a] = rng.nextDouble();\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!pq.empty()) {\n            auto [cd, s] = pq.top();\n            pq.pop();\n            if (cd > dist[s] + 1e-15) continue;\n            if (s == target) break;\n\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                double w = 1.0 + ((a == 0 || a == 2) ? penUL : 0.0) + noise * rnd[s][a];\n                double nd = cd + w;\n                if (nd < dist[n]) {\n                    dist[n] = nd;\n                    par[n] = s;\n                    pdir[n] = a;\n                    pq.push({nd, n});\n                }\n            }\n        }\n\n        vector<int> path;\n        if (par[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> distToTarget() {\n        const int INF = 1e9;\n        vector<int> d(N, INF);\n        queue<int> qu;\n        d[target] = 0;\n        qu.push(target);\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            for (int a = 0; a < 4; a++) {\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (d[n] > d[s] + 1) {\n                    d[n] = d[s] + 1;\n                    qu.push(n);\n                }\n            }\n        }\n        return d;\n    }\n\n    vector<uint8_t> seedFromPath(const vector<int>& path, int rep, bool useUB2, double epsRand) {\n        vector<uint8_t> out;\n        out.reserve(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int dir : path) {\n            for (int k = 0; k < rep && (int)out.size() < L; k++) {\n                out.push_back((uint8_t)dir);\n                stepDist(cur, dir, nxt);\n                cur = nxt;\n            }\n            if ((int)out.size() >= L) break;\n        }\n\n        while ((int)out.size() < L) {\n            int t = (int)out.size();\n            int a = useUB2 ? bestActionUB2(cur, t) : bestActionUB1(cur, t);\n            if (epsRand > 0.0 && rng.nextDouble() < epsRand) a = rng.nextInt(4);\n            out.push_back((uint8_t)a);\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n\n        return out;\n    }\n\n    vector<uint8_t> greedyUBSeed(bool useUB2) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int a = useUB2 ? bestActionUB2(cur, t) : bestActionUB1(cur, t);\n            out[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n        return out;\n    }\n\n    vector<uint8_t> greedyStaticSeed(const vector<double>& val) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int bestA = 0;\n            double bestV = -1e100;\n\n            for (int a = 0; a < 4; a++) {\n                double v = 0.0;\n                for (int s = 0; s < N; s++) {\n                    double pr = cur[s];\n                    if (pr == 0.0) continue;\n                    int n = to_eval[s][a];\n                    if (n == s) v += pr * val[s];\n                    else v += pr * (p * val[s] + q * val[n]);\n                }\n                if (v > bestV) {\n                    bestV = v;\n                    bestA = a;\n                }\n            }\n\n            out[t] = (uint8_t)bestA;\n            stepDist(cur, bestA, nxt);\n            cur = nxt;\n        }\n\n        return out;\n    }\n\n    vector<uint8_t> globalBeamSeed(int B, double noise) {\n        struct Node {\n            array<float, N> dist;\n            double score;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double score;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> beam(1), nxt;\n        beam[0].dist.fill(0.0f);\n        beam[0].dist[start] = 1.0f;\n        beam[0].score = 0.0;\n        beam[0].key = ub[L][start];\n\n        vector<vector<pair<int, uint8_t>>> trace(L + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 8);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            return a.key > b.key;\n        };\n\n        for (int d = 0; d < L; d++) {\n            int coef = (d + 1 == L ? 201 : 1);\n            int rem = L - (d + 1); // remaining after this step\n            cand.clear();\n\n            for (int i = 0; i < (int)beam.size(); i++) {\n                const auto &nd = beam[i];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = i;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    for (int s = 0; s < N; s++) {\n                        float pr = nd.dist[s];\n                        if (pr == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += pr;\n                            if (s == target) inc += (double)pr;\n                        } else {\n                            float ps = (float)(pr * p);\n                            float pn = (float)(pr * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                        }\n                    }\n\n                    ch.score = nd.score + coef * inc;\n                    ch.key = ch.score + dotFloatDouble(ch.dist, ub[rem]);\n                    if (noise > 0.0) ch.key += noise * (rng.nextDouble() - 0.5);\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            nxt.resize(cand.size());\n            trace[d + 1].resize(cand.size());\n            for (int i = 0; i < (int)cand.size(); i++) {\n                nxt[i].dist = std::move(cand[i].dist);\n                nxt[i].score = cand[i].score;\n                nxt[i].key = cand[i].key;\n                trace[d + 1][i] = {cand[i].par, cand[i].act};\n            }\n            beam.swap(nxt);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)beam.size(); i++) {\n            if (beam[i].score > beam[bestIdx].score) bestIdx = i;\n        }\n\n        vector<uint8_t> out(L);\n        int idx = bestIdx;\n        for (int d = L; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            out[d - 1] = act;\n            idx = par;\n        }\n        return out;\n    }\n\n    void buildCandidates(vector<vector<uint8_t>>& cands) {\n        auto sp = shortestPath();\n        int rep0 = (int)llround(1.3 / max(1e-9, q));\n        rep0 = max(1, min(6, rep0));\n\n        vector<int> reps = {1, max(1, rep0 - 1), rep0, min(7, rep0 + 1), min(8, rep0 + 2)};\n        sort(reps.begin(), reps.end());\n        reps.erase(unique(reps.begin(), reps.end()), reps.end());\n\n        if (!sp.empty()) {\n            for (int rep : reps) cands.push_back(seedFromPath(sp, rep, false, 0.0));\n            cands.push_back(seedFromPath(sp, rep0, true, 0.0));\n            cands.push_back(seedFromPath(sp, min(8, rep0 + 1), true, 0.05));\n        }\n\n        vector<pair<double, double>> params = {\n            {0.0, 0.0},\n            {0.4, 0.0},\n            {0.8, 0.0},\n            {0.2, 0.25},\n            {0.6, 0.25}\n        };\n        for (auto [pen, noise] : params) {\n            auto pth = weightedPath(pen, noise);\n            if (pth.empty()) continue;\n            cands.push_back(seedFromPath(pth, rep0, false, 0.0));\n            cands.push_back(seedFromPath(pth, min(8, rep0 + 1), true, 0.02));\n        }\n\n        cands.push_back(greedyUBSeed(false));\n        cands.push_back(greedyUBSeed(true));\n\n        auto d = distToTarget();\n        vector<double> val(N);\n        for (int s = 0; s < N; s++) val[s] = -1.0 * d[s];\n        cands.push_back(greedyStaticSeed(val));\n\n        int Bmain = 120 + (p > 0.35 ? 20 : 0) + (p > 0.45 ? 10 : 0);\n        cands.push_back(globalBeamSeed(Bmain, 0.0));\n        if (now() < 0.70) cands.push_back(globalBeamSeed(70, 0.02));\n\n        // fallback patterns\n        vector<uint8_t> pat(L);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 1 : 3); // D...R...\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 3 : 1); // R...D...\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = ((i & 1) ? 3 : 1);   // D,R,D,R\n        cands.push_back(pat);\n\n        // random fallback\n        vector<uint8_t> rnd(L);\n        for (int i = 0; i < L; i++) rnd[i] = (uint8_t)rng.nextInt(4);\n        cands.push_back(rnd);\n    }\n\n    double recompute() {\n        fw[0].fill(0.0);\n        fw[0][start] = 1.0;\n        pref[0] = 0.0;\n\n        for (int t = 0; t < L; t++) {\n            fw[t + 1].fill(0.0);\n            int a = seq[t];\n            for (int s = 0; s < N; s++) {\n                double pr = fw[t][s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                if (n == s) {\n                    fw[t + 1][s] += pr;\n                } else {\n                    double mv = pr * q;\n                    fw[t + 1][s] += pr - mv;\n                    fw[t + 1][n] += mv;\n                }\n            }\n            int coef = (t + 1 == L ? 201 : 1);\n            pref[t + 1] = pref[t] + coef * fw[t + 1][target];\n        }\n\n        bw[L].fill(0.0);\n        for (int t = L - 1; t >= 0; t--) {\n            int a = seq[t];\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                int n = to_eval[s][a];\n                double rs = isTar[s] * coef;\n                if (n == s) {\n                    bw[t][s] = rs + bw[t + 1][s];\n                } else {\n                    double rn = isTar[n] * coef;\n                    bw[t][s] = p * (rs + bw[t + 1][s]) + q * (rn + bw[t + 1][n]);\n                }\n            }\n        }\n\n        return pref[L];\n    }\n\n    inline void updateBest() {\n        if (curScore > bestScore) {\n            bestScore = curScore;\n            bestSeq = seq;\n        }\n    }\n\n    void addElite(const vector<uint8_t>& s, double sc) {\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestSeq = s;\n        }\n\n        for (auto &e : elite) {\n            if (e.second == s) {\n                if (sc > e.first) e.first = sc;\n                sort(elite.begin(), elite.end(),\n                     [](const auto& a, const auto& b) { return a.first > b.first; });\n                return;\n            }\n        }\n\n        elite.push_back({sc, s});\n        sort(elite.begin(), elite.end(),\n             [](const auto& a, const auto& b) { return a.first > b.first; });\n        if ((int)elite.size() > 8) elite.resize(8);\n    }\n\n    double evalSingle(int pos, int a) const {\n        double total = pref[pos];\n        int coef = (pos + 1 == L ? 201 : 1);\n\n        const auto &dist = fw[pos];\n        const auto &suf = bw[pos + 1];\n\n        for (int s = 0; s < N; s++) {\n            double pr = dist[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            double rs = isTar[s] * coef;\n            double v;\n            if (n == s) {\n                v = rs + suf[s];\n            } else {\n                double rn = isTar[n] * coef;\n                v = p * (rs + suf[s]) + q * (rn + suf[n]);\n            }\n            total += pr * v;\n        }\n        return total;\n    }\n\n    bool singleSweep(double deadline) {\n        bool improved = false;\n        array<int, L> ord;\n        iota(ord.begin(), ord.end(), 0);\n        for (int i = L - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        for (int ii = 0; ii < L; ii++) {\n            if ((ii & 15) == 0 && now() >= deadline) break;\n            int pos = ord[ii];\n\n            int curA = seq[pos];\n            int bestA = curA;\n            double bestV = curScore;\n\n            for (int a = 0; a < 4; a++) {\n                if (a == curA) continue;\n                double sc = evalSingle(pos, a);\n                if (sc > bestV + 1e-12) {\n                    bestV = sc;\n                    bestA = a;\n                }\n            }\n\n            if (bestA != curA) {\n                seq[pos] = (uint8_t)bestA;\n                curScore = recompute();\n                updateBest();\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    bool pairSweep(double deadline) {\n        bool improved = false;\n        array<int, L - 1> ord;\n        iota(ord.begin(), ord.end(), 0);\n        for (int i = L - 2; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        array<array<double, N>, 4> d1;\n        array<double, 4> base1{};\n        array<double, N> d2;\n\n        for (int ii = 0; ii < L - 1; ii++) {\n            if ((ii & 7) == 0 && now() >= deadline) break;\n            int pos = ord[ii];\n\n            int curA = seq[pos], curB = seq[pos + 1];\n            int bestA = curA, bestB = curB;\n            double bestV = curScore;\n\n            const auto &dist0 = fw[pos];\n            const auto &suf = bw[pos + 2];\n            int c1 = (pos + 1 == L ? 201 : 1);\n            int c2 = (pos + 2 == L ? 201 : 1);\n\n            for (int a = 0; a < 4; a++) {\n                stepDist(dist0, a, d1[a]);\n                base1[a] = pref[pos] + c1 * d1[a][target];\n            }\n\n            for (int a = 0; a < 4; a++) {\n                for (int b = 0; b < 4; b++) {\n                    stepDist(d1[a], b, d2);\n                    double sc = base1[a] + c2 * d2[target];\n                    double tail = 0.0;\n                    for (int s = 0; s < N; s++) tail += d2[s] * suf[s];\n                    sc += tail;\n\n                    if (sc > bestV + 1e-12) {\n                        bestV = sc;\n                        bestA = a;\n                        bestB = b;\n                    }\n                }\n            }\n\n            if (bestA != curA || bestB != curB) {\n                seq[pos] = (uint8_t)bestA;\n                seq[pos + 1] = (uint8_t)bestB;\n                curScore = recompute();\n                updateBest();\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    bool localSearch(double deadline, int rounds) {\n        bool any = false;\n        for (int r = 0; r < rounds && now() < deadline; r++) {\n            bool imp = false;\n            imp |= singleSweep(deadline);\n            if (now() < deadline) imp |= pairSweep(deadline);\n            any |= imp;\n            if (!imp) break;\n        }\n        return any;\n    }\n\n    void regrowSuffixFromCut(int cut, double epsRand) {\n        array<double, N> cur = fw[cut], nxt;\n        for (int t = cut; t < L; t++) {\n            int a = bestActionUB2(cur, t);\n            if (epsRand > 0.0 && rng.nextDouble() < epsRand) a = rng.nextInt(4);\n            seq[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n    }\n\n    void mutateCurrent() {\n        int type = rng.nextInt(100);\n\n        if (type < 45) {\n            int m = 1 + rng.nextInt(5);\n            for (int k = 0; k < m; k++) {\n                int pos = rng.nextInt(L);\n                seq[pos] = (uint8_t)rng.nextInt(4);\n            }\n        } else if (type < 75) {\n            int len = 6 + rng.nextInt(24);\n            len = min(len, L);\n            int l = rng.nextInt(L - len + 1);\n            for (int i = 0; i < len; i++) seq[l + i] = (uint8_t)rng.nextInt(4);\n        } else {\n            int cut = rng.nextInt(L - 2);\n            regrowSuffixFromCut(cut, 0.15);\n        }\n    }\n\n    bool beamPatch(int l, int w, int B, double deadline) {\n        if (now() >= deadline) return false;\n        int r = l + w - 1;\n\n        // Adaptive upper bound for this window + fixed suffix\n        vector<array<double, N>> Hh(w + 1);\n        Hh[w] = bw[r + 1];\n        for (int i = w - 1; i >= 0; i--) {\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                double rs = isTar[s] * coef;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double cand;\n                    if (n == s) {\n                        cand = rs + Hh[i + 1][s];\n                    } else {\n                        double rn = isTar[n] * coef;\n                        cand = p * (rs + Hh[i + 1][s]) + q * (rn + Hh[i + 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                Hh[i][s] = best;\n            }\n        }\n\n        struct Node {\n            array<float, N> dist;\n            double local;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double local;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> cur(1), nxt;\n        cur[0].dist.fill(0.0f);\n        for (int s = 0; s < N; s++) cur[0].dist[s] = (float)fw[l][s];\n        cur[0].local = 0.0;\n        cur[0].key = dotFloatDouble(cur[0].dist, Hh[0]);\n\n        vector<vector<pair<int, uint8_t>>> trace(w + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 8);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            return a.key > b.key;\n        };\n\n        for (int i = 0; i < w; i++) {\n            if ((i & 1) == 0 && now() >= deadline) return false;\n\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n\n            cand.clear();\n            for (int bi = 0; bi < (int)cur.size(); bi++) {\n                const auto &nd = cur[bi];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = bi;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    for (int s = 0; s < N; s++) {\n                        float pr = nd.dist[s];\n                        if (pr == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += pr;\n                            if (s == target) inc += (double)pr;\n                        } else {\n                            float ps = (float)(pr * p);\n                            float pn = (float)(pr * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                        }\n                    }\n\n                    ch.local = nd.local + coef * inc;\n                    ch.key = ch.local + dotFloatDouble(ch.dist, Hh[i + 1]);\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if (cand.empty()) return false;\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            nxt.resize(cand.size());\n            trace[i + 1].resize(cand.size());\n            for (int j = 0; j < (int)cand.size(); j++) {\n                nxt[j].dist = std::move(cand[j].dist);\n                nxt[j].local = cand[j].local;\n                nxt[j].key = cand[j].key;\n                trace[i + 1][j] = {cand[j].par, cand[j].act};\n            }\n            cur.swap(nxt);\n        }\n\n        const auto &tail = bw[r + 1];\n        int bestIdx = 0;\n        double bestVal = -1e100;\n        for (int i = 0; i < (int)cur.size(); i++) {\n            double val = cur[i].local + dotFloatDouble(cur[i].dist, tail);\n            if (val > bestVal) {\n                bestVal = val;\n                bestIdx = i;\n            }\n        }\n\n        vector<uint8_t> acts(w);\n        int idx = bestIdx;\n        for (int d = w; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            acts[d - 1] = act;\n            idx = par;\n        }\n\n        // Exact score of patched segment\n        array<double, N> dist = fw[l], nxtd;\n        double seg = 0.0;\n        for (int i = 0; i < w; i++) {\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n            stepDist(dist, acts[i], nxtd);\n            seg += coef * nxtd[target];\n            dist = nxtd;\n        }\n        double tailVal = dotDouble(dist, tail);\n        double newScore = pref[l] + seg + tailVal;\n\n        if (newScore > curScore + 1e-12) {\n            for (int i = 0; i < w; i++) seq[l + i] = acts[i];\n            curScore = recompute();\n            updateBest();\n            return true;\n        }\n        return false;\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}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int C = N * N;\nstatic constexpr int S = C * 4;\nusing Board = array<uint8_t, C>;\n\nint 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\nuint8_t SIDE[8] = {\n    (1u << 0) | (1u << 1), // 0\n    (1u << 0) | (1u << 3), // 1\n    (1u << 2) | (1u << 3), // 2\n    (1u << 1) | (1u << 2), // 3\n    0b1111,                // 4\n    0b1111,                // 5\n    (1u << 0) | (1u << 2), // 6\n    (1u << 1) | (1u << 3), // 7\n};\n\nint ROT1[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nint ROT[8][4];\nint NEI[C][4];\nint OPP[4] = {2, 3, 0, 1};\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463393265ull) {\n        x = seed ^ 0x9e3779b97f4a7c15ULL;\n        if (x == 0) x = 88172645463393265ull;\n        for (int i = 0; i < 8; i++) next_u64();\n    }\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t next_u32() { return static_cast<uint32_t>(next_u64()); }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Eval {\n    int l1 = 0, l2 = 0, l3 = 0, l4 = 0;\n    int loopCnt = 0;\n    int sumLoop = 0;\n    int matched = 0;\n    long long contest = 0;\n};\n\ninline bool better_best(const Eval& a, const Eval& b) {\n    if (a.contest != b.contest) return a.contest > b.contest;\n    if (a.l2 != b.l2) return a.l2 > b.l2;\n    if (a.l1 != b.l1) return a.l1 > b.l1;\n    if (a.l3 != b.l3) return a.l3 > b.l3;\n    if (a.sumLoop != b.sumLoop) return a.sumLoop > b.sumLoop;\n    return a.matched > b.matched;\n}\n\ninline double elite_key(const Eval& e) {\n    return (double)e.contest + 1.0 * e.l2 + 0.45 * e.l1 + 0.25 * e.l3 + 0.04 * e.sumLoop;\n}\n\n// p: 0 -> early, 1 -> late\ninline double objective(const Eval& e, double p) {\n    double q = p * p;\n    double v = 0.0;\n    v += q * (double)e.contest;\n    v += (1.0 - q) * (70.0 * e.l1 + 15.0 * e.sumLoop + 40.0 * e.loopCnt);\n    v += 8.0 * e.l2 + 2.0 * e.l3 + 0.10 * e.matched;\n    if (e.loopCnt < 2) v -= (2000.0 + 3000.0 * p);\n    return v;\n}\n\ninline double elapsed_sec(const chrono::steady_clock::time_point& st) {\n    return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n}\n\nstruct Evaluator {\n    int nxt[S];\n    int partner[S];\n    int visTag[S];\n    int visPos[S];\n    int stk[S];\n    uint8_t done[S];\n    uint8_t seenCanon[S];\n\n    Eval eval(const Board& board) {\n        uint8_t mask[C];\n        for (int c = 0; c < C; c++) mask[c] = SIDE[board[c]];\n\n        int matched = 0;\n        for (int i = 0; i < N; i++) {\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                int c = base + j;\n                uint8_t m = mask[c];\n                if (j + 1 < N) {\n                    if ((m & (1 << 2)) && (mask[c + 1] & (1 << 0))) matched++;\n                }\n                if (i + 1 < N) {\n                    if ((m & (1 << 3)) && (mask[c + N] & (1 << 1))) matched++;\n                }\n            }\n        }\n\n        for (int c = 0; c < C; c++) {\n            int t = board[c];\n            int c4 = c << 2;\n            for (int d = 0; d < 4; d++) {\n                int s = c4 | d;\n                int d2 = TO[t][d];\n                if (d2 < 0) {\n                    nxt[s] = -1;\n                    partner[s] = -1;\n                    continue;\n                }\n                partner[s] = c4 | d2;\n                int nc = NEI[c][d2];\n                if (nc < 0 || !(mask[nc] & (1 << OPP[d2]))) nxt[s] = -1;\n                else nxt[s] = (nc << 2) | OPP[d2];\n            }\n        }\n\n        memset(done, 0, sizeof(done));\n        memset(visTag, 0, sizeof(visTag));\n        memset(seenCanon, 0, sizeof(seenCanon));\n\n        int iter = 1;\n        int loopCnt = 0, sumLoop = 0;\n        int t0 = 0, t1 = 0, t2 = 0, t3 = 0;\n\n        auto push_len = [&](int len) {\n            if (len > t0) {\n                t3 = t2; t2 = t1; t1 = t0; t0 = len;\n            } else if (len > t1) {\n                t3 = t2; t2 = t1; t1 = len;\n            } else if (len > t2) {\n                t3 = t2; t2 = len;\n            } else if (len > t3) {\n                t3 = len;\n            }\n        };\n\n        for (int s0 = 0; s0 < S; s0++) {\n            if (done[s0]) continue;\n\n            int cur = s0;\n            int top = 0;\n            while (cur != -1 && !done[cur] && visTag[cur] != iter) {\n                visTag[cur] = iter;\n                visPos[cur] = top;\n                stk[top++] = cur;\n                cur = nxt[cur];\n            }\n\n            if (cur != -1 && !done[cur] && visTag[cur] == iter) {\n                int st = visPos[cur];\n                int len = top - st;\n\n                int can = INT_MAX;\n                for (int k = st; k < top; k++) {\n                    int v = stk[k];\n                    int p = partner[v];\n                    int m = (p >= 0 ? min(v, p) : v);\n                    can = min(can, m);\n                }\n\n                if (can >= 0 && can < S && !seenCanon[can]) {\n                    seenCanon[can] = 1;\n                    loopCnt++;\n                    sumLoop += len;\n                    push_len(len);\n                }\n            }\n\n            for (int k = 0; k < top; k++) done[stk[k]] = 1;\n            iter++;\n        }\n\n        Eval e;\n        e.l1 = t0; e.l2 = t1; e.l3 = t2; e.l4 = t3;\n        e.loopCnt = loopCnt;\n        e.sumLoop = sumLoop;\n        e.matched = matched;\n        e.contest = (loopCnt >= 2 ? 1LL * t0 * t1 : 0LL);\n        return e;\n    }\n};\n\ntemplate <class T>\ninline void shuffle_vec(vector<T>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n        swap(v[i], v[j]);\n    }\n}\n\ninline int cell_badness(int c, const Board& board) {\n    uint8_t m = SIDE[board[c]];\n    int bad = 0;\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) bad += 2;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 != b2) bad += 1;\n        }\n    }\n    return bad;\n}\n\ninline int local_potential(int c, uint8_t cand, const Board& board) {\n    int score = 0;\n    uint8_t m = SIDE[cand];\n\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) score -= 6;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 && b2) score += 4;\n            else if (b1 ^ b2) score -= 3;\n        }\n    }\n\n    for (int d = 0; d < 4; d++) {\n        int d2 = TO[cand][d];\n        if (d2 < 0) continue;\n        int nc = NEI[c][d2];\n        if (nc >= 0 && (SIDE[board[nc]] & (1 << OPP[d2]))) score += 1;\n        else score -= 1;\n    }\n\n    return score;\n}\n\ninline uint8_t random_other_state(\n    int c, uint8_t old,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng\n) {\n    if (possCnt[c] == 2) return (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n    int r = (int)(rng.next_u32() & 3);\n    uint8_t nw = poss[c][r];\n    if (nw == old) nw = poss[c][(r + 1) & 3];\n    return nw;\n}\n\nvoid fill_random(\n    Board& b,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng\n) {\n    for (int c = 0; c < C; c++) {\n        b[c] = poss[c][(possCnt[c] == 4) ? (rng.next_u32() & 3) : (rng.next_u32() & 1)];\n    }\n}\n\nvoid improve_connectivity(\n    Board& board,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng,\n    int passes\n) {\n    vector<int> ord(C);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int p = 0; p < passes; p++) {\n        shuffle_vec(ord, rng);\n        for (int idx = 0; idx < C; idx++) {\n            int c = ord[idx];\n            int bestScore = INT_MIN;\n            uint8_t bestState = board[c];\n\n            for (int k = 0; k < possCnt[c]; k++) {\n                uint8_t cand = poss[c][k];\n                int sc = local_potential(c, cand, board);\n                if (sc > bestScore || (sc == bestScore && (rng.next_u32() & 1))) {\n                    bestScore = sc;\n                    bestState = cand;\n                }\n            }\n            board[c] = bestState;\n        }\n    }\n}\n\nvoid quick_binary_descent(\n    Board& board,\n    Eval& curEval,\n    const vector<int>& twoCells,\n    const array<array<uint8_t, 4>, C>& poss,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int maxTry,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    if (twoCells.empty() || maxTry <= 0) return;\n    vector<int> ord = twoCells;\n    shuffle_vec(ord, rng);\n\n    double curObj = objective(curEval, p);\n    int tried = 0;\n\n    for (int idx = 0; idx < (int)ord.size() && tried < maxTry; idx++) {\n        if ((tried & 31) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        int c = ord[idx];\n        uint8_t old = board[c];\n        board[c] = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n\n        Eval ne = evaluator.eval(board);\n        double o = objective(ne, p);\n        tried++;\n\n        if (better_best(ne, curEval) || o >= curObj) {\n            curEval = ne;\n            curObj = o;\n        } else {\n            board[c] = old;\n        }\n    }\n}\n\nvoid pair_binary_descent(\n    Board& board,\n    Eval& curEval,\n    double& curObj,\n    const vector<pair<int,int>>& twoPairs,\n    const array<array<uint8_t, 4>, C>& poss,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int maxTry,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    if (twoPairs.empty() || maxTry <= 0) return;\n\n    for (int t = 0; t < maxTry; t++) {\n        if ((t & 15) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        auto [c1, c2] = twoPairs[rng.next_u32() % twoPairs.size()];\n        uint8_t o1 = board[c1], o2 = board[c2];\n\n        board[c1] = (o1 == poss[c1][0] ? poss[c1][1] : poss[c1][0]);\n        board[c2] = (o2 == poss[c2][0] ? poss[c2][1] : poss[c2][0]);\n\n        Eval ne = evaluator.eval(board);\n        double o = objective(ne, p);\n\n        if (better_best(ne, curEval) || o >= curObj) {\n            curEval = ne;\n            curObj = o;\n        } else {\n            board[c1] = o1;\n            board[c2] = o2;\n        }\n    }\n}\n\nvoid subset_descent(\n    Board& board,\n    Eval& curEval,\n    double& curObj,\n    const vector<int>& cells,\n    int maxCells,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    if (cells.empty() || maxCells <= 0) return;\n    vector<int> ord = cells;\n    shuffle_vec(ord, rng);\n    int lim = min(maxCells, (int)ord.size());\n\n    for (int ii = 0; ii < lim; ii++) {\n        if ((ii & 15) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        int c = ord[ii];\n        uint8_t old = board[c];\n\n        uint8_t bestState = old;\n        Eval bestEval = curEval;\n        double bestObj = curObj;\n\n        for (int k = 0; k < possCnt[c]; k++) {\n            uint8_t cand = poss[c][k];\n            if (cand == old) continue;\n\n            board[c] = cand;\n            Eval ne = evaluator.eval(board);\n            double o = objective(ne, p);\n\n            if (better_best(ne, bestEval) || o > bestObj + 1e-12) {\n                bestObj = o;\n                bestState = cand;\n                bestEval = ne;\n            }\n        }\n\n        board[c] = bestState;\n        if (bestState != old) {\n            curEval = bestEval;\n            curObj = bestObj;\n        }\n    }\n}\n\nstruct Elite {\n    Board st;\n    Eval ev;\n    double key = -1e100;\n};\n\ninline int hamming_dist(const Board& a, const Board& b) {\n    int d = 0;\n    for (int i = 0; i < C; i++) d += (a[i] != b[i]);\n    return d;\n}\n\nvoid add_elite(vector<Elite>& elites, const Board& st, const Eval& ev) {\n    const int MAX_E = 8;\n    const int MIN_DIST = 18;\n    double key = elite_key(ev);\n\n    for (auto& e : elites) {\n        if (hamming_dist(st, e.st) < MIN_DIST) {\n            if (better_best(ev, e.ev) || (ev.contest == e.ev.contest && key > e.key)) {\n                e.st = st;\n                e.ev = ev;\n                e.key = key;\n            }\n            return;\n        }\n    }\n\n    if ((int)elites.size() < MAX_E) {\n        elites.push_back(Elite{st, ev, key});\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < MAX_E; i++) if (elites[i].key < elites[worst].key) worst = i;\n    if (key > elites[worst].key) elites[worst] = Elite{st, ev, key};\n}\n\nint pick_elite_tournament(const vector<Elite>& elites, RNG& rng) {\n    int n = (int)elites.size();\n    int best = (int)(rng.next_u32() % n);\n    for (int t = 0; t < 3; t++) {\n        int x = (int)(rng.next_u32() % n);\n        if (elites[x].key > elites[best].key) best = x;\n    }\n    return best;\n}\n\nint pick_bad_cell(const Board& board, RNG& rng, int samples) {\n    int best = (int)(rng.next_u32() % C), bestB = -1;\n    for (int k = 0; k < samples; k++) {\n        int c = (int)(rng.next_u32() % C);\n        int b = cell_badness(c, board);\n        if (b > bestB) {\n            bestB = b;\n            best = c;\n        }\n    }\n    return best;\n}\n\nint pick_bad_two(const Board& board, const vector<int>& twoCells, RNG& rng, int samples) {\n    if (twoCells.empty()) return (int)(rng.next_u32() % C);\n    int best = twoCells[rng.next_u32() % twoCells.size()], bestB = -1;\n    for (int k = 0; k < samples; k++) {\n        int c = twoCells[rng.next_u32() % twoCells.size()];\n        int b = cell_badness(c, board);\n        if (b > bestB) {\n            bestB = b;\n            best = c;\n        }\n    }\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    // Precompute rotations\n    for (int t = 0; t < 8; t++) {\n        ROT[t][0] = t;\n        for (int k = 1; k < 4; k++) ROT[t][k] = ROT1[ROT[t][k - 1]];\n    }\n\n    // Precompute neighbors\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = i * N + j;\n            NEI[c][0] = (j > 0 ? c - 1 : -1);\n            NEI[c][1] = (i > 0 ? c - N : -1);\n            NEI[c][2] = (j + 1 < N ? c + 1 : -1);\n            NEI[c][3] = (i + 1 < N ? c + N : -1);\n        }\n    }\n\n    Board orig{};\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) orig[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    uint64_t seed = 1469598103934665603ULL;\n    for (int c = 0; c < C; c++) {\n        seed ^= (uint64_t)(orig[c] + 1);\n        seed *= 1099511628211ULL;\n    }\n    seed ^= 0x9e3779b97f4a7c15ULL;\n    RNG rng(seed);\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95;\n    const double INIT_END = 0.40;\n    const double SA_END = TL - 0.14;\n\n    array<array<uint8_t, 4>, C> poss{};\n    array<uint8_t, C> possCnt{};\n    vector<int> allCells(C);\n    iota(allCells.begin(), allCells.end(), 0);\n    vector<int> twoCells;\n    array<uint8_t, C> isTwo{};\n    vector<pair<int,int>> twoPairs;\n\n    for (int c = 0; c < C; c++) {\n        int t = orig[c];\n        if (t <= 3) {\n            possCnt[c] = 4;\n            for (int k = 0; k < 4; k++) poss[c][k] = (uint8_t)ROT[t][k];\n        } else if (t <= 5) {\n            possCnt[c] = 2;\n            poss[c][0] = 4;\n            poss[c][1] = 5;\n            twoCells.push_back(c);\n            isTwo[c] = 1;\n        } else {\n            possCnt[c] = 2;\n            poss[c][0] = 6;\n            poss[c][1] = 7;\n            twoCells.push_back(c);\n            isTwo[c] = 1;\n        }\n    }\n\n    for (int c = 0; c < C; c++) {\n        if (!isTwo[c]) continue;\n        int r = NEI[c][2], d = NEI[c][3];\n        if (r >= 0 && isTwo[r]) twoPairs.emplace_back(c, r);\n        if (d >= 0 && isTwo[d]) twoPairs.emplace_back(c, d);\n    }\n\n    Evaluator evaluator;\n\n    Board bestState = orig;\n    Eval bestEval = evaluator.eval(bestState);\n\n    vector<Elite> elites;\n    add_elite(elites, bestState, bestEval);\n\n    // ---------- Initialization ----------\n    int trial = 0;\n    while (elapsed_sec(start) < INIT_END && trial < 18) {\n        Board cand{};\n\n        if (trial == 0) {\n            cand = orig;\n        } else if (trial == 1) {\n            fill_random(cand, poss, possCnt, rng);\n        } else if (trial >= 2 && trial <= 5) {\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    int c = i * N + j;\n                    if (possCnt[c] == 2) {\n                        if (trial == 2) cand[c] = poss[c][0];\n                        else if (trial == 3) cand[c] = poss[c][1];\n                        else if (trial == 4) cand[c] = ((i + j) & 1) ? poss[c][0] : poss[c][1];\n                        else cand[c] = (i & 1) ? poss[c][0] : poss[c][1];\n                    } else {\n                        int t = orig[c];\n                        if (trial <= 3) cand[c] = (uint8_t)t;\n                        else if (trial == 4) cand[c] = (uint8_t)ROT[t][(i + j) & 3];\n                        else cand[c] = (uint8_t)ROT[t][(i + 2 * j) & 3];\n                    }\n                }\n            }\n        } else {\n            int mode = trial % 4;\n            if (mode == 0 && !elites.empty()) {\n                cand = elites[pick_elite_tournament(elites, rng)].st;\n                int flips = 12 + (int)(rng.next_u32() % 36);\n                for (int f = 0; f < flips; f++) {\n                    int c = (int)(rng.next_u32() % C);\n                    cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                }\n            } else if (mode == 1 && elites.size() >= 2) {\n                int a = pick_elite_tournament(elites, rng);\n                int b = pick_elite_tournament(elites, rng);\n                while (b == a) b = pick_elite_tournament(elites, rng);\n                for (int c = 0; c < C; c++) {\n                    cand[c] = ((rng.next_u32() & 1) ? elites[a].st[c] : elites[b].st[c]);\n                }\n                int flips = 10 + (int)(rng.next_u32() % 30);\n                for (int f = 0; f < flips; f++) {\n                    int c = (int)(rng.next_u32() % C);\n                    cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                }\n            } else {\n                fill_random(cand, poss, possCnt, rng);\n            }\n        }\n\n        int passes = (trial == 0 ? 8 : (trial < 6 ? 5 : 3));\n        improve_connectivity(cand, poss, possCnt, rng, passes);\n\n        Eval e = evaluator.eval(cand);\n\n        if (elapsed_sec(start) < INIT_END - 0.01) {\n            double p0 = 0.20;\n            int bt = (trial < 8 ? 130 : 70);\n            quick_binary_descent(cand, e, twoCells, poss, evaluator, rng, p0, bt, start, INIT_END);\n\n            double obj = objective(e, p0);\n            int desc = (trial < 5 ? 80 : 40);\n            subset_descent(cand, e, obj, allCells, desc, poss, possCnt, evaluator, rng, p0, start, INIT_END);\n        }\n\n        if (better_best(e, bestEval)) {\n            bestEval = e;\n            bestState = cand;\n        }\n        add_elite(elites, cand, e);\n        trial++;\n    }\n\n    int si = 0;\n    for (int i = 1; i < (int)elites.size(); i++) {\n        if (elites[i].key > elites[si].key) si = i;\n    }\n\n    Board curState = elites[si].st;\n    Eval curEval = elites[si].ev;\n    if (better_best(curEval, bestEval)) {\n        bestEval = curEval;\n        bestState = curState;\n    }\n\n    auto estimate_T0 = [&](const Board& st, const Eval& ev) {\n        double base = objective(ev, 0.0);\n        Board tmp = st;\n        double sum = 0.0;\n        int cnt = 0;\n        for (int t = 0; t < 40; t++) {\n            int c = (int)(rng.next_u32() % C);\n            uint8_t old = tmp[c];\n            tmp[c] = random_other_state(c, old, poss, possCnt, rng);\n            Eval ne = evaluator.eval(tmp);\n            sum += fabs(objective(ne, 0.0) - base);\n            tmp[c] = old;\n            cnt++;\n        }\n        double avg = (cnt ? sum / cnt : 80.0);\n        double T0 = avg * 3.0;\n        if (T0 < 40.0) T0 = 40.0;\n        if (T0 > 2500.0) T0 = 2500.0;\n        return T0;\n    };\n\n    double T0 = estimate_T0(curState, curEval);\n    double T1 = max(0.03, T0 * 0.0007);\n\n    // ---------- SA ----------\n    long long iter = 0;\n    double lastBestSec = elapsed_sec(start);\n    double lastRestartSec = lastBestSec;\n    double lastIntenseSec = lastBestSec;\n    bool forcedDiversify = false;\n\n    double progress = min(1.0, elapsed_sec(start) / TL);\n    double temp = T0 * pow(T1 / T0, progress);\n    double curObj = objective(curEval, progress);\n\n    while (true) {\n        if ((iter & 127LL) == 0) {\n            double now = elapsed_sec(start);\n            if (now >= SA_END) break;\n\n            progress = now / TL;\n            if (progress > 1.0) progress = 1.0;\n            temp = T0 * pow(T1 / T0, progress);\n            curObj = objective(curEval, progress);\n\n            // Stagnation restart\n            if (now - lastBestSec > 0.20 && now - lastRestartSec > 0.07 && !elites.empty()) {\n                Board cand{};\n                bool doCross = (elites.size() >= 2 && (rng.next_u32() % 100) < 35);\n\n                if (doCross) {\n                    int a = pick_elite_tournament(elites, rng);\n                    int b = pick_elite_tournament(elites, rng);\n                    while (b == a) b = pick_elite_tournament(elites, rng);\n                    for (int c = 0; c < C; c++) {\n                        cand[c] = ((rng.next_u32() & 1) ? elites[a].st[c] : elites[b].st[c]);\n                    }\n                } else {\n                    cand = elites[pick_elite_tournament(elites, rng)].st;\n                }\n\n                int maxFlip = 12 + (int)((1.0 - progress) * 38.0);\n                int flips = 6 + (int)(rng.next_u32() % (uint32_t)(maxFlip + 1));\n                for (int f = 0; f < flips; f++) {\n                    int c = ((rng.next_u32() % 100) < 60) ? pick_bad_cell(cand, rng, 4)\n                                                          : (int)(rng.next_u32() % C);\n                    cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                }\n\n                if (progress < 0.75 && (rng.next_u32() % 100) < 70) {\n                    improve_connectivity(cand, poss, possCnt, rng, 1);\n                }\n\n                curState = cand;\n                curEval = evaluator.eval(curState);\n                curObj = objective(curEval, progress);\n                add_elite(elites, curState, curEval);\n\n                if (better_best(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    add_elite(elites, bestState, bestEval);\n                    lastBestSec = now;\n                }\n                lastRestartSec = now;\n            }\n\n            // Forced diversification for weak instances\n            if (!forcedDiversify && progress > 0.58 && bestEval.contest < 4800 && now < SA_END - 0.12) {\n                double dl = min(SA_END, now + 0.045);\n                while (elapsed_sec(start) < dl) {\n                    Board cand{};\n                    if (elites.size() >= 2 && (rng.next_u32() % 100) < 50) {\n                        int a = pick_elite_tournament(elites, rng);\n                        int b = pick_elite_tournament(elites, rng);\n                        while (b == a) b = pick_elite_tournament(elites, rng);\n                        for (int c = 0; c < C; c++) {\n                            cand[c] = ((rng.next_u32() & 1) ? elites[a].st[c] : elites[b].st[c]);\n                        }\n                    } else if (!elites.empty()) {\n                        cand = elites[pick_elite_tournament(elites, rng)].st;\n                    } else {\n                        fill_random(cand, poss, possCnt, rng);\n                    }\n\n                    int flips = 28 + (int)(rng.next_u32() % 68);\n                    for (int f = 0; f < flips; f++) {\n                        int c = (int)(rng.next_u32() % C);\n                        cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                    }\n\n                    improve_connectivity(cand, poss, possCnt, rng, 1);\n                    Eval e = evaluator.eval(cand);\n\n                    double pnow = progress;\n                    if (elapsed_sec(start) < dl - 0.004) {\n                        quick_binary_descent(cand, e, twoCells, poss, evaluator, rng, pnow, 50, start, dl);\n                    }\n                    double o = objective(e, pnow);\n\n                    if (o > curObj) {\n                        curState = cand;\n                        curEval = e;\n                        curObj = o;\n                    }\n                    if (better_best(e, bestEval)) {\n                        bestEval = e;\n                        bestState = cand;\n                        lastBestSec = elapsed_sec(start);\n                    }\n                    add_elite(elites, cand, e);\n                }\n                forcedDiversify = true;\n            }\n\n            // Periodic intensification\n            if (now - lastIntenseSec > 0.11 && progress < 0.93 && now < SA_END - 0.015) {\n                double dl = min(SA_END, now + 0.010);\n                double pnow = max(0.20, progress);\n\n                quick_binary_descent(curState, curEval, twoCells, poss, evaluator, rng, pnow, 60, start, dl);\n                curObj = objective(curEval, progress);\n\n                pair_binary_descent(curState, curEval, curObj, twoPairs, poss, evaluator, rng, pnow, 35, start, dl);\n\n                subset_descent(curState, curEval, curObj, allCells, 35, poss, possCnt, evaluator, rng, pnow, start, dl);\n\n                if (better_best(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    add_elite(elites, bestState, bestEval);\n                    lastBestSec = elapsed_sec(start);\n                }\n                add_elite(elites, curState, curEval);\n                lastIntenseSec = now;\n            }\n\n            // Late stabilization\n            if (progress > 0.90 && (iter & 2047LL) == 0) {\n                curState = bestState;\n                curEval = bestEval;\n                curObj = objective(curEval, progress);\n            }\n        }\n\n        int changedIdx[16];\n        uint8_t oldVal[16];\n        int changed = 0;\n\n        int mt = (int)(rng.next_u32() % 100);\n        int th1, th2, th3, th4;\n        if (progress < 0.55) {\n            th1 = 50; th2 = 72; th3 = 87; th4 = 96;\n        } else if (progress < 0.82) {\n            th1 = 58; th2 = 80; th3 = 92; th4 = 98;\n        } else {\n            th1 = 66; th2 = 89; th3 = 97; th4 = 99;\n        }\n\n        if (mt < th1) {\n            int c = ((rng.next_u32() % 100) < 72) ? pick_bad_cell(curState, rng, 6)\n                                                  : (int)(rng.next_u32() % C);\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changed = 1;\n\n            if (possCnt[c] == 4 && (rng.next_u32() & 1)) {\n                uint8_t old = curState[c];\n                int bestSc = INT_MIN;\n                uint8_t bestSt = old;\n                for (int k = 0; k < 4; k++) {\n                    uint8_t cand = poss[c][k];\n                    int sc = local_potential(c, cand, curState);\n                    if (sc > bestSc || (sc == bestSc && (rng.next_u32() & 1))) {\n                        bestSc = sc;\n                        bestSt = cand;\n                    }\n                }\n                if (bestSt == old) bestSt = random_other_state(c, old, poss, possCnt, rng);\n                curState[c] = bestSt;\n            } else {\n                curState[c] = random_other_state(c, curState[c], poss, possCnt, rng);\n            }\n        } else if (mt < th2 && !twoCells.empty()) {\n            int c = pick_bad_two(curState, twoCells, rng, 6);\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changed = 1;\n            curState[c] = (curState[c] == poss[c][0] ? poss[c][1] : poss[c][0]);\n        } else if (mt < th3) {\n            int c1 = pick_bad_cell(curState, rng, 5);\n            int c2 = -1;\n            int d0 = (int)(rng.next_u32() & 3);\n            for (int tt = 0; tt < 4; tt++) {\n                int d = (d0 + tt) & 3;\n                if (NEI[c1][d] >= 0) {\n                    c2 = NEI[c1][d];\n                    break;\n                }\n            }\n            if (c2 < 0) c2 = (int)(rng.next_u32() % C);\n            if (c2 == c1) c2 = (c1 + 1) % C;\n\n            changedIdx[0] = c1; oldVal[0] = curState[c1];\n            changedIdx[1] = c2; oldVal[1] = curState[c2];\n            changed = 2;\n\n            curState[c1] = random_other_state(c1, curState[c1], poss, possCnt, rng);\n            curState[c2] = random_other_state(c2, curState[c2], poss, possCnt, rng);\n        } else if (mt < th4) {\n            int i = (int)(rng.next_u32() % (N - 1));\n            int j = (int)(rng.next_u32() % (N - 1));\n            int c0 = i * N + j;\n            int cells[4] = {c0, c0 + 1, c0 + N, c0 + N + 1};\n            int delta = (rng.next_u32() & 1) ? 1 : 3;\n\n            changed = 4;\n            for (int k = 0; k < 4; k++) {\n                int c = cells[k];\n                changedIdx[k] = c;\n                oldVal[k] = curState[c];\n                curState[c] = (uint8_t)ROT[curState[c]][delta];\n            }\n        } else {\n            int i = (int)(rng.next_u32() % (N - 2));\n            int j = (int)(rng.next_u32() % (N - 2));\n            changed = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    int c = (i + di) * N + (j + dj);\n                    changedIdx[changed] = c;\n                    oldVal[changed] = curState[c];\n                    changed++;\n                    curState[c] = poss[c][(possCnt[c] == 4) ? (rng.next_u32() & 3) : (rng.next_u32() & 1)];\n                }\n            }\n        }\n\n        Eval ne = evaluator.eval(curState);\n        double newObj = objective(ne, progress);\n\n        bool accept = false;\n        if (better_best(ne, curEval)) {\n            accept = true;\n        } else {\n            double diff = newObj - curObj;\n            if (diff >= 0.0) accept = true;\n            else if (rng.next_double() < exp(diff / max(1e-9, temp))) accept = true;\n        }\n\n        if (accept) {\n            curEval = ne;\n            curObj = newObj;\n\n            if (better_best(curEval, bestEval)) {\n                bestEval = curEval;\n                bestState = curState;\n                add_elite(elites, bestState, bestEval);\n                lastBestSec = elapsed_sec(start);\n            } else if ((iter & 2047LL) == 0 && (rng.next_u32() % 100) < 15) {\n                add_elite(elites, curState, curEval);\n            }\n        } else {\n            for (int k = 0; k < changed; k++) curState[changedIdx[k]] = oldVal[k];\n        }\n\n        iter++;\n    }\n\n    // ---------- Final polish ----------\n    Board finState = bestState;\n    Eval finEval = bestEval;\n    const double pfin = 0.999;\n    double finObj = objective(finEval, pfin);\n    double deadline = TL - 0.002;\n\n    if (elapsed_sec(start) < deadline) {\n        quick_binary_descent(finState, finEval, twoCells, poss, evaluator, rng, pfin, 240, start, deadline);\n        finObj = objective(finEval, pfin);\n        pair_binary_descent(finState, finEval, finObj, twoPairs, poss, evaluator, rng, pfin, 220, start, deadline);\n    }\n\n    // Deterministic binary single-flip passes\n    if (elapsed_sec(start) < deadline && !twoCells.empty()) {\n        vector<int> ord2 = twoCells;\n        for (int pass = 0; pass < 3; pass++) {\n            if (elapsed_sec(start) >= deadline) break;\n            shuffle_vec(ord2, rng);\n            bool improved = false;\n\n            for (int idx = 0; idx < (int)ord2.size(); idx++) {\n                if ((idx & 31) == 0 && elapsed_sec(start) >= deadline) break;\n                int c = ord2[idx];\n                uint8_t old = finState[c];\n                finState[c] = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n\n                Eval ne = evaluator.eval(finState);\n                double o = objective(ne, pfin);\n\n                if (better_best(ne, finEval) || (!better_best(finEval, ne) && o > finObj + 1e-12)) {\n                    finEval = ne;\n                    finObj = o;\n                    improved = true;\n                } else {\n                    finState[c] = old;\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    // Deterministic binary pair-flip passes\n    if (elapsed_sec(start) < deadline && !twoPairs.empty()) {\n        vector<int> ordp(twoPairs.size());\n        iota(ordp.begin(), ordp.end(), 0);\n\n        for (int pass = 0; pass < 2; pass++) {\n            if (elapsed_sec(start) >= deadline) break;\n            shuffle_vec(ordp, rng);\n            bool improved = false;\n\n            for (int ii = 0; ii < (int)ordp.size(); ii++) {\n                if ((ii & 15) == 0 && elapsed_sec(start) >= deadline) break;\n                auto [c1, c2] = twoPairs[ordp[ii]];\n                uint8_t o1 = finState[c1], o2 = finState[c2];\n\n                finState[c1] = (o1 == poss[c1][0] ? poss[c1][1] : poss[c1][0]);\n                finState[c2] = (o2 == poss[c2][0] ? poss[c2][1] : poss[c2][0]);\n\n                Eval ne = evaluator.eval(finState);\n                double o = objective(ne, pfin);\n\n                if (better_best(ne, finEval) || (!better_best(finEval, ne) && o > finObj + 1e-12)) {\n                    finEval = ne;\n                    finObj = o;\n                    improved = true;\n                } else {\n                    finState[c1] = o1;\n                    finState[c2] = o2;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    // Full local orientation descent\n    if (elapsed_sec(start) < deadline) {\n        vector<int> ord(C);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < 2; pass++) {\n            if (elapsed_sec(start) >= deadline) break;\n            shuffle_vec(ord, rng);\n            bool improved = false;\n\n            int lim = C;\n            double rem = deadline - elapsed_sec(start);\n            if (rem < 0.04) lim = 420;\n            if (rem < 0.02) lim = 180;\n\n            for (int ii = 0; ii < lim; ii++) {\n                if ((ii & 15) == 0 && elapsed_sec(start) >= deadline) break;\n\n                int c = ord[ii];\n                uint8_t old = finState[c];\n\n                uint8_t bestS = old;\n                Eval bestE = finEval;\n                double bestO = finObj;\n\n                for (int k = 0; k < possCnt[c]; k++) {\n                    uint8_t cand = poss[c][k];\n                    if (cand == old) continue;\n\n                    finState[c] = cand;\n                    Eval ne = evaluator.eval(finState);\n                    double o = objective(ne, pfin);\n\n                    if (better_best(ne, bestE) || (!better_best(bestE, ne) && o > bestO + 1e-12)) {\n                        bestS = cand;\n                        bestE = ne;\n                        bestO = o;\n                    }\n                }\n\n                finState[c] = bestS;\n                if (bestS != old) {\n                    finEval = bestE;\n                    finObj = bestO;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    if (elapsed_sec(start) < deadline) {\n        quick_binary_descent(finState, finEval, twoCells, poss, evaluator, rng, pfin, 120, start, deadline);\n        finObj = objective(finEval, pfin);\n    }\n\n    if (better_best(finEval, bestEval) ||\n        (!better_best(bestEval, finEval) && finObj > objective(bestEval, pfin))) {\n        bestEval = finEval;\n        bestState = finState;\n    }\n\n    // Output rotation counts\n    string ans(C, '0');\n    for (int c = 0; c < C; c++) {\n        int o = orig[c], f = bestState[c];\n        int rot = 0;\n        for (; rot < 4; rot++) if (ROT[o][rot] == f) break;\n        if (rot == 4) rot = 0;\n        ans[c] = char('0' + rot);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N_global, T_global, NN_global, FULLV;\nint NEI[100][4];\nuint64_t zobrist[100][16];\nbool CONN[2][16][16]; // 0: horizontal right-left, 1: vertical down-up\n\nconst int OPP[4] = {1, 0, 3, 2};\nconst char OPCH[4] = {'U', 'D', 'L', 'R'};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n};\n\nstatic inline uint64_t splitmix64_seed(uint64_t &x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\nstatic inline uint64_t splitmix64_stat(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\nstruct FastHash {\n    size_t operator()(uint64_t x) const noexcept {\n        static const uint64_t FIXED_RANDOM =\n            (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n        return (size_t)splitmix64_stat(x + FIXED_RANDOM);\n    }\n};\n\nusing Board = array<uint8_t, 100>;\n\nstruct AdjEdge {\n    uint8_t u, v;\n    uint8_t typ; // 0 horizontal, 1 vertical\n};\nvector<AdjEdge> g_edges;\n\ninline int uf_find(int x, int parent[]) {\n    while (parent[x] != x) {\n        parent[x] = parent[parent[x]];\n        x = parent[x];\n    }\n    return x;\n}\n\nstruct EvalInfo {\n    int S = 0;         // largest tree component\n    int cmax = 0;      // largest connected component\n    int cmaxEx = 0;    // cycle excess of largest connected component\n    int totalEx = 0;   // sum of cycle excesses\n    int totalEdges = 0;\n    int compCnt = 0;\n\n    int pot4 = 0;      // max(v - 4*ex)\n    int pot7 = 0;      // max(v - 7*ex)\n    int near1 = 0;     // max v with ex <= 1\n    int treeSum = 0;   // sum of v for ex==0 components\n};\n\ninline EvalInfo evaluate_state(const Board &b) {\n    int parent[100];\n    int sz[100];\n    int ed[100];\n\n    for (int i = 0; i < NN_global; i++) {\n        if (b[i] != 0) {\n            parent[i] = i;\n            sz[i] = 1;\n            ed[i] = 0;\n        } else {\n            parent[i] = -1;\n        }\n    }\n\n    for (const auto &e : g_edges) {\n        uint8_t a = b[e.u];\n        uint8_t c = b[e.v];\n        if (a != 0 && c != 0 && CONN[e.typ][a][c]) {\n            int ra = uf_find((int)e.u, parent);\n            int rb = uf_find((int)e.v, parent);\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\n    EvalInfo out;\n    bool first = true;\n    for (int i = 0; i < NN_global; i++) {\n        if (parent[i] == i) {\n            out.compCnt++;\n            int v = sz[i];\n            int e = ed[i];\n            int ex = e - (v - 1);\n\n            if (ex == 0) {\n                out.S = max(out.S, v);\n                out.treeSum += v;\n            }\n            if (ex <= 1) out.near1 = max(out.near1, v);\n\n            out.pot4 = max(out.pot4, v - 4 * ex);\n            out.pot7 = max(out.pot7, v - 7 * ex);\n\n            out.totalEx += ex;\n            out.totalEdges += e;\n\n            if (first || v > out.cmax || (v == out.cmax && ex < out.cmaxEx)) {\n                out.cmax = v;\n                out.cmaxEx = ex;\n                first = false;\n            }\n        }\n    }\n\n    if (out.S < 1) out.S = 1;\n    if (out.cmax < 1) out.cmax = 1;\n    if (out.pot4 < 0) out.pot4 = 0;\n    if (out.pot7 < 0) out.pot7 = 0;\n    return out;\n}\n\ninline long long calc_key(const EvalInfo &e, int depth, int mode) {\n    int r = (T_global > 0 ? depth * 1000 / T_global : 1000);\n    int edgeGap = abs(e.totalEdges - (FULLV - 1));\n    int compGap = max(0, e.compCnt - 1);\n\n    if (mode == 0) { // connect-first\n        if (r < 300) {\n            return 4200000LL * e.cmax\n                 + 2700000LL * e.pot4\n                 + 1000000LL * e.S\n                 +  500000LL * e.near1\n                 +  120000LL * e.treeSum\n                 - 1100000LL * e.cmaxEx\n                 -   50000LL * e.totalEx\n                 -  150000LL * compGap\n                 -   12000LL * edgeGap;\n        } else if (r < 700) {\n            return 3000000LL * e.cmax\n                 + 3200000LL * e.pot4\n                 + 2400000LL * e.S\n                 +  900000LL * e.near1\n                 +  220000LL * e.treeSum\n                 - 1700000LL * e.cmaxEx\n                 -   75000LL * e.totalEx\n                 -  220000LL * compGap\n                 -   18000LL * edgeGap;\n        } else {\n            return 5600000LL * e.S\n                 + 2600000LL * e.pot4\n                 + 1300000LL * e.near1\n                 +  900000LL * e.cmax\n                 +  320000LL * e.treeSum\n                 - 2300000LL * e.cmaxEx\n                 -  110000LL * e.totalEx\n                 -  260000LL * compGap\n                 -   24000LL * edgeGap;\n        }\n    } else if (mode == 1) { // balanced\n        if (r < 250) {\n            return 3800000LL * e.cmax\n                 + 2500000LL * e.pot4\n                 + 1700000LL * e.S\n                 +  650000LL * e.near1\n                 +  120000LL * e.treeSum\n                 - 1300000LL * e.cmaxEx\n                 -   55000LL * e.totalEx\n                 -  180000LL * compGap\n                 -   15000LL * edgeGap;\n        } else if (r < 700) {\n            return 4200000LL * e.pot4\n                 + 4000000LL * e.S\n                 + 1700000LL * e.cmax\n                 + 1200000LL * e.near1\n                 +  320000LL * e.treeSum\n                 - 2000000LL * e.cmaxEx\n                 -   90000LL * e.totalEx\n                 -  240000LL * compGap\n                 -   22000LL * edgeGap;\n        } else {\n            return 7000000LL * e.S\n                 + 2100000LL * e.near1\n                 + 1900000LL * e.pot7\n                 +  750000LL * e.cmax\n                 +  420000LL * e.treeSum\n                 - 2500000LL * e.cmaxEx\n                 -  130000LL * e.totalEx\n                 -  280000LL * compGap\n                 -   26000LL * edgeGap;\n        }\n    } else { // mode 2: cycle-break / endgame\n        if (r < 500) {\n            return 7700000LL * e.S\n                 + 3400000LL * e.near1\n                 + 2500000LL * e.pot7\n                 +  900000LL * e.treeSum\n                 +  500000LL * e.cmax\n                 - 2900000LL * e.cmaxEx\n                 -  170000LL * e.totalEx\n                 -  260000LL * compGap\n                 -   21000LL * edgeGap;\n        } else {\n            return 9500000LL * e.S\n                 + 4000000LL * e.near1\n                 + 3000000LL * e.pot7\n                 + 1200000LL * e.treeSum\n                 +  420000LL * e.cmax\n                 - 3400000LL * e.cmaxEx\n                 -  220000LL * e.totalEx\n                 -  320000LL * compGap\n                 -   28000LL * edgeGap;\n        }\n    }\n}\n\ninline long long calc_div_score(const EvalInfo &e) {\n    return 3700000LL * e.pot4\n         + 3000000LL * e.near1\n         + 2700000LL * e.S\n         +  800000LL * e.cmax\n         - 1300000LL * e.cmaxEx\n         -   80000LL * e.totalEx\n         -  120000LL * max(0, e.compCnt - 1);\n}\n\ninline uint64_t compute_hash(const Board &b) {\n    uint64_t h = 0;\n    for (int i = 0; i < NN_global; i++) h ^= zobrist[i][b[i]];\n    return h;\n}\ninline uint64_t state_key(uint64_t rawHash, uint8_t lastDir) {\n    return rawHash ^ (0x9e3779b97f4a7c15ULL * (uint64_t)(lastDir + 1));\n}\n\nstruct SearchResult {\n    string path;\n    Board board{};\n    int blank = 0;\n    int lastDir = 4;\n    int S = 0;\n    int cmax = 0;\n    int cEx = 0;\n    long long key = LLONG_MIN;\n    long long divScore = LLONG_MIN;\n    uint64_t hk = 0;\n};\n\ninline void fill_result_metrics(SearchResult &r, const EvalInfo &e, int mode) {\n    r.S = e.S;\n    r.cmax = e.cmax;\n    r.cEx = e.cmaxEx;\n    r.key = calc_key(e, (int)r.path.size(), mode);\n    r.divScore = calc_div_score(e);\n    uint64_t h = compute_hash(r.board);\n    r.hk = state_key(h, (uint8_t)r.lastDir);\n}\n\ninline bool better_result(const SearchResult &a, const SearchResult &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    if (a.cmax != b.cmax) return a.cmax > b.cmax;\n    if (a.cEx != b.cEx) return a.cEx < b.cEx;\n    if (a.divScore != b.divScore) return a.divScore > b.divScore;\n    return a.path.size() < b.path.size();\n}\ninline bool better_div(const SearchResult &a, const SearchResult &b) {\n    if (a.divScore != b.divScore) return a.divScore > b.divScore;\n    if (a.S != b.S) return a.S > b.S;\n    if (a.cmax != b.cmax) return a.cmax > b.cmax;\n    if (a.cEx != b.cEx) return a.cEx < b.cEx;\n    return a.path.size() < b.path.size();\n}\ninline bool better_tuple(int S, int cmax, int cEx, int len, const SearchResult &best) {\n    if (S != best.S) return S > best.S;\n    if (S == FULLV && len != (int)best.path.size()) return len < (int)best.path.size();\n    if (cmax != best.cmax) return cmax > best.cmax;\n    if (cEx != best.cEx) return cEx < best.cEx;\n    return len < (int)best.path.size();\n}\n\nstruct Node {\n    Board b{};\n    uint8_t blank = 0;\n    uint16_t depth = 0;\n    int parent = -1;\n    uint8_t lastDir = 4;\n    char mv = '?';\n    uint64_t hash = 0;\n\n    int S = 0, cmax = 0, cEx = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN;\n};\n\nstruct Cand {\n    int parent = -1;\n    uint8_t nb = 0;\n    uint8_t lastDir = 4;\n    char mv = '?';\n    uint16_t depth = 0;\n    uint64_t hash = 0;\n    uint64_t sk = 0;\n\n    int S = 0, cmax = 0, cEx = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN;\n};\n\nstruct BeamOutput {\n    SearchResult objBest;\n    SearchResult keyBest;\n};\n\nSearchResult make_result_from_node(const SearchResult &start, const vector<Node> &nodes, int nid, int mode) {\n    SearchResult r;\n    string suffix;\n    for (int cur = nid; nodes[cur].parent != -1; cur = nodes[cur].parent) {\n        suffix.push_back(nodes[cur].mv);\n    }\n    reverse(suffix.begin(), suffix.end());\n\n    r.path = start.path + suffix;\n    r.board = nodes[nid].b;\n    r.blank = nodes[nid].blank;\n    r.lastDir = nodes[nid].lastDir;\n    r.S = nodes[nid].S;\n    r.cmax = nodes[nid].cmax;\n    r.cEx = nodes[nid].cEx;\n    r.key = nodes[nid].key;\n\n    EvalInfo e = evaluate_state(r.board);\n    r.divScore = calc_div_score(e);\n    r.hk = state_key(nodes[nid].hash, (uint8_t)r.lastDir);\n    (void)mode;\n    return r;\n}\n\nBeamOutput run_beam(\n    const SearchResult &start,\n    int width,\n    int mode,\n    int depthLimit,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng,\n    unordered_map<uint64_t, uint16_t, FastHash> *globalVisit = nullptr\n) {\n    BeamOutput out;\n    out.objBest = start;\n    out.keyBest = start;\n\n    int startDepth = (int)start.path.size();\n    if (width <= 0 || startDepth >= depthLimit) {\n        EvalInfo e = evaluate_state(start.board);\n        SearchResult s = start;\n        fill_result_metrics(s, e, mode);\n        out.objBest = s;\n        out.keyBest = s;\n        return out;\n    }\n\n    const int NODE_LIMIT = 280000;\n\n    vector<Node> nodes;\n    size_t est = (size_t)(depthLimit - startDepth + 1) * (size_t)width + 2048ULL;\n    if (est > (size_t)NODE_LIMIT) est = (size_t)NODE_LIMIT;\n    nodes.reserve(est);\n\n    Node root;\n    root.b = start.board;\n    root.blank = (uint8_t)start.blank;\n    root.depth = (uint16_t)startDepth;\n    root.parent = -1;\n    root.lastDir = (uint8_t)start.lastDir;\n    root.mv = '?';\n    root.hash = compute_hash(root.b);\n    {\n        EvalInfo e0 = evaluate_state(root.b);\n        root.S = e0.S;\n        root.cmax = e0.cmax;\n        root.cEx = e0.cmaxEx;\n        root.key = calc_key(e0, startDepth, mode);\n        root.pri = root.key;\n    }\n    nodes.push_back(root);\n\n    auto better_node_obj = [&](int a, int b) -> bool {\n        const Node &x = nodes[a];\n        const Node &y = nodes[b];\n        if (x.S != y.S) return x.S > y.S;\n        if (x.S == FULLV && x.depth != y.depth) return x.depth < y.depth;\n        if (x.cmax != y.cmax) return x.cmax > y.cmax;\n        if (x.cEx != y.cEx) return x.cEx < y.cEx;\n        if (x.key != y.key) return x.key > y.key;\n        return x.depth < y.depth;\n    };\n    auto better_cand_obj = [&](const Cand &x, const Cand &y) -> bool {\n        if (x.S != y.S) return x.S > y.S;\n        if (x.cmax != y.cmax) return x.cmax > y.cmax;\n        if (x.cEx != y.cEx) return x.cEx < y.cEx;\n        return x.key > y.key;\n    };\n\n    int bestObjId = 0;\n    int bestKeyId = 0;\n\n    vector<int> beam, nextBeam;\n    beam.reserve(width + 8);\n    nextBeam.reserve(width + 8);\n    beam.push_back(0);\n\n    unordered_map<uint64_t, uint16_t, FastHash> seenDepth;\n    seenDepth.max_load_factor(0.7f);\n    seenDepth.reserve((size_t)width * 64 + 512ULL);\n    seenDepth[state_key(root.hash, root.lastDir)] = root.depth;\n\n    vector<Cand> cands;\n    cands.reserve((size_t)width * 4 + 64);\n    unordered_map<uint64_t, int, FastHash> localPos;\n    localPos.max_load_factor(0.7f);\n    localPos.reserve((size_t)width * 6 + 128);\n\n    const long long VISIT_PENALTY = 240000LL;\n\n    for (int dep = startDepth; dep < depthLimit; dep++) {\n        if ((dep & 3) == 0 && chrono::steady_clock::now() >= deadline) break;\n        if ((int)nodes.size() >= NODE_LIMIT) break;\n\n        cands.clear();\n        localPos.clear();\n\n        bool timeout = false;\n        for (int bi = 0; bi < (int)beam.size(); bi++) {\n            if ((bi & 31) == 0 && chrono::steady_clock::now() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int id = beam[bi];\n\n            Board base = nodes[id].b;\n            uint8_t curBlank = nodes[id].blank;\n            uint8_t curLast = nodes[id].lastDir;\n            uint16_t childDepth = (uint16_t)(nodes[id].depth + 1);\n            uint64_t curHash = nodes[id].hash;\n\n            for (int d = 0; d < 4; d++) {\n                if (curLast < 4 && d == OPP[curLast]) continue;\n                int nb = NEI[curBlank][d];\n                if (nb < 0) continue;\n\n                uint8_t tile = base[nb];\n                base[curBlank] = tile;\n                base[nb] = 0;\n\n                uint64_t ch = curHash\n                            ^ zobrist[curBlank][0]\n                            ^ zobrist[curBlank][tile]\n                            ^ zobrist[nb][tile]\n                            ^ zobrist[nb][0];\n                uint64_t sk = state_key(ch, (uint8_t)d);\n\n                auto itg = seenDepth.find(sk);\n                if (itg != seenDepth.end() && itg->second <= childDepth) {\n                    base[nb] = tile;\n                    base[curBlank] = 0;\n                    continue;\n                }\n\n                EvalInfo ec = evaluate_state(base);\n\n                Cand cd;\n                cd.parent = id;\n                cd.nb = (uint8_t)nb;\n                cd.lastDir = (uint8_t)d;\n                cd.mv = OPCH[d];\n                cd.depth = childDepth;\n                cd.hash = ch;\n                cd.sk = sk;\n\n                cd.S = ec.S;\n                cd.cmax = ec.cmax;\n                cd.cEx = ec.cmaxEx;\n                cd.key = calc_key(ec, childDepth, mode);\n\n                long long pri = cd.key * 1024LL + (long long)(rng.next() & 1023ULL);\n                if (globalVisit) {\n                    auto itv = globalVisit->find(sk);\n                    if (itv != globalVisit->end()) {\n                        pri -= VISIT_PENALTY * (long long)itv->second;\n                    }\n                }\n                cd.pri = pri;\n\n                auto itl = localPos.find(sk);\n                if (itl == localPos.end()) {\n                    localPos[sk] = (int)cands.size();\n                    cands.push_back(cd);\n                } else {\n                    int idx = itl->second;\n                    const Cand &old = cands[idx];\n                    if (cd.pri > old.pri || (cd.pri == old.pri && cd.key > old.key)) {\n                        cands[idx] = cd;\n                    }\n                }\n\n                base[nb] = tile;\n                base[curBlank] = 0;\n            }\n        }\n\n        if (timeout || cands.empty()) break;\n\n        int bestObjCandIdx = 0, bestKeyCandIdx = 0;\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (better_cand_obj(cands[i], cands[bestObjCandIdx])) bestObjCandIdx = i;\n            if (cands[i].key > cands[bestKeyCandIdx].key) bestKeyCandIdx = i;\n        }\n\n        int maxAdd = NODE_LIMIT - (int)nodes.size();\n        int take = min(width, (int)cands.size());\n        take = min(take, maxAdd);\n        if (take <= 0) break;\n\n        vector<int> ord((int)cands.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmpPri = [&](int a, int b) -> bool {\n            const Cand &x = cands[a];\n            const Cand &y = cands[b];\n            if (x.pri != y.pri) return x.pri > y.pri;\n            if (x.S != y.S) return x.S > y.S;\n            if (x.cmax != y.cmax) return x.cmax > y.cmax;\n            if (x.cEx != y.cEx) return x.cEx < y.cEx;\n            if (x.key != y.key) return x.key > y.key;\n            return a < b;\n        };\n\n        if ((int)ord.size() > take) {\n            nth_element(ord.begin(), ord.begin() + take, ord.end(), cmpPri);\n            ord.resize(take);\n\n            auto contains = [&](int idx) -> bool {\n                for (int v : ord) if (v == idx) return true;\n                return false;\n            };\n            auto replace_worst_with = [&](int idx) {\n                if (contains(idx) || ord.empty()) return;\n                int w = 0;\n                for (int i = 1; i < (int)ord.size(); i++) {\n                    if (cmpPri(ord[w], ord[i])) w = i; // ord[i] is worse\n                }\n                ord[w] = idx;\n            };\n            replace_worst_with(bestObjCandIdx);\n            if (bestKeyCandIdx != bestObjCandIdx) replace_worst_with(bestKeyCandIdx);\n        }\n\n        sort(ord.begin(), ord.end(), cmpPri);\n        ord.erase(unique(ord.begin(), ord.end()), ord.end());\n        if ((int)ord.size() > take) ord.resize(take);\n\n        nextBeam.clear();\n        for (int idx : ord) {\n            const Cand &c = cands[idx];\n\n            Board pb = nodes[c.parent].b;\n            uint8_t pblank = nodes[c.parent].blank;\n            uint8_t tile = pb[c.nb];\n            pb[pblank] = tile;\n            pb[c.nb] = 0;\n\n            Node child;\n            child.b = std::move(pb);\n            child.blank = c.nb;\n            child.depth = c.depth;\n            child.parent = c.parent;\n            child.lastDir = c.lastDir;\n            child.mv = c.mv;\n            child.hash = c.hash;\n            child.S = c.S;\n            child.cmax = c.cmax;\n            child.cEx = c.cEx;\n            child.key = c.key;\n            child.pri = c.pri;\n\n            nodes.push_back(std::move(child));\n            int nid = (int)nodes.size() - 1;\n            nextBeam.push_back(nid);\n\n            auto it = seenDepth.find(c.sk);\n            if (it == seenDepth.end() || it->second > c.depth) seenDepth[c.sk] = c.depth;\n\n            if (better_node_obj(nid, bestObjId)) bestObjId = nid;\n            if (nodes[nid].key > nodes[bestKeyId].key ||\n                (nodes[nid].key == nodes[bestKeyId].key && better_node_obj(nid, bestKeyId))) {\n                bestKeyId = nid;\n            }\n        }\n\n        if (nextBeam.empty()) break;\n        beam.swap(nextBeam);\n\n        if (nodes[bestObjId].S == FULLV) break;\n    }\n\n    out.objBest = make_result_from_node(start, nodes, bestObjId, mode);\n    out.keyBest = make_result_from_node(start, nodes, bestKeyId, mode);\n    return out;\n}\n\nstruct WalkOutput {\n    SearchResult bestObj;\n    SearchResult bestKey;\n};\n\nWalkOutput guided_walk(\n    const SearchResult &start,\n    int mode,\n    int greedPermille,\n    bool look2,\n    int depthLimit,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng,\n    unordered_map<uint64_t, uint16_t, FastHash> *globalVisit = nullptr\n) {\n    WalkOutput out;\n    int startDepth = (int)start.path.size();\n    out.bestObj = start;\n    out.bestKey = start;\n\n    if (startDepth >= depthLimit) {\n        EvalInfo e0 = evaluate_state(start.board);\n        fill_result_metrics(out.bestObj, e0, mode);\n        out.bestKey = out.bestObj;\n        return out;\n    }\n\n    Board board = start.board;\n    int blank = start.blank;\n    int lastDir = start.lastDir;\n    string path = start.path;\n\n    uint64_t hash = compute_hash(board);\n    EvalInfo curEval = evaluate_state(board);\n    long long curKey = calc_key(curEval, startDepth, mode);\n\n    out.bestObj.path = path;\n    out.bestObj.board = board;\n    out.bestObj.blank = blank;\n    out.bestObj.lastDir = lastDir;\n    out.bestObj.S = curEval.S;\n    out.bestObj.cmax = curEval.cmax;\n    out.bestObj.cEx = curEval.cmaxEx;\n    out.bestObj.key = curKey;\n    out.bestObj.divScore = calc_div_score(curEval);\n    out.bestObj.hk = state_key(hash, (uint8_t)lastDir);\n    out.bestKey = out.bestObj;\n\n    deque<uint64_t> recent;\n    recent.push_back(hash);\n    const int RECENT_WINDOW = 18;\n    const long long LOOP_PENALTY = 17000000LL;\n    const long long VISIT_PENALTY = 200000LL;\n\n    struct GCand {\n        int d = 0;\n        int nb = 0;\n        Board b{};\n        uint64_t h = 0;\n        uint64_t sk = 0;\n        EvalInfo e;\n        long long key = LLONG_MIN;\n        long long val = LLONG_MIN;\n    };\n\n    for (int step = startDepth; step < depthLimit; step++) {\n        if ((step & 15) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        GCand cs[4];\n        int m = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n            int nb = NEI[blank][d];\n            if (nb < 0) continue;\n\n            GCand c;\n            c.d = d;\n            c.nb = nb;\n            c.b = board;\n\n            uint8_t tile = c.b[nb];\n            c.b[blank] = tile;\n            c.b[nb] = 0;\n\n            c.h = hash\n                ^ zobrist[blank][0]\n                ^ zobrist[blank][tile]\n                ^ zobrist[nb][tile]\n                ^ zobrist[nb][0];\n            c.sk = state_key(c.h, (uint8_t)d);\n\n            c.e = evaluate_state(c.b);\n            c.key = calc_key(c.e, step + 1, mode);\n\n            for (uint64_t h0 : recent) {\n                if (h0 == c.h) {\n                    c.key -= LOOP_PENALTY;\n                    break;\n                }\n            }\n            if (globalVisit) {\n                auto itv = globalVisit->find(c.sk);\n                if (itv != globalVisit->end()) c.key -= VISIT_PENALTY * (long long)itv->second;\n            }\n\n            c.val = c.key;\n\n            if (look2 && step + 1 < depthLimit) {\n                long long best2 = LLONG_MIN / 4;\n                for (int d2 = 0; d2 < 4; d2++) {\n                    if (d2 == OPP[d]) continue;\n                    int nb2 = NEI[nb][d2];\n                    if (nb2 < 0) continue;\n\n                    Board b2 = c.b;\n                    uint8_t t2 = b2[nb2];\n                    b2[nb] = t2;\n                    b2[nb2] = 0;\n\n                    EvalInfo e2 = evaluate_state(b2);\n                    long long k2 = calc_key(e2, step + 2, mode);\n                    if (k2 > best2) best2 = k2;\n                }\n                if (best2 > LLONG_MIN / 8) c.val = c.key * 4 + best2;\n            }\n\n            cs[m++] = std::move(c);\n        }\n\n        if (m == 0) break;\n\n        sort(cs, cs + m, [](const GCand &a, const GCand &b) {\n            if (a.val != b.val) return a.val > b.val;\n            return a.key > b.key;\n        });\n\n        int pick = 0;\n        uint64_t rr = rng.next() % 1000ULL;\n        if (m >= 2 && rr > (uint64_t)greedPermille) {\n            pick = (m == 2) ? 1 : (1 + (int)(rng.next() % (uint64_t)(m - 1)));\n        }\n\n        const GCand &ch = cs[pick];\n\n        board = ch.b;\n        blank = ch.nb;\n        lastDir = ch.d;\n        hash = ch.h;\n        curEval = ch.e;\n        curKey = ch.key;\n        path.push_back(OPCH[ch.d]);\n\n        if (better_tuple(curEval.S, curEval.cmax, curEval.cmaxEx, (int)path.size(), out.bestObj)) {\n            out.bestObj.path = path;\n            out.bestObj.board = board;\n            out.bestObj.blank = blank;\n            out.bestObj.lastDir = lastDir;\n            out.bestObj.S = curEval.S;\n            out.bestObj.cmax = curEval.cmax;\n            out.bestObj.cEx = curEval.cmaxEx;\n            out.bestObj.key = curKey;\n            out.bestObj.divScore = calc_div_score(curEval);\n            out.bestObj.hk = state_key(hash, (uint8_t)lastDir);\n            if (out.bestObj.S == FULLV) break;\n        }\n\n        if (curKey > out.bestKey.key) {\n            out.bestKey.path = path;\n            out.bestKey.board = board;\n            out.bestKey.blank = blank;\n            out.bestKey.lastDir = lastDir;\n            out.bestKey.S = curEval.S;\n            out.bestKey.cmax = curEval.cmax;\n            out.bestKey.cEx = curEval.cmaxEx;\n            out.bestKey.key = curKey;\n            out.bestKey.divScore = calc_div_score(curEval);\n            out.bestKey.hk = state_key(hash, (uint8_t)lastDir);\n        }\n\n        recent.push_back(hash);\n        if ((int)recent.size() > RECENT_WINDOW) recent.pop_front();\n    }\n\n    return out;\n}\n\nSearchResult random_perturb(\n    const SearchResult &start,\n    int steps,\n    int mode,\n    int greedPermille,\n    XorShift64 &rng\n) {\n    SearchResult cur = start;\n    int startDepth = (int)start.path.size();\n    if (startDepth >= T_global || steps <= 0) return cur;\n\n    Board board = start.board;\n    int blank = start.blank;\n    int lastDir = start.lastDir;\n    string path = start.path;\n\n    int lim = min(T_global, startDepth + steps);\n\n    struct PCand {\n        int d = 0;\n        int nb = 0;\n        Board b{};\n        EvalInfo e;\n        long long key = LLONG_MIN;\n    };\n\n    for (int step = startDepth; step < lim; step++) {\n        PCand cs[4];\n        int m = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n            int nb = NEI[blank][d];\n            if (nb < 0) continue;\n\n            PCand c;\n            c.d = d;\n            c.nb = nb;\n            c.b = board;\n\n            uint8_t tile = c.b[nb];\n            c.b[blank] = tile;\n            c.b[nb] = 0;\n\n            c.e = evaluate_state(c.b);\n            c.key = calc_key(c.e, step + 1, mode);\n            cs[m++] = std::move(c);\n        }\n\n        if (m == 0) break;\n\n        sort(cs, cs + m, [](const PCand &a, const PCand &b) {\n            if (a.key != b.key) return a.key > b.key;\n            return a.d < b.d;\n        });\n\n        int pick = 0;\n        uint64_t rr = rng.next() % 1000ULL;\n        if (m >= 2 && rr > (uint64_t)greedPermille) {\n            pick = (m == 2) ? 1 : (int)(rng.next() % (uint64_t)m);\n        }\n\n        board = cs[pick].b;\n        blank = cs[pick].nb;\n        lastDir = cs[pick].d;\n        path.push_back(OPCH[cs[pick].d]);\n    }\n\n    EvalInfo ef = evaluate_state(board);\n    cur.path = std::move(path);\n    cur.board = board;\n    cur.blank = blank;\n    cur.lastDir = lastDir;\n    fill_result_metrics(cur, ef, mode);\n    return cur;\n}\n\nint dir_from_char(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\nSearchResult make_prefix_state(\n    const SearchResult &src,\n    int prefLen,\n    const Board &init,\n    int initBlank\n) {\n    SearchResult r;\n    r.path.clear();\n    r.board = init;\n    r.blank = initBlank;\n    r.lastDir = 4;\n\n    int lim = min(prefLen, (int)src.path.size());\n    r.path.reserve(lim);\n\n    for (int i = 0; i < lim; i++) {\n        int d = dir_from_char(src.path[i]);\n        if (d < 0) break;\n        int nb = NEI[r.blank][d];\n        if (nb < 0) break;\n        uint8_t tile = r.board[nb];\n        r.board[r.blank] = tile;\n        r.board[nb] = 0;\n        r.blank = nb;\n        r.lastDir = d;\n        r.path.push_back(src.path[i]);\n    }\n\n    EvalInfo e = evaluate_state(r.board);\n    fill_result_metrics(r, e, 1);\n    return r;\n}\n\nstring best_legal_prefix(const string &path, const Board &init, int initBlank) {\n    Board b = init;\n    int blank = initBlank;\n\n    string cur, best;\n    cur.reserve(min((int)path.size(), T_global));\n    best.reserve(min((int)path.size(), T_global));\n\n    EvalInfo e0 = evaluate_state(b);\n    int bestS = e0.S;\n    int bestLen = (bestS == FULLV ? 0 : INT_MAX);\n\n    auto better_obj = [&](int S, int len) -> bool {\n        if (S != bestS) return S > bestS;\n        if (S == FULLV) return len < bestLen;\n        return false;\n    };\n\n    for (char c : path) {\n        if ((int)cur.size() >= T_global) break;\n        int d = dir_from_char(c);\n        if (d < 0) break;\n        int nb = NEI[blank][d];\n        if (nb < 0) break; // illegal -> truncate\n\n        uint8_t tile = b[nb];\n        b[blank] = tile;\n        b[nb] = 0;\n        blank = nb;\n        cur.push_back(c);\n\n        EvalInfo e = evaluate_state(b);\n        int S = e.S;\n        int len = (int)cur.size();\n        if (better_obj(S, len)) {\n            bestS = S;\n            bestLen = len;\n            best = cur;\n        }\n    }\n\n    return best;\n}\n\ntemplate<class Comp>\nvoid insert_pool(vector<SearchResult> &pool, const SearchResult &r, int limitSize, Comp comp) {\n    for (auto &x : pool) {\n        if (x.hk == r.hk) {\n            if (comp(r, x)) x = r;\n            sort(pool.begin(), pool.end(), comp);\n            if ((int)pool.size() > limitSize) pool.resize(limitSize);\n            return;\n        }\n    }\n    pool.push_back(r);\n    sort(pool.begin(), pool.end(), comp);\n    if ((int)pool.size() > limitSize) pool.resize(limitSize);\n}\n\nconst SearchResult* pick_pool(const vector<SearchResult> &pool, XorShift64 &rng) {\n    if (pool.empty()) return nullptr;\n    int k = min((int)pool.size(), 6);\n    uint64_t r = rng.next() % 100ULL;\n    int idx;\n    if (r < 45ULL) idx = 0;\n    else if (r < 70ULL && k >= 2) idx = 1;\n    else if (r < 85ULL && k >= 3) idx = 2;\n    else idx = (int)(rng.next() % (uint64_t)k);\n    return &pool[idx];\n}\n\nint hex_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    return 10 + (c - 'A');\n}\ninline int rnd_int(XorShift64 &rng, int l, int r) {\n    if (l >= r) return l;\n    return l + (int)(rng.next() % (uint64_t)(r - l + 1));\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N_global >> T_global;\n    NN_global = N_global * N_global;\n    FULLV = NN_global - 1;\n\n    Board init{};\n    int initBlank = -1;\n\n    for (int i = 0; i < N_global; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N_global; j++) {\n            int v = hex_to_int(s[j]);\n            init[i * N_global + j] = (uint8_t)v;\n            if (v == 0) initBlank = i * N_global + j;\n        }\n    }\n\n    for (int p = 0; p < NN_global; p++) {\n        int r = p / N_global;\n        int c = p % N_global;\n        NEI[p][0] = (r > 0) ? (p - N_global) : -1;            // U\n        NEI[p][1] = (r + 1 < N_global) ? (p + N_global) : -1; // D\n        NEI[p][2] = (c > 0) ? (p - 1) : -1;                   // L\n        NEI[p][3] = (c + 1 < N_global) ? (p + 1) : -1;        // R\n    }\n\n    for (int a = 0; a < 16; a++) {\n        for (int b = 0; b < 16; b++) {\n            CONN[0][a][b] = ((a & 4) && (b & 1)); // right-left\n            CONN[1][a][b] = ((a & 8) && (b & 2)); // down-up\n        }\n    }\n\n    g_edges.clear();\n    g_edges.reserve(2 * N_global * (N_global - 1));\n    for (int i = 0; i < N_global; i++) {\n        for (int j = 0; j < N_global; j++) {\n            int id = i * N_global + j;\n            if (j + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + 1), 0});\n            if (i + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + N_global), 1});\n        }\n    }\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n    for (int i = 0; i < NN_global; i++) {\n        seed ^= (uint64_t)init[i] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n\n    uint64_t zseed = seed ^ 0xdeadbeefcafebabeULL;\n    for (int i = 0; i < 100; i++) {\n        for (int v = 0; v < 16; v++) {\n            zobrist[i][v] = splitmix64_seed(zseed);\n        }\n    }\n\n    XorShift64 rng(seed ^ 0x517cc1b727220a95ULL);\n\n    SearchResult initRes;\n    initRes.path = \"\";\n    initRes.board = init;\n    initRes.blank = initBlank;\n    initRes.lastDir = 4;\n    {\n        EvalInfo e0 = evaluate_state(initRes.board);\n        fill_result_metrics(initRes, e0, 0);\n    }\n\n    SearchResult best = initRes;\n    int depthLimit = T_global;\n\n    vector<SearchResult> poolObj, poolPot;\n    poolObj.reserve(16);\n    poolPot.reserve(16);\n\n    unordered_map<uint64_t, uint16_t, FastHash> visitCnt;\n    visitCnt.max_load_factor(0.7f);\n    visitCnt.reserve(1 << 15);\n\n    auto touch_visit = [&](const SearchResult &r) {\n        auto &x = visitCnt[r.hk];\n        if (x < 60) x++;\n    };\n\n    auto consider = [&](const SearchResult &r, bool updateBest = true) {\n        if (updateBest && better_result(r, best)) best = r;\n        insert_pool(poolObj, r, 12, better_result);\n        insert_pool(poolPot, r, 12, better_div);\n        touch_visit(r);\n\n        if (best.S == FULLV) {\n            depthLimit = min(depthLimit, (int)best.path.size() - 1);\n            if (depthLimit < 0) depthLimit = 0;\n        }\n    };\n\n    consider(initRes, true);\n\n    auto choose_start = [&](bool exploratory, bool preferPot) -> const SearchResult* {\n        const SearchResult *p = nullptr;\n        if (preferPot) {\n            p = pick_pool(poolPot, rng);\n            if (!p && exploratory) p = pick_pool(poolObj, rng);\n        } else if (!exploratory) {\n            p = pick_pool(poolObj, rng);\n            if (!p) p = pick_pool(poolPot, rng);\n        } else {\n            if ((rng.next() & 1ULL) == 0ULL) p = pick_pool(poolObj, rng);\n            else p = pick_pool(poolPot, rng);\n            if (!p) p = pick_pool(poolObj, rng);\n            if (!p) p = pick_pool(poolPot, rng);\n        }\n\n        if (!p) p = &initRes;\n        if ((int)p->path.size() >= depthLimit) {\n            const SearchResult *q = pick_pool(poolObj, rng);\n            if (q && (int)q->path.size() < depthLimit) p = q;\n            else p = &initRes;\n        }\n        return p;\n    };\n\n    auto startTime = chrono::steady_clock::now();\n    const int TIME_LIMIT_MS = 2760;\n    auto globalDeadline = startTime + chrono::milliseconds(TIME_LIMIT_MS);\n\n    auto P1 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 20 / 100);\n    auto P2 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 35 / 100);\n    auto P3 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 50 / 100);\n    auto P4 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 68 / 100);\n    if (P1 > globalDeadline) P1 = globalDeadline;\n    if (P2 > globalDeadline) P2 = globalDeadline;\n    if (P3 > globalDeadline) P3 = globalDeadline;\n    if (P4 > globalDeadline) P4 = globalDeadline;\n\n    int wMain = clamp(1250000 / max(1, 2 * T_global), 160, 700);\n    if (N_global <= 7) wMain += 40;\n    if (N_global >= 10) wMain -= 20;\n    wMain = clamp(wMain, 160, 720);\n    int wMid = max(90, wMain * 3 / 4);\n    int wSmall = max(70, wMain / 2);\n\n    int Hlong = max(180, T_global / 3);\n    int Hmid = max(110, T_global / 6);\n    int Hshort = max(60, T_global / 12);\n    int Hend = max(140, T_global / 5);\n\n    // Phase 1\n    if (chrono::steady_clock::now() < P1 && depthLimit > 0) {\n        int local = min(depthLimit, Hlong);\n        if (local > 0) {\n            BeamOutput bo = run_beam(initRes, wMain, 0, local, P1, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, true);\n        }\n    }\n\n    // Phase 2\n    if (chrono::steady_clock::now() < P2 && depthLimit > 0) {\n        int local = min(depthLimit, Hlong + Hmid);\n        if (local > 0) {\n            BeamOutput bo = run_beam(initRes, wMid, 1, local, P2, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, true);\n        }\n    }\n\n    // Phase 3\n    if (chrono::steady_clock::now() < P3 && depthLimit > 0) {\n        const SearchResult *st = choose_start(true, true);\n        int local = min(depthLimit, (int)st->path.size() + Hlong);\n        if (local > (int)st->path.size()) {\n            BeamOutput bo = run_beam(*st, wMid, 2, local, P3, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, true);\n        }\n    }\n\n    // Phase 4 seed walk\n    if (chrono::steady_clock::now() < P4 && depthLimit > 0) {\n        const SearchResult *st = choose_start(true, false);\n        int local = min(depthLimit, (int)st->path.size() + Hlong);\n        auto dl = min(P4, chrono::steady_clock::now() + chrono::milliseconds(65));\n        WalkOutput wo = guided_walk(*st, 1, 860, true, local, dl, rng, &visitCnt);\n        consider(wo.bestObj, true);\n        consider(wo.bestKey, true);\n    }\n\n    int nearThr = max(2, N_global / 2);\n    int iter = 0;\n\n    while (chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n        auto now = chrono::steady_clock::now();\n\n        if (best.S == FULLV) {\n            // minimize K\n            auto dl = min(now + chrono::milliseconds(38), globalDeadline);\n            BeamOutput bo = run_beam(initRes, wSmall, 2, depthLimit, dl, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, false);\n            continue;\n        }\n\n        if (best.S >= FULLV - nearThr) {\n            const SearchResult *st = &best;\n\n            auto dl1 = min(chrono::steady_clock::now() + chrono::milliseconds(58), globalDeadline);\n            int local1 = min(depthLimit, (int)st->path.size() + Hend);\n            if (local1 > (int)st->path.size()) {\n                BeamOutput bo = run_beam(*st, wMain, 2, local1, dl1, rng, &visitCnt);\n                consider(bo.objBest, true);\n                consider(bo.keyBest, true);\n            }\n\n            if (chrono::steady_clock::now() < globalDeadline) {\n                auto dl2 = min(chrono::steady_clock::now() + chrono::milliseconds(34), globalDeadline);\n                WalkOutput wo = guided_walk(*st, 2, 905, true, depthLimit, dl2, rng, &visitCnt);\n                consider(wo.bestObj, true);\n                consider(wo.bestKey, false);\n            }\n\n            iter++;\n            continue;\n        }\n\n        uint64_t act = rng.next() % 100ULL;\n\n        if (act < 20ULL) {\n            // long rollout from diversity pool\n            const SearchResult *st = choose_start(true, true);\n            auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(66), globalDeadline);\n            int mode = 1 + (int)(rng.next() % 2ULL); // 1 or 2\n            int greed = rnd_int(rng, 820, 940);\n            WalkOutput wo = guided_walk(*st, mode, greed, false, depthLimit, dl, rng, &visitCnt);\n            consider(wo.bestObj, true);\n            consider(wo.bestKey, false);\n\n        } else if (act < 40ULL) {\n            // local guided\n            const SearchResult *st = choose_start(true, false);\n            int horizon = min(depthLimit, (int)st->path.size() + Hmid + rnd_int(rng, 0, Hshort));\n            if (horizon > (int)st->path.size()) {\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(46), globalDeadline);\n                int mode = (int)(rng.next() % 3ULL);\n                int greed = rnd_int(rng, 760, 930);\n                bool look2 = ((rng.next() & 3ULL) == 0ULL);\n                WalkOutput wo = guided_walk(*st, mode, greed, look2, horizon, dl, rng, &visitCnt);\n                consider(wo.bestObj, true);\n                consider(wo.bestKey, false);\n            }\n\n        } else if (act < 62ULL) {\n            // perturb then short beam\n            const SearchResult *st = choose_start(true, true);\n            int steps = Hshort / 2 + rnd_int(rng, 0, Hshort);\n            int pMode = (int)(rng.next() % 2ULL);\n            int greed = rnd_int(rng, 700, 900);\n            SearchResult rp = random_perturb(*st, steps, pMode, greed, rng);\n            consider(rp, true);\n\n            if (chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n                int local = min(depthLimit, (int)rp.path.size() + Hmid + rnd_int(rng, 0, Hshort / 2));\n                if (local > (int)rp.path.size()) {\n                    auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(48), globalDeadline);\n                    BeamOutput bo = run_beam(rp, wSmall, 2, local, dl, rng, &visitCnt);\n                    consider(bo.objBest, true);\n                    consider(bo.keyBest, false);\n                }\n            }\n\n        } else if (act < 84ULL) {\n            // local beam\n            bool preferPot = ((rng.next() & 1ULL) == 0ULL);\n            const SearchResult *st = choose_start(true, preferPot);\n            int local = min(depthLimit, (int)st->path.size() + Hmid + rnd_int(rng, 0, Hshort));\n            if (local > (int)st->path.size()) {\n                int w = rnd_int(rng, wSmall, wMid);\n                int mode = (int)(rng.next() % 3ULL);\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(52), globalDeadline);\n                BeamOutput bo = run_beam(*st, w, mode, local, dl, rng, &visitCnt);\n                consider(bo.objBest, true);\n                consider(bo.keyBest, true);\n            }\n\n        } else {\n            // prefix restart from best\n            if ((int)best.path.size() >= 24) {\n                int back = min((int)best.path.size() - 1, Hmid + Hshort / 2);\n                int pref = (int)best.path.size() - rnd_int(rng, 8, max(8, back));\n                if (pref < 0) pref = 0;\n\n                SearchResult pre = make_prefix_state(best, pref, init, initBlank);\n                consider(pre, false);\n\n                int local = min(depthLimit, (int)pre.path.size() + Hmid + rnd_int(rng, 0, Hshort / 2));\n                if (local > (int)pre.path.size()) {\n                    auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(42), globalDeadline);\n                    BeamOutput bo = run_beam(pre, wSmall, 1 + (int)(rng.next() % 2ULL), local, dl, rng, &visitCnt);\n                    consider(bo.objBest, true);\n                    consider(bo.keyBest, true);\n                }\n            } else {\n                const SearchResult *st = choose_start(true, false);\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(42), globalDeadline);\n                int local = min(depthLimit, (int)st->path.size() + Hshort + rnd_int(rng, 0, Hshort));\n                WalkOutput wo = guided_walk(*st, 1, 860, false, local, dl, rng, &visitCnt);\n                consider(wo.bestObj, true);\n                consider(wo.bestKey, false);\n            }\n        }\n\n        if ((iter % 5 == 2) && chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n            const SearchResult *top = pick_pool(poolObj, rng);\n            if (top && (int)top->path.size() < depthLimit) {\n                int local = min(depthLimit, (int)top->path.size() + Hshort);\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(26), globalDeadline);\n                BeamOutput bo = run_beam(*top, wSmall, 2, local, dl, rng, &visitCnt);\n                consider(bo.objBest, true);\n                consider(bo.keyBest, false);\n            }\n        }\n\n        iter++;\n    }\n\n    string out = best_legal_prefix(best.path, init, initBlank);\n    if ((int)out.size() > T_global) out.resize(T_global);\n    cout << out << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct Line {\n    long long x1, y1, x2, y2;\n    long long dx, dy;\n};\n\nstruct EvalKey {\n    int F = 0;\n    int def2 = 0;\n    int active = 0;\n    int waste = 0;\n    long long over = 0;\n};\n\nstatic inline bool betterKey(const EvalKey& a, const EvalKey& b) {\n    if (a.F != b.F) return a.F > b.F;\n    if (a.def2 != b.def2) return a.def2 < b.def2;\n    if (a.active != b.active) return a.active > b.active;\n    if (a.waste != b.waste) return a.waste < b.waste;\n    return a.over < b.over;\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) {\n        x = seed ? seed : 88172645463325252ull;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct State {\n    vector<vector<int>> pieces;\n    vector<int> pieceSize;\n    vector<int> pieceOf;     // -1 deleted\n    vector<int> active;\n    array<int, 11> h{};\n    int F = 0;\n    int def2 = 0;\n    int waste = 0;\n    long long over = 0;\n    vector<Line> lines;\n};\n\nstruct RunResult {\n    vector<Line> lines;\n    EvalKey key;\n};\n\nclass Solver {\n    static constexpr double PI = 3.1415926535897932384626433832795;\n    static constexpr long long BIG = (1LL << 62);\n\n    int N, K;\n    array<int, 11> a{};\n    vector<Point> pts;\n    int totalA = 0;\n    vector<long long> pen;\n\n    chrono::steady_clock::time_point t0;\n    const double TL = 2.82;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline long long orient(const Line& ln, const Point& p) const {\n        return ln.dx * ((long long)p.y - ln.y1) - ln.dy * ((long long)p.x - ln.x1);\n    }\n\n    inline int calcF(const array<int, 11>& h) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], h[d]);\n        return s;\n    }\n\n    inline int calcDef2(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int sat = min(a[d], h[d]);\n            int def = a[d] - sat;\n            v += def * def;\n        }\n        return v;\n    }\n\n    inline int calcWaste(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int ex = max(0, h[d] - a[d]);\n            v += ex * ex;\n        }\n        return v;\n    }\n\n    inline EvalKey stateKey(const State& st) const {\n        return EvalKey{st.F, st.def2, (int)st.active.size(), st.waste, st.over};\n    }\n\n    inline void addPart(array<int, 11>& h, long long& over, int t, int delta) const {\n        if (t <= 0) return;\n        if (t <= 10) h[t] += delta;\n        over += (long long)delta * pen[t];\n    }\n\n    inline void addPieceState(array<int, 11>& h, long long& over, int s, int l, int delta) const {\n        if (l <= 0 || l >= s) {\n            addPart(h, over, s, delta);\n        } else {\n            addPart(h, over, l, delta);\n            addPart(h, over, s - l, delta);\n        }\n    }\n\n    inline double normTheta(double th) const {\n        while (th < 0) th += PI;\n        while (th >= PI) th -= PI;\n        return th;\n    }\n\n    Line makeLineFromNormal(double nx, double ny, double c) const {\n        const double S = 8.8e8;\n        double dx = -ny, dy = nx;\n        double cx = nx * c, cy = ny * c;\n\n        long long x1 = llround(cx + dx * S);\n        long long y1 = llround(cy + dy * S);\n        long long x2 = llround(cx - dx * S);\n        long long y2 = llround(cy - dy * S);\n\n        if (x1 == x2 && y1 == y2) x2++;\n\n        Line ln;\n        ln.x1 = x1; ln.y1 = y1;\n        ln.x2 = x2; ln.y2 = y2;\n        ln.dx = ln.x2 - ln.x1;\n        ln.dy = ln.y2 - ln.y1;\n        if (ln.dx == 0 && ln.dy == 0) {\n            ln.x2++;\n            ln.dx = 1;\n        }\n        return ln;\n    }\n\n    Line makeLine(double theta, double c) const {\n        return makeLineFromNormal(cos(theta), sin(theta), c);\n    }\n\n    Line randomGlobalLine(XorShift64& rng) const {\n        double theta = rng.nextDouble() * PI;\n        double c = (rng.nextDouble() * 2.0 - 1.0) * 9200.0;\n        return makeLine(theta, c);\n    }\n\n    EvalKey evalLine(const State& st, const Line& ln, vector<int>& L, vector<int>& R) const {\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) {\n            L[i] = 0;\n            R[i] = 0;\n        }\n\n        for (int idx : st.active) {\n            int pid = st.pieceOf[idx];\n            long long v = orient(ln, pts[idx]);\n            if (v > 0) L[pid]++;\n            else if (v < 0) R[pid]++;\n        }\n\n        array<int, 11> h2 = st.h;\n        long long over2 = st.over;\n        int removed = 0;\n\n        for (int pid = 0; pid < P; pid++) {\n            int s = st.pieceSize[pid];\n            int l = L[pid];\n            int r = R[pid];\n\n            if (l == s || r == s) continue;\n\n            removed += s - l - r;\n            over2 -= pen[s];\n            if (l > 0) over2 += pen[l];\n            if (r > 0) over2 += pen[r];\n\n            if (1 <= s && s <= 10) h2[s]--;\n            if (1 <= l && l <= 10) h2[l]++;\n            if (1 <= r && r <= 10) h2[r]++;\n        }\n\n        EvalKey key;\n        key.F = calcF(h2);\n        key.def2 = calcDef2(h2);\n        key.active = (int)st.active.size() - removed;\n        key.waste = calcWaste(h2);\n        key.over = over2;\n        return key;\n    }\n\n    void rebuildMetrics(State& st) const {\n        st.h.fill(0);\n        st.over = 0;\n        for (int s : st.pieceSize) {\n            if (1 <= s && s <= 10) st.h[s]++;\n            st.over += pen[s];\n        }\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n    }\n\n    void applyLine(State& st, const Line& ln) const {\n        vector<vector<int>> newPieces;\n        vector<int> newSizes;\n        vector<int> newActive;\n\n        newPieces.reserve(st.pieces.size() * 2 + 2);\n        newSizes.reserve(st.pieces.size() * 2 + 2);\n        newActive.reserve(st.active.size());\n\n        fill(st.pieceOf.begin(), st.pieceOf.end(), -1);\n\n        for (const auto& pc : st.pieces) {\n            vector<int> left, right;\n            left.reserve(pc.size());\n            right.reserve(pc.size());\n\n            for (int idx : pc) {\n                long long v = orient(ln, pts[idx]);\n                if (v > 0) left.push_back(idx);\n                else if (v < 0) right.push_back(idx);\n            }\n\n            if (!left.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : left) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)left.size());\n                newPieces.push_back(move(left));\n            }\n            if (!right.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : right) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)right.size());\n                newPieces.push_back(move(right));\n            }\n        }\n\n        st.pieces.swap(newPieces);\n        st.pieceSize.swap(newSizes);\n        st.active.swap(newActive);\n        st.lines.push_back(ln);\n        rebuildMetrics(st);\n    }\n\n    bool bestCutForTheta(const State& st, double theta, double& bestC, EvalKey& pred,\n                         vector<pair<double, int>>& ord, vector<int>& cntLeft) const {\n        int M = (int)st.active.size();\n        if (M < 2) return false;\n\n        double nx = cos(theta), ny = sin(theta);\n        ord.resize(M);\n        for (int i = 0; i < M; i++) {\n            int idx = st.active[i];\n            ord[i] = {nx * pts[idx].x + ny * pts[idx].y, idx};\n        }\n        sort(ord.begin(), ord.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) cntLeft[i] = 0;\n\n        array<int, 11> hcur = st.h;\n        long long overcur = st.over;\n\n        bool found = false;\n        EvalKey bestLocal{};\n        double cLocal = 0.0;\n\n        const double EPS = 1e-12;\n        int i = 0;\n        while (i < M) {\n            int j = i + 1;\n            while (j < M && fabs(ord[j].first - ord[i].first) <= EPS) j++;\n\n            for (int k = i; k < j; k++) {\n                int idx = ord[k].second;\n                int pid = st.pieceOf[idx];\n                int s = st.pieceSize[pid];\n                int oldL = cntLeft[pid];\n                int newL = oldL + 1;\n\n                addPieceState(hcur, overcur, s, oldL, -1);\n                addPieceState(hcur, overcur, s, newL, +1);\n                cntLeft[pid] = newL;\n            }\n\n            if (j < M) {\n                double lv = ord[j - 1].first;\n                double rv = ord[j].first;\n                if (rv - lv > EPS) {\n                    EvalKey key;\n                    key.F = calcF(hcur);\n                    key.def2 = calcDef2(hcur);\n                    key.active = M;\n                    key.waste = calcWaste(hcur);\n                    key.over = overcur;\n                    if (!found || betterKey(key, bestLocal)) {\n                        found = true;\n                        bestLocal = key;\n                        cLocal = (lv + rv) * 0.5;\n                    }\n                }\n            }\n            i = j;\n        }\n\n        if (!found) return false;\n        bestC = cLocal;\n        pred = bestLocal;\n        return true;\n    }\n\n    pair<Line, EvalKey> realizeThetaC(const State& st, double theta, double c,\n                                      vector<int>& L, vector<int>& R) const {\n        Line bestLn = makeLine(theta, c);\n        EvalKey bestEv = evalLine(st, bestLn, L, R);\n\n        int curAct = (int)st.active.size();\n        if (bestEv.active == curAct) return {bestLn, bestEv};\n\n        static const double off[6] = {1e-4, -1e-4, 5e-4, -5e-4, 2e-3, -2e-3};\n        for (double d : off) {\n            Line ln = makeLine(theta, c + d);\n            EvalKey ev = evalLine(st, ln, L, R);\n            if (betterKey(ev, bestEv)) {\n                bestEv = ev;\n                bestLn = ln;\n            }\n        }\n        return {bestLn, bestEv};\n    }\n\n    int pickPieceRandom(const State& st, XorShift64& rng, int minSize) const {\n        if (st.active.empty()) return -1;\n        int S = (int)st.active.size();\n        for (int t = 0; t < 30; t++) {\n            int idx = st.active[rng.nextInt(0, S - 1)];\n            int pid = st.pieceOf[idx];\n            if (st.pieceSize[pid] >= minSize) return pid;\n        }\n        int best = -1, bestSize = 0;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s >= minSize && s > bestSize) {\n                bestSize = s;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int chooseTargetPiece(const State& st) const {\n        int best = -1;\n        long long bestScore = -1;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s < 2) continue;\n\n            long long score;\n            if (s > 10) {\n                score = 1000000LL + 1000LL * s;\n            } else {\n                int overSup = max(0, st.h[s] - a[s]);\n                score = (long long)overSup * 10000LL + s;\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int pickDeficitSize(const State& st, XorShift64& rng) const {\n        int w[11];\n        int sumW = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - st.h[d]);\n            int wt = 1 + def * def * 3;\n            w[d] = wt;\n            sumW += wt;\n        }\n        int r = rng.nextInt(1, sumW);\n        for (int d = 1; d <= 10; d++) {\n            if (r <= w[d]) return d;\n            r -= w[d];\n        }\n        return 1;\n    }\n\n    bool calcPCA(const State& st, int pid, double& th1, double& th2) const {\n        const auto& pc = st.pieces[pid];\n        int s = (int)pc.size();\n        if (s < 2) return false;\n\n        long double mx = 0, my = 0;\n        for (int idx : pc) {\n            mx += pts[idx].x;\n            my += pts[idx].y;\n        }\n        mx /= s;\n        my /= s;\n\n        long double cxx = 0, cyy = 0, cxy = 0;\n        for (int idx : pc) {\n            long double dx = pts[idx].x - mx;\n            long double dy = pts[idx].y - my;\n            cxx += dx * dx;\n            cyy += dy * dy;\n            cxy += dx * dy;\n        }\n        if ((double)(cxx + cyy) < 1e-9) return false;\n\n        double ang = 0.5 * atan2((double)(2 * cxy), (double)(cxx - cyy));\n        th1 = normTheta(ang);\n        th2 = normTheta(ang + PI * 0.5);\n        return true;\n    }\n\n    Line lineByQuantile(const State& st, int pid, double theta, int t, vector<double>& buf) const {\n        const auto& vec = st.pieces[pid];\n        int s = (int)vec.size();\n        t = max(1, min(s - 1, t));\n\n        double nx = cos(theta), ny = sin(theta);\n        buf.clear();\n        buf.reserve(s);\n        for (int idx : vec) {\n            buf.push_back(nx * pts[idx].x + ny * pts[idx].y);\n        }\n\n        sort(buf.begin(), buf.end());\n        double l = buf[t - 1], r = buf[t];\n        double c = (l + r) * 0.5;\n        if (fabs(r - l) < 1e-12) c += 1e-6;\n        return makeLine(theta, c);\n    }\n\n    RunResult runOne(uint64_t seed, int runId, double runEnd) {\n        XorShift64 rng(seed);\n\n        State st;\n        st.pieceOf.assign(N, 0);\n        st.pieces.assign(1, {});\n        st.pieces[0].resize(N);\n        iota(st.pieces[0].begin(), st.pieces[0].end(), 0);\n        st.pieceSize.assign(1, N);\n        st.active = st.pieces[0];\n        st.h.fill(0);\n        if (1 <= N && N <= 10) st.h[N] = 1;\n        st.over = pen[N];\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n\n        int oriBase;\n        if (N >= 4500) oriBase = 8;\n        else if (N >= 3000) oriBase = 10;\n        else if (N >= 1800) oriBase = 12;\n        else oriBase = 14;\n\n        int qBase = (N >= 3500 ? 3 : 4);\n        int noImpLimit = (runId == 0 ? 13 : 10);\n        if (runId == 0) oriBase += 2;\n        if (runId >= 3) oriBase = max(6, oriBase - 2);\n\n        vector<int> L(max(1, N), 0), R(max(1, N), 0), cntLeft(max(1, N), 0);\n        vector<pair<double, int>> ord;\n        ord.reserve(max(1, N));\n        vector<double> projBuf;\n        projBuf.reserve(max(1, N));\n\n        int noImprove = 0;\n        double runBudget = runEnd - elapsed();\n\n        for (int iter = 0; iter < K * 3 && (int)st.lines.size() < K; iter++) {\n            if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n            if (st.active.empty()) break;\n            if (st.F >= totalA) break;\n\n            int step = (int)st.lines.size();\n            EvalKey cur = stateKey(st);\n\n            int targetPid = chooseTargetPiece(st);\n            bool hasPCA = false;\n            double pca1 = 0.0, pca2 = 0.0;\n            if (targetPid >= 0) hasPCA = calcPCA(st, targetPid, pca1, pca2);\n\n            double remRun = runEnd - elapsed();\n            int oriCnt = oriBase;\n            if (step < 6) oriCnt += 2;\n            if (noImprove >= 3) oriCnt += 3;\n            if (runBudget < 0.35 || remRun < 0.22) oriCnt = max(4, oriCnt - 4);\n            if (remRun < 0.12) oriCnt = max(3, oriCnt / 2);\n\n            int qCnt = qBase;\n            if (noImprove >= 3) qCnt += 1;\n            if (runBudget < 0.35 || remRun < 0.22) qCnt = max(1, qCnt - 2);\n            if (remRun < 0.12) qCnt = 1;\n\n            vector<double> thetas;\n            thetas.reserve(oriCnt + 10);\n\n            auto addTheta = [&](double th) {\n                thetas.push_back(normTheta(th));\n            };\n\n            if (hasPCA) {\n                addTheta(pca1);\n                addTheta(pca2);\n                addTheta(pca1 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n                addTheta(pca2 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n            }\n\n            int prevUse = min((int)st.lines.size(), 2);\n            for (int i = 0; i < prevUse; i++) {\n                const Line& pl = st.lines[(int)st.lines.size() - 1 - i];\n                double th = atan2((double)pl.dx, (double)(-pl.dy));\n                addTheta(th + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n                addTheta(th + PI * 0.5 + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n            }\n\n            while ((int)thetas.size() < oriCnt) {\n                addTheta(rng.nextDouble() * PI);\n            }\n            if ((int)thetas.size() > 24) thetas.resize(24);\n\n            EvalKey bestEv{-1, INT_MAX, -1, INT_MAX, BIG};\n            Line bestLn{};\n            bool found = false;\n\n            for (double th : thetas) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                double c = 0.0;\n                EvalKey pred;\n                if (!bestCutForTheta(st, th, c, pred, ord, cntLeft)) continue;\n                auto [ln, ev] = realizeThetaC(st, th, c, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int qi = 0; qi < qCnt; qi++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n\n                int pid = -1;\n                if (targetPid >= 0 && st.pieceSize[targetPid] >= 2 && rng.nextDouble() < 0.65) {\n                    pid = targetPid;\n                } else {\n                    pid = pickPieceRandom(st, rng, 2);\n                }\n                if (pid < 0) continue;\n\n                int s = st.pieceSize[pid];\n                if (s <= 1) continue;\n\n                int d = pickDeficitSize(st, rng);\n                vector<int> candT;\n                if (1 <= d && d < s) candT.push_back(d);\n                if (1 <= s - d && s - d < s) candT.push_back(s - d);\n\n                int mid = s / 2;\n                if (1 <= mid && mid < s) candT.push_back(mid);\n\n                int w = max(1, s / 6);\n                int tr = mid + rng.nextInt(-w, w);\n                tr = max(1, min(s - 1, tr));\n                candT.push_back(tr);\n\n                int t = candT[rng.nextInt(0, (int)candT.size() - 1)];\n\n                double th;\n                if (hasPCA && rng.nextDouble() < 0.55) {\n                    th = (rng.nextDouble() < 0.5 ? pca1 : pca2)\n                       + (rng.nextDouble() * 2.0 - 1.0) * 0.28;\n                } else {\n                    th = rng.nextDouble() * PI;\n                }\n                th = normTheta(th);\n\n                Line ln = lineByQuantile(st, pid, th, t, projBuf);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                Line ln = randomGlobalLine(rng);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            if (!found) break;\n\n            bool accept = betterKey(bestEv, cur);\n            if (!accept && noImprove >= 5) {\n                if (bestEv.F == cur.F &&\n                    bestEv.active == cur.active &&\n                    bestEv.def2 <= cur.def2 + 1 &&\n                    (bestEv.waste < cur.waste || bestEv.over < cur.over)) {\n                    accept = true;\n                }\n            }\n\n            if (accept) {\n                applyLine(st, bestLn);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= noImpLimit) break;\n            }\n        }\n\n        RunResult rr;\n        rr.lines = move(st.lines);\n        rr.key = stateKey(st);\n        return rr;\n    }\n\npublic:\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> K;\n        a.fill(0);\n        totalA = 0;\n        for (int d = 1; d <= 10; d++) {\n            cin >> a[d];\n            totalA += a[d];\n        }\n\n        pts.resize(N);\n        for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n        pen.assign(N + 1, 0);\n        for (int s = 0; s <= N; s++) {\n            if (s > 10) {\n                long long t = s - 10;\n                pen[s] = t * t;\n            }\n        }\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        uint64_t seedBase = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            v += 0x9e3779b97f4a7c15ULL;\n            v = (v ^ (v >> 30)) * 0xbf58476d1ce4e5b9ULL;\n            v = (v ^ (v >> 27)) * 0x94d049bb133111ebULL;\n            v ^= (v >> 31);\n            seedBase ^= v + 0x9e3779b97f4a7c15ULL + (seedBase << 6) + (seedBase >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)K);\n        for (int d = 1; d <= 10; d++) mix((uint64_t)a[d]);\n        for (const auto& p : pts) {\n            uint64_t v = ((uint64_t)(p.x + 20000) << 20) ^ (uint64_t)(p.y + 20000);\n            mix(v);\n        }\n\n        EvalKey bestKey{-1, INT_MAX, -1, INT_MAX, BIG};\n        vector<Line> bestLines;\n\n        int runId = 0;\n        while (true) {\n            double rem = TL - elapsed();\n            if (rem < 0.08) break;\n\n            double factor = (runId == 0 ? 0.58 : (runId < 3 ? 0.62 : 0.70));\n            double budget = rem * factor;\n            budget = max(0.14, budget);\n            budget = min(budget, rem - 0.03);\n            if (budget <= 0.02) break;\n\n            double runEnd = elapsed() + budget;\n            uint64_t seed = seedBase + 0x9e3779b97f4a7c15ULL * (uint64_t)(runId + 1);\n\n            RunResult rr = runOne(seed, runId, runEnd);\n            if (bestLines.empty() || betterKey(rr.key, bestKey)) {\n                bestKey = rr.key;\n                bestLines = move(rr.lines);\n            }\n\n            runId++;\n            if (bestKey.F >= totalA) break;\n        }\n\n        if (bestLines.empty()) {\n            cout << 0 << '\\n';\n            return;\n        }\n\n        cout << bestLines.size() << '\\n';\n        for (const auto& ln : bestLines) {\n            cout << ln.x1 << ' ' << ln.y1 << ' ' << ln.x2 << ' ' << ln.y2 << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(next() % (uint64_t)n); } // n > 0\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nclass Solver {\n    using Clock = chrono::steady_clock;\n\n    static constexpr int MAXN = 61;\n    static constexpr int MAXD = 121;\n\n    struct Point {\n        int x, y;\n    };\n    struct Move {\n        int x1, y1, x2, y2, x3, y3, x4, y4;\n    };\n    struct Candidate {\n        Move mv;\n        double val;\n        int w;\n        int L;\n    };\n    struct Core {\n        array<uint64_t, MAXN> row{}, col{}, usedH{}, usedV{};\n        array<uint64_t, MAXD> diagPos{}, diagNeg{}, usedPos{}, usedNeg{};\n        long long sumW = 0;\n        int dotCount = 0;\n    };\n\n    struct HeuParam {\n        // val = w - m*(a*L + b*L^2 + c*cong) + m*g*conn\n        double a0, a1;\n        double b0, b1;\n        double c0, c1; // congestion coeff\n        double g0, g1;\n        double m0, m1; // global penalty/bonus scale\n\n        bool stochastic;\n        int pickK;\n        int keep;\n    };\n\n    struct RunConfig {\n        HeuParam h;\n\n        bool lookahead;\n        int laSteps;\n        int laBranch;\n        int laDepth;   // 1 or 2\n        double laCoef;\n        double laDecay;\n        double laWmix; // rollout mixed score: (1-laWmix)*val + laWmix*w\n    };\n\n    struct RunResult {\n        long long sumW;\n        vector<Move> ops;\n    };\n\n    struct EliteRun {\n        long long sumW;\n        RunConfig cfg;\n        vector<Move> ops;\n    };\n\n    int N = 0, M = 0;\n    int off = 0;\n    int diagCnt = 0;\n    double density = 0.0;\n\n    vector<pair<int, int>> initDots;\n    int W[MAXN][MAXN]{};\n    vector<pair<int, int>> cellsByWeight;\n    uint64_t rangeMask[MAXN + 1][MAXN + 1]{};\n\n    double invDiagPos[MAXD]{}, invDiagNeg[MAXD]{};\n\n    static inline constexpr array<int, 8> pairU = {0, 1, 2, 3, 4, 5, 6, 7};\n    static inline constexpr array<int, 8> pairV = {1, 2, 3, 0, 5, 6, 7, 4};\n\n    static inline int ctz64(uint64_t v) { return __builtin_ctzll(v); }\n    static inline int msb64(uint64_t v) { return 63 - __builtin_clzll(v); }\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    double randRange(XorShift64 &rng, double lo, double hi) const {\n        return lo + (hi - lo) * rng.nextDouble();\n    }\n\n    // ~mean 0 noise\n    double normalish(XorShift64 &rng) const {\n        double z = 0.0;\n        for (int i = 0; i < 6; i++) z += rng.nextDouble();\n        return z - 3.0;\n    }\n\n    void buildTables() {\n        off = N - 1;\n        diagCnt = 2 * N - 1;\n\n        int c = (N - 1) / 2;\n        cellsByWeight.clear();\n        cellsByWeight.reserve(N * N);\n\n        for (int y = 0; y < N; y++) {\n            for (int x = 0; x < N; x++) {\n                int dx = x - c;\n                int dy = y - c;\n                W[y][x] = dx * dx + dy * dy + 1;\n                cellsByWeight.emplace_back(x, y);\n            }\n        }\n\n        sort(cellsByWeight.begin(), cellsByWeight.end(), [&](const auto &a, const auto &b) {\n            int wa = W[a.second][a.first];\n            int wb = W[b.second][b.first];\n            if (wa != wb) return wa > wb;\n            if (a.second != b.second) return a.second < b.second;\n            return a.first < b.first;\n        });\n\n        for (int l = 0; l <= N; l++) for (int r = 0; r <= N; r++) rangeMask[l][r] = 0;\n        for (int l = 0; l <= N; l++) {\n            uint64_t m = 0;\n            for (int r = l + 1; r <= N; r++) {\n                m |= (1ULL << (r - 1)); // [l, r)\n                rangeMask[l][r] = m;\n            }\n        }\n\n        for (int d = 0; d < diagCnt; d++) {\n            int k = d - off;\n            int len = N - abs(k);\n            int seg = max(1, len - 1);\n            invDiagPos[d] = 1.0 / (double)seg;\n        }\n        for (int s = 0; s < diagCnt; s++) {\n            int len = (s < N ? s + 1 : 2 * N - 1 - s);\n            int seg = max(1, len - 1);\n            invDiagNeg[s] = 1.0 / (double)seg;\n        }\n    }\n\n    inline bool hasDot(const Core &st, int x, int y) const {\n        return ((st.row[y] >> x) & 1ULL) != 0ULL;\n    }\n\n    inline void addDot(Core &st, int x, int y) const {\n        uint64_t bx = 1ULL << x;\n        st.row[y] |= bx;\n        st.col[x] |= (1ULL << y);\n        st.diagPos[x - y + off] |= bx;\n        st.diagNeg[x + y] |= bx;\n        st.dotCount++;\n    }\n\n    Point nearestDot(const Core &st, int x, int y, int dir) const {\n        uint64_t m = 0;\n        switch (dir) {\n            case 0: // E\n                m = st.row[y] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                return {ctz64(m), y};\n            case 1: // N\n                m = st.col[x] & (~0ULL << (y + 1));\n                if (!m) return {-1, -1};\n                return {x, ctz64(m)};\n            case 2: // W\n                m = st.row[y] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                return {msb64(m), y};\n            case 3: // S\n                m = st.col[x] & ((1ULL << y) - 1);\n                if (!m) return {-1, -1};\n                return {x, msb64(m)};\n            case 4: { // NE\n                int d = x - y + off;\n                m = st.diagPos[d] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                int k = d - off;\n                return {nx, nx - k};\n            }\n            case 5: { // NW\n                int s = x + y;\n                m = st.diagNeg[s] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                return {nx, s - nx};\n            }\n            case 6: { // SW\n                int d = x - y + off;\n                m = st.diagPos[d] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                int k = d - off;\n                return {nx, nx - k};\n            }\n            default: { // 7: SE\n                int s = x + y;\n                m = st.diagNeg[s] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                return {nx, s - nx};\n            }\n        }\n    }\n\n    inline bool edgeFree(const Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) {\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            return (st.usedV[x] & rangeMask[l][r]) == 0ULL;\n        }\n        if (y1 == y2) {\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedH[y] & rangeMask[l][r]) == 0ULL;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedPos[d] & rangeMask[l][r]) == 0ULL;\n        }\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        return (st.usedNeg[s] & rangeMask[l][r]) == 0ULL;\n    }\n\n    inline void useEdge(Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) {\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            st.usedV[x] |= rangeMask[l][r];\n            return;\n        }\n        if (y1 == y2) {\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedH[y] |= rangeMask[l][r];\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedPos[d] |= rangeMask[l][r];\n            return;\n        }\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        st.usedNeg[s] |= rangeMask[l][r];\n    }\n\n    inline void applyMove(Core &st, const Move &mv) const {\n        useEdge(st, mv.x1, mv.y1, mv.x2, mv.y2);\n        useEdge(st, mv.x2, mv.y2, mv.x3, mv.y3);\n        useEdge(st, mv.x3, mv.y3, mv.x4, mv.y4);\n        useEdge(st, mv.x4, mv.y4, mv.x1, mv.y1);\n        addDot(st, mv.x1, mv.y1);\n        st.sumW += W[mv.y1][mv.x1];\n    }\n\n    Core makeBaseState() const {\n        Core st;\n        for (auto [x, y] : initDots) {\n            if (!hasDot(st, x, y)) {\n                addDot(st, x, y);\n                st.sumW += W[y][x];\n            }\n        }\n        return st;\n    }\n\n    inline void evalCoeffs(const HeuParam &h, double progress,\n                           double &a, double &b, double &c, double &g, double &m) const {\n        a = h.a0 + (h.a1 - h.a0) * progress;\n        b = h.b0 + (h.b1 - h.b0) * progress;\n        c = h.c0 + (h.c1 - h.c0) * progress;\n        g = h.g0 + (h.g1 - h.g0) * progress;\n        m = h.m0 + (h.m1 - h.m0) * progress;\n\n        if (a < 0.0) a = 0.0;\n        if (b < 0.0) b = 0.0;\n        if (c < 0.0) c = 0.0;\n        if (g < 0.0) g = 0.0;\n        m = clampD(m, 0.0, 1.5);\n    }\n\n    inline bool betterCand(const Candidate &A, const Candidate &B) const {\n        if (A.val > B.val + 1e-9) return true;\n        if (A.val + 1e-9 < B.val) return false;\n        if (A.w != B.w) return A.w > B.w;\n        return A.L < B.L;\n    }\n\n    inline void buildOcc(const Core &st,\n                         double occH[MAXN], double occV[MAXN],\n                         double occP[MAXD], double occN[MAXD]) const {\n        double invHV = 1.0 / (double)max(1, N - 1);\n        for (int i = 0; i < N; i++) {\n            occH[i] = (double)__builtin_popcountll(st.usedH[i]) * invHV;\n            occV[i] = (double)__builtin_popcountll(st.usedV[i]) * invHV;\n        }\n        for (int d = 0; d < diagCnt; d++) {\n            occP[d] = (double)__builtin_popcountll(st.usedPos[d]) * invDiagPos[d];\n            occN[d] = (double)__builtin_popcountll(st.usedNeg[d]) * invDiagNeg[d];\n        }\n    }\n\n    inline double edgeOcc(int x1, int y1, int x2, int y2,\n                          const double occH[MAXN], const double occV[MAXN],\n                          const double occP[MAXD], const double occN[MAXD]) const {\n        if (x1 == x2) return occV[x1];\n        if (y1 == y2) return occH[y1];\n        if ((x2 - x1) == (y2 - y1)) return occP[x1 - y1 + off];\n        return occN[x1 + y1];\n    }\n\n    void findTopCandidates(const Core &st, double a, double b, double c, double g, double m,\n                           int keep, vector<Candidate> &out) const {\n        out.clear();\n        if (keep <= 0) return;\n        if ((int)out.capacity() < keep + 1) out.reserve(keep + 1);\n\n        array<Point, 8> near{};\n\n        bool useCong = (c > 1e-12);\n        double occH[MAXN], occV[MAXN], occP[MAXD], occN[MAXD];\n        if (useCong) buildOcc(st, occH, occV, occP, occN);\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n            if ((int)out.size() == keep) {\n                double ub = (double)w - m * (a * 2.0 + b * 4.0) + m * g * 8.0;\n                if (ub + 1e-9 < out.back().val) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n            if (conn < 2) continue;\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du], p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double cong = 0.0;\n                if (useCong) {\n                    double o12 = edgeOcc(x, y, p2.x, p2.y, occH, occV, occP, occN);\n                    double o23 = edgeOcc(p2.x, p2.y, x3, y3, occH, occV, occP, occN);\n                    double o34 = edgeOcc(x3, y3, p4.x, p4.y, occH, occV, occP, occN);\n                    double o41 = edgeOcc(p4.x, p4.y, x, y, occH, occV, occP, occN);\n                    cong = len1 * (o12 + o34) + len2 * (o23 + o41);\n                }\n\n                double val = (double)w - m * (a * (double)L + b * (double)L * (double)L + c * cong)\n                           + m * g * (double)conn;\n\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                int pos = 0;\n                while (pos < (int)out.size() && !betterCand(cand, out[pos])) pos++;\n                if (pos >= keep) continue;\n\n                out.insert(out.begin() + pos, cand);\n                if ((int)out.size() > keep) out.pop_back();\n            }\n        }\n    }\n\n    bool findBestCandidate(const Core &st, double a, double b, double c, double g, double m,\n                           Candidate &best) const {\n        bool found = false;\n        array<Point, 8> near{};\n\n        bool useCong = (c > 1e-12);\n        double occH[MAXN], occV[MAXN], occP[MAXD], occN[MAXD];\n        if (useCong) buildOcc(st, occH, occV, occP, occN);\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n            if (found) {\n                double ub = (double)w - m * (a * 2.0 + b * 4.0) + m * g * 8.0;\n                if (ub + 1e-9 < best.val) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n            if (conn < 2) continue;\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du], p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double cong = 0.0;\n                if (useCong) {\n                    double o12 = edgeOcc(x, y, p2.x, p2.y, occH, occV, occP, occN);\n                    double o23 = edgeOcc(p2.x, p2.y, x3, y3, occH, occV, occP, occN);\n                    double o34 = edgeOcc(x3, y3, p4.x, p4.y, occH, occV, occP, occN);\n                    double o41 = edgeOcc(p4.x, p4.y, x, y, occH, occV, occP, occN);\n                    cong = len1 * (o12 + o34) + len2 * (o23 + o41);\n                }\n\n                double val = (double)w - m * (a * (double)L + b * (double)L * (double)L + c * cong)\n                           + m * g * (double)conn;\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                if (!found || betterCand(cand, best)) {\n                    best = cand;\n                    found = true;\n                }\n            }\n        }\n\n        return found;\n    }\n\n    int pickRankedIndex(int k, XorShift64 &rng) const {\n        if (k <= 1) return 0;\n        int total = k * (k + 1) / 2;\n        int r = rng.nextInt(total);\n        for (int i = 0; i < k; i++) {\n            int wt = k - i;\n            if (r < wt) return i;\n            r -= wt;\n        }\n        return k - 1;\n    }\n\n    bool selectMove(const Core &st, const RunConfig &cfg, int moveCnt, int baseDotCount, int totalAddable,\n                    XorShift64 &rng, Clock::time_point deadline, Move &out, vector<Candidate> &cands) const {\n        double progress = (double)(st.dotCount - baseDotCount) / (double)max(1, totalAddable);\n\n        double a, b, c, g, m;\n        evalCoeffs(cfg.h, progress, a, b, c, g, m);\n\n        bool laPossible = cfg.lookahead && (moveCnt < cfg.laSteps);\n\n        int keep = cfg.h.keep;\n        if (!cfg.h.stochastic && !laPossible) keep = 1;\n        keep = max(keep, max(1, cfg.h.pickK));\n        if (laPossible) keep = max(keep, max(2, cfg.laBranch));\n        if (Clock::now() + chrono::milliseconds(2) >= deadline) keep = min(keep, 8);\n\n        findTopCandidates(st, a, b, c, g, m, keep, cands);\n        if (cands.empty()) return false;\n\n        int idx = 0;\n\n        bool doLA = laPossible && ((int)cands.size() >= 2);\n        if (doLA) {\n            int needMs = (cfg.laDepth >= 2 ? 5 : 3);\n            if (Clock::now() + chrono::milliseconds(needMs) >= deadline) doLA = false;\n            double margin = (cfg.laDepth >= 2 ? 125.0 : 100.0);\n            if (cands[0].val - cands[1].val > margin) doLA = false;\n        }\n\n        if (doLA) {\n            int B = min(cfg.laBranch, (int)cands.size());\n            vector<pair<double, int>> scored;\n            scored.reserve(B);\n\n            for (int i = 0; i < B; i++) {\n                if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n                Core tmp = st;\n                applyMove(tmp, cands[i].mv);\n\n                double score = (1.0 - cfg.laWmix) * cands[i].val + cfg.laWmix * (double)cands[i].w;\n                double coef = cfg.laCoef;\n\n                for (int dep = 0; dep < cfg.laDepth; dep++) {\n                    if (coef <= 1e-9) break;\n                    if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n                    double p2 = (double)(tmp.dotCount - baseDotCount) / (double)max(1, totalAddable);\n                    double a2, b2, c2, g2, m2;\n                    evalCoeffs(cfg.h, p2, a2, b2, c2, g2, m2);\n\n                    Candidate nxt;\n                    if (!findBestCandidate(tmp, a2, b2, c2, g2, m2, nxt)) break;\n\n                    double nxtScore = (1.0 - cfg.laWmix) * nxt.val + cfg.laWmix * (double)nxt.w;\n                    score += coef * nxtScore;\n                    applyMove(tmp, nxt.mv);\n                    coef *= cfg.laDecay;\n                }\n\n                scored.emplace_back(score, i);\n            }\n\n            if (!scored.empty()) {\n                sort(scored.begin(), scored.end(), [&](const auto &A, const auto &B) {\n                    return A.first > B.first;\n                });\n\n                if (cfg.h.stochastic) {\n                    int k = min(cfg.h.pickK, (int)scored.size());\n                    int r = pickRankedIndex(max(1, k), rng);\n                    idx = scored[r].second;\n                } else {\n                    idx = scored[0].second;\n                }\n            } else {\n                doLA = false;\n            }\n        }\n\n        if (!doLA) {\n            if (cfg.h.stochastic) {\n                int k = min(cfg.h.pickK, (int)cands.size());\n                idx = pickRankedIndex(max(1, k), rng);\n            } else {\n                idx = 0;\n            }\n        }\n\n        out = cands[idx].mv;\n        return true;\n    }\n\n    RunResult runFromState(Core st, vector<Move> ops, const RunConfig &cfg,\n                           int baseDotCount, int totalAddable,\n                           XorShift64 &rng, Clock::time_point deadline) const {\n        ops.reserve(ops.size() + max(0, N * N - st.dotCount));\n        vector<Candidate> cands;\n        cands.reserve(48);\n\n        int moveCnt = (int)ops.size();\n\n        while (true) {\n            if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n            Move mv;\n            if (!selectMove(st, cfg, moveCnt, baseDotCount, totalAddable, rng, deadline, mv, cands)) break;\n\n            applyMove(st, mv);\n            ops.push_back(mv);\n            moveCnt++;\n        }\n\n        return {st.sumW, move(ops)};\n    }\n\n    RunResult runOne(const Core &base, const RunConfig &cfg, XorShift64 &rng, Clock::time_point deadline) const {\n        vector<Move> empty;\n        int baseDotCount = base.dotCount;\n        int totalAddable = max(1, N * N - baseDotCount);\n        return runFromState(base, move(empty), cfg, baseDotCount, totalAddable, rng, deadline);\n    }\n\n    int familyOf(const RunConfig &cfg) const {\n        return (cfg.h.c0 + cfg.h.c1 <= 1e-12) ? 0 : 1;\n    }\n\n    void normalizeConfig(RunConfig &cfg, int remainMs) const {\n        cfg.h.a0 = clampD(cfg.h.a0, 0.0, 8.0);\n        cfg.h.a1 = clampD(cfg.h.a1, 0.0, 4.0);\n        cfg.h.b0 = clampD(cfg.h.b0, 0.0, 0.08);\n        cfg.h.b1 = clampD(cfg.h.b1, 0.0, 0.05);\n        cfg.h.c0 = clampD(cfg.h.c0, 0.0, 2.5);\n        cfg.h.c1 = clampD(cfg.h.c1, 0.0, 2.5);\n        cfg.h.g0 = clampD(cfg.h.g0, 0.0, 4.0);\n        cfg.h.g1 = clampD(cfg.h.g1, 0.0, 3.0);\n        cfg.h.m0 = clampD(cfg.h.m0, 0.0, 1.5);\n        cfg.h.m1 = clampD(cfg.h.m1, 0.0, 1.5);\n\n        cfg.h.pickK = clamp(cfg.h.pickK, 1, 10);\n        cfg.h.keep = clamp(cfg.h.keep, 1, 32);\n        if (!cfg.h.stochastic) cfg.h.pickK = 1;\n\n        if (remainMs < 950) cfg.lookahead = false;\n\n        if (cfg.lookahead) {\n            cfg.laSteps = clamp(cfg.laSteps, 20, 220);\n            cfg.laBranch = clamp(cfg.laBranch, 2, 6);\n            cfg.laDepth = clamp(cfg.laDepth, 1, 2);\n            cfg.laCoef = clampD(cfg.laCoef, 0.35, 1.20);\n            cfg.laDecay = clampD(cfg.laDecay, 0.35, 0.92);\n            cfg.laWmix = clampD(cfg.laWmix, 0.0, 0.5);\n\n            if (remainMs < 1500) cfg.laDepth = 1;\n            if (remainMs < 1200) cfg.laSteps = min(cfg.laSteps, 85);\n\n            cfg.h.keep = max(cfg.h.keep, cfg.laBranch);\n        } else {\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laDepth = 0;\n            cfg.laCoef = 0.0;\n            cfg.laDecay = 0.0;\n            cfg.laWmix = 0.0;\n        }\n\n        cfg.h.keep = max(cfg.h.keep, cfg.h.pickK);\n\n        if (remainMs < 560) {\n            cfg.lookahead = false;\n            cfg.h.keep = min(cfg.h.keep, 14);\n            cfg.h.pickK = min(cfg.h.pickK, 5);\n        }\n        if (remainMs < 320) {\n            cfg.h.keep = min(cfg.h.keep, 10);\n            cfg.h.pickK = min(cfg.h.pickK, 3);\n        }\n    }\n\n    RunConfig randomConfigFamily(XorShift64 &rng, int remainMs, int family) const {\n        RunConfig cfg{};\n\n        double densF = 1.0;\n        if (density < 0.040) densF = 1.15;\n        else if (density > 0.065) densF = 0.90;\n\n        double densC = 1.0;\n        if (density > 0.060) densC = 1.30;\n        else if (density < 0.040) densC = 0.80;\n\n        cfg.h.a0 = randRange(rng, 0.0, 6.0 * densF);\n        cfg.h.a1 = randRange(rng, 0.0, 2.6);\n        cfg.h.b0 = randRange(rng, 0.0, 0.044 * densF);\n        cfg.h.b1 = randRange(rng, 0.0, 0.023);\n        cfg.h.g0 = randRange(rng, 0.0, 2.4);\n        cfg.h.g1 = randRange(rng, 0.0, 1.4);\n        cfg.h.m0 = randRange(rng, 0.45, 1.15);\n        cfg.h.m1 = randRange(rng, 0.30, 1.05);\n\n        if (family == 0) {\n            cfg.h.c0 = 0.0;\n            cfg.h.c1 = 0.0;\n        } else {\n            cfg.h.c0 = randRange(rng, 0.10, 1.30 * densC);\n            cfg.h.c1 = randRange(rng, 0.03, 0.85 * densC);\n            if (rng.nextInt(100) < 8) {\n                cfg.h.c0 = 0.0;\n                cfg.h.c1 = 0.0;\n            }\n        }\n\n        if (rng.nextInt(5) == 0) swap(cfg.h.a0, cfg.h.a1);\n        if (rng.nextInt(6) == 0) swap(cfg.h.b0, cfg.h.b1);\n        if (rng.nextInt(7) == 0) swap(cfg.h.c0, cfg.h.c1);\n        if (rng.nextInt(5) == 0) swap(cfg.h.g0, cfg.h.g1);\n        if (rng.nextInt(7) == 0) swap(cfg.h.m0, cfg.h.m1);\n\n        cfg.h.stochastic = (rng.nextInt(100) < 90);\n        cfg.h.pickK = 2 + rng.nextInt(7); // 2..8\n        cfg.h.keep = 8 + rng.nextInt(16); // 8..23\n        if (!cfg.h.stochastic) {\n            cfg.h.pickK = 1;\n            cfg.h.keep = 1 + rng.nextInt(8);\n        }\n\n        bool allowLA = (remainMs > 1050 && rng.nextInt(100) < 16);\n        if (allowLA) {\n            cfg.lookahead = true;\n            cfg.laDepth = (rng.nextInt(100) < 28 ? 2 : 1);\n\n            if (cfg.laDepth == 2) {\n                cfg.laSteps = 26 + rng.nextInt(55);  // 26..80\n                cfg.laBranch = 3 + rng.nextInt(2);   // 3..4\n                cfg.laCoef = randRange(rng, 0.45, 0.80);\n                cfg.laDecay = randRange(rng, 0.45, 0.70);\n                cfg.laWmix = randRange(rng, 0.08, 0.25);\n            } else {\n                cfg.laSteps = 40 + rng.nextInt(91);  // 40..130\n                cfg.laBranch = 3 + rng.nextInt(3);   // 3..5\n                cfg.laCoef = randRange(rng, 0.55, 1.00);\n                cfg.laDecay = randRange(rng, 0.55, 0.86);\n                cfg.laWmix = randRange(rng, 0.05, 0.22);\n            }\n        } else {\n            cfg.lookahead = false;\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laDepth = 0;\n            cfg.laCoef = 0.0;\n            cfg.laDecay = 0.0;\n            cfg.laWmix = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    RunConfig mutateConfig(const RunConfig &baseCfg, XorShift64 &rng, int remainMs, int familyHint = -1) const {\n        RunConfig cfg = baseCfg;\n\n        auto madd = [&](double v, double sigma, double lo, double hi) {\n            v += normalish(rng) * sigma;\n            return clampD(v, lo, hi);\n        };\n\n        cfg.h.a0 = madd(cfg.h.a0, 0.80, 0.0, 8.0);\n        cfg.h.a1 = madd(cfg.h.a1, 0.45, 0.0, 4.0);\n        cfg.h.b0 = madd(cfg.h.b0, 0.007, 0.0, 0.08);\n        cfg.h.b1 = madd(cfg.h.b1, 0.004, 0.0, 0.05);\n        cfg.h.c0 = madd(cfg.h.c0, 0.14, 0.0, 2.5);\n        cfg.h.c1 = madd(cfg.h.c1, 0.10, 0.0, 2.5);\n        cfg.h.g0 = madd(cfg.h.g0, 0.35, 0.0, 4.0);\n        cfg.h.g1 = madd(cfg.h.g1, 0.25, 0.0, 3.0);\n        cfg.h.m0 = madd(cfg.h.m0, 0.10, 0.0, 1.5);\n        cfg.h.m1 = madd(cfg.h.m1, 0.10, 0.0, 1.5);\n\n        if (familyHint == 0) {\n            cfg.h.c0 = 0.0;\n            cfg.h.c1 = 0.0;\n        } else if (familyHint == 1) {\n            double densC = 1.0;\n            if (density > 0.060) densC = 1.30;\n            else if (density < 0.040) densC = 0.80;\n            if (cfg.h.c0 + cfg.h.c1 < 1e-8) {\n                cfg.h.c0 = randRange(rng, 0.12, 1.10 * densC);\n                cfg.h.c1 = randRange(rng, 0.03, 0.75 * densC);\n            }\n        } else {\n            if (rng.nextInt(100) < 10) {\n                cfg.h.c0 = 0.0;\n                cfg.h.c1 = 0.0;\n            }\n        }\n\n        if (rng.nextInt(100) < 9) cfg.h.stochastic = !cfg.h.stochastic;\n        cfg.h.pickK = clamp(cfg.h.pickK + (rng.nextInt(5) - 2), 1, 10);\n        cfg.h.keep = clamp(cfg.h.keep + (rng.nextInt(11) - 5), 1, 32);\n\n        if (remainMs < 950) {\n            cfg.lookahead = false;\n        } else {\n            if (rng.nextInt(100) < 9) cfg.lookahead = !cfg.lookahead;\n            if (!cfg.lookahead && remainMs > 1500 && rng.nextInt(100) < 14) cfg.lookahead = true;\n        }\n\n        if (cfg.lookahead) {\n            if (cfg.laDepth == 0) cfg.laDepth = 1;\n            if (cfg.laSteps == 0) cfg.laSteps = 70;\n            if (cfg.laBranch == 0) cfg.laBranch = 4;\n            if (cfg.laCoef == 0.0) cfg.laCoef = 0.75;\n            if (cfg.laDecay == 0.0) cfg.laDecay = 0.68;\n            if (cfg.laWmix == 0.0) cfg.laWmix = 0.12;\n\n            if (rng.nextInt(100) < 25) cfg.laDepth = clamp(cfg.laDepth + (rng.nextInt(3) - 1), 1, 2);\n            cfg.laSteps = clamp(cfg.laSteps + (rng.nextInt(61) - 30), 20, 220);\n            cfg.laBranch = clamp(cfg.laBranch + (rng.nextInt(3) - 1), 2, 6);\n            cfg.laCoef = clampD(cfg.laCoef + normalish(rng) * 0.08, 0.35, 1.20);\n            cfg.laDecay = clampD(cfg.laDecay + normalish(rng) * 0.08, 0.35, 0.92);\n            cfg.laWmix = clampD(cfg.laWmix + normalish(rng) * 0.04, 0.0, 0.5);\n        } else {\n            cfg.laDepth = 0;\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laCoef = 0.0;\n            cfg.laDecay = 0.0;\n            cfg.laWmix = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    RunConfig quickifyConfig(const RunConfig &baseCfg, XorShift64 &rng, int remainMs) const {\n        RunConfig cfg = baseCfg;\n        cfg.lookahead = false;\n        cfg.h.stochastic = true;\n        cfg.h.pickK = 2 + rng.nextInt(3); // 2..4\n        cfg.h.keep = max(cfg.h.pickK, 8 + rng.nextInt(6)); // 8..13\n        cfg.h.m0 = clampD(cfg.h.m0 + normalish(rng) * 0.06, 0.35, 1.2);\n        cfg.h.m1 = clampD(cfg.h.m1 + normalish(rng) * 0.06, 0.30, 1.1);\n\n        if (familyOf(cfg) == 0) {\n            cfg.h.c0 = 0.0;\n            cfg.h.c1 = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    void addEliteRun(vector<EliteRun> &elites, long long sumW, const RunConfig &cfg, const vector<Move> &ops) const {\n        const int LIM = 8;\n        if ((int)elites.size() == LIM && sumW <= elites.back().sumW) return;\n\n        int pos = 0;\n        while (pos < (int)elites.size() && elites[pos].sumW >= sumW) pos++;\n\n        EliteRun e;\n        e.sumW = sumW;\n        e.cfg = cfg;\n        e.ops = ops;\n\n        elites.insert(elites.begin() + pos, move(e));\n        if ((int)elites.size() > LIM) elites.pop_back();\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t seed = 1469598103934665603ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v;\n            seed *= 1099511628211ULL;\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        for (auto [x, y] : initDots) {\n            mix(((uint64_t)(uint32_t)x << 32) | (uint32_t)y);\n        }\n        return seed ? seed : 1ULL;\n    }\n\npublic:\n    void readInput() {\n        cin >> N >> M;\n        initDots.resize(M);\n        for (int i = 0; i < M; i++) {\n            int x, y;\n            cin >> x >> y;\n            initDots[i] = {x, y};\n        }\n        density = (double)M / (double)(N * N);\n        buildTables();\n    }\n\n    void solve() {\n        Core base = makeBaseState();\n        int baseDotCount = base.dotCount;\n        int totalAddable = max(1, N * N - baseDotCount);\n\n        long long bestSum = base.sumW;\n        vector<Move> bestOps;\n\n        vector<EliteRun> elitesAll;\n\n        XorShift64 rng(makeSeed());\n        auto deadline = Clock::now() + chrono::milliseconds(4740);\n\n        auto mk = [&](double a0, double a1, double b0, double b1, double c0, double c1,\n                      double g0, double g1, double m0, double m1,\n                      bool stochastic, int pickK, int keep,\n                      bool lookahead, int laSteps, int laBranch, int laDepth,\n                      double laCoef, double laDecay, double laWmix) {\n            RunConfig c;\n            c.h = {a0, a1, b0, b1, c0, c1, g0, g1, m0, m1, stochastic, pickK, keep};\n            c.lookahead = lookahead;\n            c.laSteps = laSteps;\n            c.laBranch = laBranch;\n            c.laDepth = laDepth;\n            c.laCoef = laCoef;\n            c.laDecay = laDecay;\n            c.laWmix = laWmix;\n            return c;\n        };\n\n        auto processResult = [&](RunResult &&rr, const RunConfig &cfgUsed) {\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = rr.ops;\n            }\n            addEliteRun(elitesAll, rr.sumW, cfgUsed, rr.ops);\n        };\n\n        auto runScratch = [&](RunConfig cfg) {\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            normalizeConfig(cfg, remain);\n            if (Clock::now() + chrono::milliseconds(6) >= deadline) return;\n            RunResult rr = runOne(base, cfg, rng, deadline);\n            processResult(move(rr), cfg);\n        };\n\n        auto runFromElitePrefix = [&](const EliteRun &er, int cut, RunConfig cfg) {\n            if (cut <= 0 || cut >= (int)er.ops.size()) {\n                runScratch(cfg);\n                return;\n            }\n\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            normalizeConfig(cfg, remain);\n            if (Clock::now() + chrono::milliseconds(6) >= deadline) return;\n\n            Core st = base;\n            vector<Move> pref;\n            pref.reserve(cut);\n            for (int i = 0; i < cut; i++) {\n                applyMove(st, er.ops[i]);\n                pref.push_back(er.ops[i]);\n            }\n\n            RunResult rr = runFromState(st, move(pref), cfg, baseDotCount, totalAddable, rng, deadline);\n            processResult(move(rr), cfg);\n        };\n\n        auto pickEliteIdx = [&](int family, int topCap) -> int {\n            vector<int> idxs;\n            idxs.reserve(elitesAll.size());\n            for (int i = 0; i < (int)elitesAll.size(); i++) {\n                if (family < 0 || familyOf(elitesAll[i].cfg) == family) {\n                    idxs.push_back(i);\n                    if ((int)idxs.size() >= topCap) break;\n                }\n            }\n            if (idxs.empty()) return -1;\n            int r = pickRankedIndex((int)idxs.size(), rng);\n            return idxs[r];\n        };\n\n        auto tryPrefix = [&](int family, bool quick) -> bool {\n            int idx = pickEliteIdx(family, quick ? 3 : 5);\n            if (idx < 0) return false;\n\n            const EliteRun &er = elitesAll[idx];\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n\n            RunConfig cfg = mutateConfig(er.cfg, rng, remain, familyOf(er.cfg));\n            if (quick) cfg = quickifyConfig(cfg, rng, remain);\n\n            int L = (int)er.ops.size();\n            if (L < 8) {\n                runScratch(cfg);\n                return true;\n            }\n\n            int lo = quick ? max(5, L * 28 / 100) : max(6, L * 20 / 100);\n            int hi = quick ? min(L - 1, L * 62 / 100) : min(L - 1, L * 80 / 100);\n            if (remain < 1300) hi = min(hi, max(lo, L * 58 / 100));\n            if (hi < lo) {\n                runScratch(cfg);\n                return true;\n            }\n\n            int cut = lo + (hi > lo ? rng.nextInt(hi - lo + 1) : 0);\n            runFromElitePrefix(er, cut, cfg);\n            return true;\n        };\n\n        // ---- Presets: keep legacy + congestion-aware ----\n        vector<RunConfig> presets;\n        // legacy\n        presets.push_back(mk(3.0, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0, 0, 0, 0));\n\n        // strong classic\n        presets.push_back(mk(2.5, 0.3, 0.010, 0.001, 0.0, 0.0, 1.2, 0.1, 0.95, 0.85, true, 4, 20, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(0.9, 0.0, 0.001, 0.0, 0.0, 0.0, 0.5, 0.0, 0.65, 0.50, true, 6, 24, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(4.4, 0.9, 0.020, 0.002, 0.0, 0.0, 1.8, 0.2, 1.0, 0.9, false, 1, 12, true, 90, 4, 1, 0.78, 0.70, 0.10));\n        presets.push_back(mk(3.6, 0.7, 0.015, 0.003, 0.0, 0.0, 1.2, 0.1, 0.95, 0.85, true, 3, 12, true, 45, 3, 2, 0.62, 0.62, 0.14));\n\n        // congestion-aware\n        presets.push_back(mk(4.8, 1.1, 0.022, 0.003, 0.70, 0.25, 1.3, 0.1, 1.0, 0.9, false, 1, 12, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(2.6, 0.4, 0.010, 0.001, 0.55, 0.15, 0.9, 0.1, 0.95, 0.80, true, 4, 16, true, 55, 3, 1, 0.66, 0.66, 0.10));\n        presets.push_back(mk(3.0, 0.5, 0.012, 0.002, 0.85, 0.25, 1.0, 0.1, 0.95, 0.82, true, 3, 14, true, 42, 3, 2, 0.56, 0.58, 0.12));\n\n        for (auto cfg : presets) {\n            if (Clock::now() + chrono::milliseconds(12) >= deadline) break;\n            runScratch(cfg);\n        }\n\n        // ---- Adaptive portfolio loop ----\n        while (Clock::now() + chrono::milliseconds(26) < deadline) {\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            int mode = rng.nextInt(100);\n\n            if (remain > 1900) {\n                if (mode < 18 && !elitesAll.empty()) {\n                    if (!tryPrefix(-1, false)) runScratch(randomConfigFamily(rng, remain, rng.nextInt(2)));\n                    continue;\n                }\n\n                if (mode < 56) {\n                    int ei = pickEliteIdx(0, 4);\n                    if (ei >= 0 && rng.nextInt(100) < 62) {\n                        RunConfig cfg = mutateConfig(elitesAll[ei].cfg, rng, remain, 0);\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, 0));\n                    }\n                } else {\n                    int ei = pickEliteIdx(1, 4);\n                    if (ei >= 0 && rng.nextInt(100) < 60) {\n                        RunConfig cfg = mutateConfig(elitesAll[ei].cfg, rng, remain, 1);\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, 1));\n                    }\n                }\n            } else if (remain > 1000) {\n                if (mode < 32 && !elitesAll.empty()) {\n                    if (!tryPrefix(-1, false)) runScratch(randomConfigFamily(rng, remain, rng.nextInt(2)));\n                } else if (mode < 76 && !elitesAll.empty()) {\n                    int ei = pickEliteIdx(-1, 5);\n                    if (ei >= 0) {\n                        int fam = familyOf(elitesAll[ei].cfg);\n                        RunConfig cfg = mutateConfig(elitesAll[ei].cfg, rng, remain, fam);\n                        if (rng.nextInt(100) < 25) cfg = quickifyConfig(cfg, rng, remain);\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, rng.nextInt(2)));\n                    }\n                } else {\n                    int fam = (rng.nextInt(100) < 50 ? 0 : 1);\n                    runScratch(randomConfigFamily(rng, remain, fam));\n                }\n            } else {\n                if (mode < 74 && !elitesAll.empty()) {\n                    if (!tryPrefix(-1, true)) {\n                        RunConfig cfg = quickifyConfig(randomConfigFamily(rng, remain, rng.nextInt(2)), rng, remain);\n                        runScratch(cfg);\n                    }\n                } else {\n                    int fam = (rng.nextInt(100) < 55 ? 0 : 1);\n                    RunConfig cfg = randomConfigFamily(rng, remain, fam);\n                    cfg = quickifyConfig(cfg, rng, remain);\n                    runScratch(cfg);\n                }\n            }\n        }\n\n        // ---- Final intensification from top elites (snapshot) ----\n        vector<EliteRun> finalSeeds = elitesAll;\n        if ((int)finalSeeds.size() > 3) finalSeeds.resize(3);\n\n        int cyc = 0;\n        while (!finalSeeds.empty() && Clock::now() + chrono::milliseconds(18) < deadline) {\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            const EliteRun &er = finalSeeds[cyc % finalSeeds.size()];\n            cyc++;\n\n            RunConfig cfg = mutateConfig(er.cfg, rng, remain, familyOf(er.cfg));\n            cfg = quickifyConfig(cfg, rng, remain);\n\n            int L = (int)er.ops.size();\n            if (L >= 10) {\n                static const int PCTS[4] = {30, 40, 50, 60};\n                int pct = PCTS[rng.nextInt(4)];\n                int cut = (int)((long long)L * pct / 100LL);\n                cut = clamp(cut, 6, L - 1);\n\n                Core st = base;\n                vector<Move> pref;\n                pref.reserve(cut);\n                for (int i = 0; i < cut; i++) {\n                    applyMove(st, er.ops[i]);\n                    pref.push_back(er.ops[i]);\n                }\n\n                RunResult rr = runFromState(st, move(pref), cfg, baseDotCount, totalAddable, rng, deadline);\n                if (rr.sumW > bestSum) {\n                    bestSum = rr.sumW;\n                    bestOps = move(rr.ops);\n                }\n            } else {\n                RunResult rr = runOne(base, cfg, rng, deadline);\n                if (rr.sumW > bestSum) {\n                    bestSum = rr.sumW;\n                    bestOps = move(rr.ops);\n                }\n            }\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (const auto &m : bestOps) {\n            cout << m.x1 << ' ' << m.y1 << ' '\n                 << m.x2 << ' ' << m.y2 << ' '\n                 << m.x3 << ' ' << m.y3 << ' '\n                 << m.x4 << ' ' << m.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int CELLS = 100;\nstatic constexpr double TIME_LIMIT = 1.92;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Board {\n    uint8_t a[CELLS];\n    int filled;\n};\n\nint FLV[101];\nint SUF[102][4];\nint NEI[CELLS][4];\n\ninline void init_neighbors() {\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int id = r * N + c;\n            NEI[id][0] = (r > 0) ? id - N : -1;      // F (up)\n            NEI[id][1] = (r + 1 < N) ? id + N : -1;  // B (down)\n            NEI[id][2] = (c > 0) ? id - 1 : -1;      // L\n            NEI[id][3] = (c + 1 < N) ? id + 1 : -1;  // R\n        }\n    }\n}\n\ninline void tilt(const Board& src, Board& dst, int dir) {\n    dst.filled = src.filled;\n    if (dir == 2) { // L\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = 0;\n            for (int c = 0; c < N; ++c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w++)] = v;\n            }\n            while (w < N) dst.a[base + (w++)] = 0;\n        }\n    } else if (dir == 3) { // R\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w--)] = v;\n            }\n            while (w >= 0) dst.a[base + (w--)] = 0;\n        }\n    } else if (dir == 0) { // F\n        for (int c = 0; c < N; ++c) {\n            int w = 0;\n            for (int r = 0; r < N; ++r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w++) * N + c] = v;\n            }\n            while (w < N) dst.a[(w++) * N + c] = 0;\n        }\n    } else { // B\n        for (int c = 0; c < N; ++c) {\n            int w = N - 1;\n            for (int r = N - 1; r >= 0; --r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w--) * N + c] = v;\n            }\n            while (w >= 0) dst.a[(w--) * N + c] = 0;\n        }\n    }\n}\n\ninline void place_by_rank(Board& b, int rank, uint8_t flavor) {\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            if (--rank == 0) {\n                b.a[i] = flavor;\n                ++b.filled;\n                return;\n            }\n        }\n    }\n    // fallback\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            b.a[i] = flavor;\n            ++b.filled;\n            return;\n        }\n    }\n}\n\ninline void comp_stats(const Board& b, int sq[4], int mx[4]) {\n    sq[0] = sq[1] = sq[2] = sq[3] = 0;\n    mx[0] = mx[1] = mx[2] = mx[3] = 0;\n\n    static uint32_t seen[CELLS];\n    static uint32_t stamp = 1;\n    ++stamp;\n    if (stamp == 0) {\n        memset(seen, 0, sizeof(seen));\n        stamp = 1;\n    }\n\n    int q[CELLS];\n    for (int i = 0; i < CELLS; ++i) {\n        uint8_t col = b.a[i];\n        if (col == 0 || seen[i] == stamp) continue;\n\n        seen[i] = stamp;\n        int head = 0, tail = 0;\n        q[tail++] = i;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            ++sz;\n            for (int k = 0; k < 4; ++k) {\n                int to = NEI[v][k];\n                if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                    seen[to] = stamp;\n                    q[tail++] = to;\n                }\n            }\n        }\n        sq[col] += sz * sz;\n        mx[col] = max(mx[col], sz);\n    }\n}\n\ninline int comp_sq_total(const Board& b) {\n    int sq[4], mx[4];\n    comp_stats(b, sq, mx);\n    return sq[1] + sq[2] + sq[3];\n}\n\ninline int same_adj_pairs(const Board& b) {\n    int adj = 0;\n    for (int r = 0; r < N; ++r) {\n        int base = r * N;\n        for (int c = 0; c < N; ++c) {\n            int id = base + c;\n            uint8_t v = b.a[id];\n            if (!v) continue;\n            if (c + 1 < N && b.a[id + 1] == v) ++adj;\n            if (r + 1 < N && b.a[id + N] == v) ++adj;\n        }\n    }\n    return adj;\n}\n\ninline long long state_score(const Board& b, int nextTurn) {\n    if (nextTurn < 1) nextTurn = 1;\n    if (nextTurn > 101) nextTurn = 101;\n\n    int sq[4], mx[4];\n    comp_stats(b, sq, mx);\n\n    long long totalSq = 1LL * sq[1] + sq[2] + sq[3];\n    long long score = 100LL * totalSq;\n\n    for (int f = 1; f <= 3; ++f) {\n        int rem = SUF[nextTurn][f];\n        score += 1LL * sq[f] * rem;\n        score += 2LL * mx[f] * rem;\n    }\n\n    if (nextTurn >= 70) score += 6LL * same_adj_pairs(b);\n    return score;\n}\n\ninline void greedy_tilt_step(Board& b, int turn) {\n    Board tmp, bestB;\n    long long bestVal = LLONG_MIN;\n    for (int d = 0; d < 4; ++d) {\n        tilt(b, tmp, d);\n        long long v = state_score(tmp, turn + 1);\n        if (v > bestVal) {\n            bestVal = v;\n            bestB = tmp;\n        }\n    }\n    b = bestB;\n}\n\ninline long long rollout_greedy(const Board& start, int t, int endTurn, const uint8_t ranks[101]) {\n    Board b = start;\n    for (int u = t + 1; u <= endTurn; ++u) {\n        place_by_rank(b, (int)ranks[u], (uint8_t)FLV[u]);\n        if (u < 100) greedy_tilt_step(b, u);\n    }\n    if (endTurn >= 100) return 100LL * comp_sq_total(b);\n    return state_score(b, endTurn + 1);\n}\n\ninline long long rollout_beam2(const Board& start, int t, int endTurn, const uint8_t ranks[101]) {\n    Board cur[2], cand[8], tmp;\n    long long candVal[8];\n    int curN = 1;\n    cur[0] = start;\n\n    for (int u = t + 1; u <= endTurn; ++u) {\n        for (int i = 0; i < curN; ++i) {\n            place_by_rank(cur[i], (int)ranks[u], (uint8_t)FLV[u]);\n        }\n        if (u == 100) break;\n\n        int candN = 0;\n        for (int i = 0; i < curN; ++i) {\n            for (int d = 0; d < 4; ++d) {\n                tilt(cur[i], tmp, d);\n                cand[candN] = tmp;\n                candVal[candN] = state_score(tmp, u + 1);\n                ++candN;\n            }\n        }\n\n        int keep = min(2, candN);\n        for (int k = 0; k < keep; ++k) {\n            int bi = k;\n            for (int j = k + 1; j < candN; ++j) {\n                if (candVal[j] > candVal[bi]) bi = j;\n            }\n            if (bi != k) {\n                swap(candVal[bi], candVal[k]);\n                swap(cand[bi], cand[k]);\n            }\n            cur[k] = cand[k];\n        }\n        curN = keep;\n    }\n\n    long long best = LLONG_MIN;\n    if (endTurn >= 100) {\n        for (int i = 0; i < curN; ++i) best = max(best, 100LL * comp_sq_total(cur[i]));\n    } else {\n        int nt = endTurn + 1;\n        for (int i = 0; i < curN; ++i) best = max(best, state_score(cur[i], nt));\n    }\n    return best;\n}\n\ndouble exact_expect(const Board& b, int nextTurn) {\n    // board state before placing candy nextTurn\n    if (nextTurn == 101) return (double)comp_sq_total(b);\n\n    int empties = 101 - nextTurn;\n    double sum = 0.0;\n\n    for (int p = 1; p <= empties; ++p) {\n        Board placed = b;\n        place_by_rank(placed, p, (uint8_t)FLV[nextTurn]);\n\n        if (nextTurn == 100) {\n            sum += (double)comp_sq_total(placed);\n        } else {\n            double best = -1e100;\n            Board nxt;\n            for (int d = 0; d < 4; ++d) {\n                tilt(placed, nxt, d);\n                double v = exact_expect(nxt, nextTurn + 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n    }\n    return sum / (double)empties;\n}\n\nbool one_step_prior(\n    const Board first[4], int t, XorShift& rng, const Timer& timer, double softDeadline, long double out[4]\n) {\n    int u = t + 1;\n    if (u > 100) return false;\n    int empties = 100 - t;\n\n    int L;\n    bool exact = false;\n    if (empties <= 12) {\n        L = empties;\n        exact = true;\n    } else if (empties <= 30) {\n        L = 12;\n    } else {\n        L = 8;\n    }\n\n    static int sample[100];\n    if (exact) {\n        for (int i = 0; i < L; ++i) sample[i] = i + 1;\n    } else {\n        static int ord[100];\n        for (int i = 0; i < empties; ++i) ord[i] = i + 1;\n        for (int i = 0; i < L; ++i) {\n            int j = rng.next_int(i, empties - 1);\n            swap(ord[i], ord[j]);\n            sample[i] = ord[i];\n        }\n    }\n\n    Board b, tmp;\n    for (int d = 0; d < 4; ++d) {\n        long long acc = 0;\n        for (int i = 0; i < L; ++i) {\n            if ((i & 3) == 0 && timer.elapsed() > softDeadline) return false;\n\n            b = first[d];\n            place_by_rank(b, sample[i], (uint8_t)FLV[u]);\n\n            long long v;\n            if (u == 100) {\n                v = 100LL * comp_sq_total(b);\n            } else {\n                long long best = LLONG_MIN;\n                for (int d2 = 0; d2 < 4; ++d2) {\n                    tilt(b, tmp, d2);\n                    best = max(best, state_score(tmp, u + 1));\n                }\n                v = best;\n            }\n            acc += v;\n        }\n        out[d] = (long double)acc / (long double)L;\n    }\n    return true;\n}\n\nint choose_move(const Board& cur, int t, XorShift& rng, const Timer& timer) {\n    int rem = 100 - t;\n    if (rem <= 0) return 0;\n\n    Board first[4];\n    long long firstV[4];\n    for (int d = 0; d < 4; ++d) {\n        tilt(cur, first[d], d);\n        firstV[d] = state_score(first[d], t + 1);\n    }\n\n    int bestImmediate = 0;\n    for (int d = 1; d < 4; ++d) if (firstV[d] > firstV[bestImmediate]) bestImmediate = d;\n\n    double now = timer.elapsed();\n    double timeLeft = TIME_LIMIT - now;\n    if (timeLeft < 0.010) return bestImmediate;\n\n    // exact endgame\n    if (rem <= 5 && timeLeft > 0.090) {\n        int bestDir = bestImmediate;\n        double bestVal = -1e100;\n        for (int d = 0; d < 4; ++d) {\n            double v = exact_expect(first[d], t + 1);\n            if (v > bestVal + 1e-12 ||\n                (fabs(v - bestVal) <= 1e-12 && firstV[d] > firstV[bestDir])) {\n                bestVal = v;\n                bestDir = d;\n            }\n        }\n        return bestDir;\n    }\n\n    if (now >= TIME_LIMIT - 0.003) return bestImmediate;\n\n    // time budget\n    double reserve = 0.055;\n    double freeTime = timeLeft - reserve;\n    if (freeTime <= 0.0) return bestImmediate;\n\n    double base = freeTime / (rem + 1);\n    double phase;\n    if (rem >= 70) phase = 0.60;\n    else if (rem >= 45) phase = 0.92;\n    else if (rem >= 25) phase = 1.28;\n    else phase = 1.70;\n\n    double budget = base * phase;\n    budget = max(0.0010, min(0.042, budget));\n\n    // ambiguity correction using immediate scores\n    int b1 = 0, b2 = 1;\n    if (firstV[b2] > firstV[b1]) swap(b1, b2);\n    for (int d = 2; d < 4; ++d) {\n        if (firstV[d] > firstV[b1]) {\n            b2 = b1;\n            b1 = d;\n        } else if (firstV[d] > firstV[b2]) {\n            b2 = d;\n        }\n    }\n    long long gap = firstV[b1] - firstV[b2];\n    long long absTop = llabs(firstV[b1]) + 1;\n    if (gap * 45LL < absTop) budget *= 1.20;\n    else if (gap * 18LL > absTop) budget *= 0.88;\n\n    budget = min(budget, freeTime * 0.92);\n    if (budget < 0.0010) return bestImmediate;\n\n    double deadline = min(TIME_LIMIT - 0.0015, timer.elapsed() + budget);\n\n    // horizon\n    int H;\n    if (rem >= 70) H = 8;\n    else if (rem >= 52) H = 11;\n    else if (rem >= 36) H = 14;\n    else if (rem >= 24) H = 18;\n    else H = rem;\n\n    if (budget < 0.0034) H = min(H, 12);\n    if (budget < 0.0025) H = min(H, 9);\n    H = max(1, min(H, rem));\n\n    int endTurn = t + H;\n\n    long double total[4];\n    for (int d = 0; d < 4; ++d) total[d] = 0.90L * (long double)firstV[d];\n\n    // one-step prior\n    if (rem <= 58 && budget >= 0.0030) {\n        long double prior[4];\n        double pd = min(deadline, timer.elapsed() + min(0.22 * budget, 0.0045));\n        if (one_step_prior(first, t, rng, timer, pd, prior)) {\n            long double w;\n            if (rem <= 18) w = 1.55L;\n            else if (rem <= 35) w = 1.30L;\n            else w = 1.05L;\n            for (int d = 0; d < 4; ++d) total[d] += w * prior[d];\n        }\n    }\n\n    bool useBeam2 = (rem <= 14 && budget >= 0.0070);\n\n    int minScen = (budget >= 0.0045 ? 2 : 1);\n    int maxScen = (useBeam2 ? 96 : 240);\n\n    static uint8_t ranksA[101], ranksB[101];\n    int scen = 0;\n\n    auto eval_one = [&](const uint8_t ranks[101]) {\n        for (int d = 0; d < 4; ++d) {\n            long long v = useBeam2\n                ? rollout_beam2(first[d], t, endTurn, ranks)\n                : rollout_greedy(first[d], t, endTurn, ranks);\n            total[d] += (long double)v;\n        }\n    };\n\n    while (scen < maxScen) {\n        if (scen >= minScen && timer.elapsed() > deadline) break;\n\n        for (int u = t + 1; u <= endTurn; ++u) {\n            int R = 101 - u;\n            int ra = rng.next_int(1, R);\n            ranksA[u] = (uint8_t)ra;\n            ranksB[u] = (uint8_t)(R + 1 - ra); // antithetic\n        }\n\n        eval_one(ranksA);\n        ++scen;\n        if (scen >= maxScen) break;\n\n        if (scen >= minScen && timer.elapsed() > deadline) break;\n        eval_one(ranksB);\n        ++scen;\n    }\n\n    int bestDir = 0;\n    for (int d = 1; d < 4; ++d) {\n        if (total[d] > total[bestDir] + 1e-12L ||\n            (fabsl(total[d] - total[bestDir]) <= 1e-12L && firstV[d] > firstV[bestDir])) {\n            bestDir = d;\n        }\n    }\n    return bestDir;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 1; i <= 100; ++i) {\n        if (!(cin >> FLV[i])) return 0;\n    }\n\n    for (int c = 1; c <= 3; ++c) SUF[101][c] = 0;\n    for (int t = 100; t >= 1; --t) {\n        for (int c = 1; c <= 3; ++c) SUF[t][c] = SUF[t + 1][c];\n        SUF[t][FLV[t]]++;\n    }\n\n    init_neighbors();\n\n    uint64_t seed = 1469598103934665603ull;\n    for (int i = 1; i <= 100; ++i) {\n        seed ^= (uint64_t)(FLV[i] + 131 * i);\n        seed *= 1099511628211ull;\n    }\n    XorShift rng(seed);\n    Timer timer;\n\n    Board cur{};\n    memset(cur.a, 0, sizeof(cur.a));\n    cur.filled = 0;\n\n    for (int t = 1; t <= 100; ++t) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        place_by_rank(cur, p, (uint8_t)FLV[t]);\n\n        int dir = 0; // F\n        if (t < 100) {\n            dir = choose_move(cur, t, rng, timer);\n            Board nxt;\n            tilt(cur, nxt, dir);\n            cur = nxt;\n        }\n\n        cout << DIR_CH[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    inline 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    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline uint64_t prob_to_u64(double p) {\n    if (p <= 0.0) return 0ULL;\n    if (p >= 1.0) return numeric_limits<uint64_t>::max();\n    long double v = p * (long double)numeric_limits<uint64_t>::max();\n    if (v < 0) v = 0;\n    if (v > (long double)numeric_limits<uint64_t>::max()) v = (long double)numeric_limits<uint64_t>::max();\n    return (uint64_t)v;\n}\n\nstruct Sig3 {\n    int d, n1, n2;\n    bool operator<(const Sig3& o) const {\n        if (d != o.d) return d < o.d;\n        if (n1 != o.n1) return n1 < o.n1;\n        return n2 < o.n2;\n    }\n};\n\nstruct Graph {\n    vector<uint8_t> bits; // length L\n    vector<int> deg_sorted;\n    vector<int> nd_sorted;\n    vector<int> nd2_sorted;\n    int edges = 0;\n    int uniq_sig = 0;\n};\n\nstruct Codebook {\n    int N = 0;\n    int L = 0;\n    int B = 0;\n    int FB = 0;\n    int distinct = 0;\n\n    vector<int> eu, ev;        // edge endpoints by lex order\n    vector<int> pairId;        // size B*B\n    vector<int> blockCap;      // size FB\n    vector<Graph> graphs;      // size M\n};\n\nstruct FeatureWork {\n    vector<int> deg, nd, nd2;\n    vector<int> ord, bin;\n    vector<uint64_t> key;      // random tiebreak keys\n    vector<uint8_t> bits;      // noisy sampled bits\n\n    FeatureWork() {}\n    FeatureWork(int N, int L) { init(N, L); }\n\n    void init(int N, int L) {\n        deg.assign(N, 0);\n        nd.assign(N, 0);\n        nd2.assign(N, 0);\n        ord.resize(N);\n        bin.assign(N, 0);\n        key.assign(N, 0);\n        bits.assign(L, 0);\n    }\n};\n\nstruct ProtoBank {\n    int M = 0, N = 0, S = 0, FB = 0;\n    // samples\n    vector<int16_t> sdeg;   // M*S*N\n    vector<int32_t> snd;    // M*S*N\n    vector<int32_t> snd2;   // M*S*N\n    vector<uint16_t> sblk;  // M*S*FB\n\n    // centers\n    vector<float> cdeg;     // M*N\n    vector<float> cnd;      // M*N\n    vector<float> cnd2;     // M*N\n    vector<float> cblk;     // M*FB\n\n    // inverse variances (global)\n    double invD = 1.0;\n    double invN1 = 1.0;\n    double invN2 = 1.0;\n    vector<double> invB;    // FB\n};\n\nstruct DecodeParam {\n    double m1 = 1.0;    // nd multiplier\n    double m2 = 0.0;    // nd2 multiplier\n    double mB = 0.0;    // block multiplier\n\n    double a1 = 0.7;    // min1 sample weight\n    double a2 = 0.1;    // min2 sample weight\n    double a3 = 0.2;    // center weight\n    bool useSecond = true;\n    string name;\n};\n\nstatic inline uint64_t fnv_mix(uint64_t h, uint64_t x) {\n    h ^= x;\n    h *= 1099511628211ULL;\n    return h;\n}\n\nuint64_t hash_sorted3(const vector<int>& a, const vector<int>& b, const vector<int>& c) {\n    uint64_t h = 1469598103934665603ULL;\n    int n = (int)a.size();\n    for (int i = 0; i < n; i++) {\n        h = fnv_mix(h, (uint64_t)(a[i] + 1));\n        h = fnv_mix(h, (uint64_t)(b[i] + 10007));\n        h = fnv_mix(h, (uint64_t)(c[i] + 1000003));\n    }\n    return h;\n}\n\nuint64_t hash_signature(const Graph& g) {\n    uint64_t h = 1469598103934665603ULL;\n    h = fnv_mix(h, (uint64_t)(g.edges + 1));\n    h = fnv_mix(h, (uint64_t)(g.uniq_sig + 3));\n    int n = (int)g.deg_sorted.size();\n    for (int i = 0; i < n; i++) {\n        h = fnv_mix(h, (uint64_t)(g.deg_sorted[i] + 1));\n        h = fnv_mix(h, (uint64_t)(g.nd_sorted[i] + 10007));\n        h = fnv_mix(h, (uint64_t)(g.nd2_sorted[i] + 1000003));\n    }\n    return h;\n}\n\nvoid build_edges(int N, vector<int>& eu, vector<int>& ev) {\n    eu.clear();\n    ev.clear();\n    eu.reserve(N * (N - 1) / 2);\n    ev.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            eu.push_back(i);\n            ev.push_back(j);\n        }\n    }\n}\n\nint choose_bins(int N) {\n    if (N <= 10) return 3;\n    if (N <= 16) return 4;\n    if (N <= 25) return 5;\n    if (N <= 40) return 6;\n    if (N <= 64) return 8;\n    return 10;\n}\n\nvoid init_block_meta(Codebook& cb) {\n    cb.B = choose_bins(cb.N);\n    cb.FB = cb.B * (cb.B + 1) / 2;\n    cb.pairId.assign(cb.B * cb.B, -1);\n    cb.blockCap.assign(cb.FB, 0);\n\n    vector<int> sz(cb.B);\n    for (int b = 0; b < cb.B; b++) {\n        int l = (long long)b * cb.N / cb.B;\n        int r = (long long)(b + 1) * cb.N / cb.B;\n        sz[b] = r - l;\n    }\n\n    int id = 0;\n    for (int i = 0; i < cb.B; i++) {\n        for (int j = i; j < cb.B; j++) {\n            cb.pairId[i * cb.B + j] = id;\n            cb.pairId[j * cb.B + i] = id;\n            int cap = (i == j) ? (sz[i] * (sz[i] - 1) / 2) : (sz[i] * sz[j]);\n            cb.blockCap[id] = cap;\n            id++;\n        }\n    }\n}\n\nGraph make_graph_from_bits(vector<uint8_t>&& bits, int N, const vector<int>& eu, const vector<int>& ev) {\n    Graph g;\n    g.bits = std::move(bits);\n    int L = (int)eu.size();\n\n    vector<int> deg(N, 0), nd(N, 0), nd2(N, 0);\n    g.edges = 0;\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            g.edges++;\n            int u = eu[e], v = ev[e];\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd[u] += deg[v];\n            nd[v] += deg[u];\n        }\n    }\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd2[u] += nd[v];\n            nd2[v] += nd[u];\n        }\n    }\n\n    vector<Sig3> sig(N);\n    for (int i = 0; i < N; i++) sig[i] = {deg[i], nd[i], nd2[i]};\n    sort(sig.begin(), sig.end());\n\n    g.deg_sorted.resize(N);\n    g.nd_sorted.resize(N);\n    g.nd2_sorted.resize(N);\n    g.uniq_sig = 0;\n    for (int i = 0; i < N; i++) {\n        g.deg_sorted[i] = sig[i].d;\n        g.nd_sorted[i] = sig[i].n1;\n        g.nd2_sorted[i] = sig[i].n2;\n        if (i == 0 || sig[i].d != sig[i - 1].d || sig[i].n1 != sig[i - 1].n1 || sig[i].n2 != sig[i - 1].n2) {\n            g.uniq_sig++;\n        }\n    }\n    return g;\n}\n\nvector<int> random_group_ids(int N, int K, RNG& rng) {\n    K = min(K, N);\n    vector<int> sz(K, 1);\n    int rem = N - K;\n    for (int i = 0; i < rem; i++) sz[rng.next_int(0, K - 1)]++;\n\n    vector<int> gid;\n    gid.reserve(N);\n    for (int g = 0; g < K; g++) {\n        for (int c = 0; c < sz[g]; c++) gid.push_back(g);\n    }\n    for (int i = N - 1; i >= 1; i--) {\n        int j = rng.next_int(0, i);\n        swap(gid[i], gid[j]);\n    }\n    return gid;\n}\n\nint pick_mode(double eps, RNG& rng) {\n    double r = rng.next_double();\n    if (eps >= 0.28) {\n        // More random/threshold-like for high noise\n        if (r < 0.25) return 0;   // ER\n        if (r < 0.45) return 4;   // sum threshold\n        if (r < 0.63) return 5;   // product threshold\n        if (r < 0.78) return 6;   // interval\n        if (r < 0.90) return 7;   // xor partitions\n        if (r < 0.97) return 9;   // hub threshold\n        return 8;                 // threshold insertion\n    } else if (eps >= 0.15) {\n        if (r < 0.18) return 0;\n        if (r < 0.32) return 1;\n        if (r < 0.44) return 2;\n        if (r < 0.56) return 3;\n        if (r < 0.68) return 4;\n        if (r < 0.78) return 5;\n        if (r < 0.87) return 6;\n        if (r < 0.94) return 7;\n        if (r < 0.97) return 8;\n        return 9;\n    } else {\n        return rng.next_int(0, 9);\n    }\n}\n\nGraph generate_candidate_graph(int N, const vector<int>& eu, const vector<int>& ev, RNG& rng, double eps) {\n    int L = (int)eu.size();\n    vector<uint8_t> bits(L, 0);\n\n    int mode = pick_mode(eps, rng);\n\n    if (mode == 0) {\n        // ER (biased to extremes)\n        double u = rng.next_double();\n        double p = (rng.next_double() < 0.5) ? (u * u) : (1.0 - (1.0 - u) * (1.0 - u));\n        uint64_t th = prob_to_u64(p);\n        for (int e = 0; e < L; e++) bits[e] = (rng.next_u64() < th);\n    } else if (mode == 1) {\n        // Binary SBM\n        int K = rng.next_int(2, min(10, N));\n        auto gid = random_group_ids(N, K, rng);\n        vector<vector<uint8_t>> B(K, vector<uint8_t>(K, 0));\n        for (int i = 0; i < K; i++) {\n            for (int j = i; j < K; j++) {\n                uint8_t x = (uint8_t)(rng.next_u64() & 1ULL);\n                B[i][j] = B[j][i] = x;\n            }\n        }\n        for (int e = 0; e < L; e++) bits[e] = B[gid[eu[e]]][gid[ev[e]]];\n    } else if (mode == 2) {\n        // Union of cliques\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] == gid[ev[e]]);\n    } else if (mode == 3) {\n        // Complete multipartite\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] != gid[ev[e]]);\n    } else if (mode == 4) {\n        // Sum threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 2000);\n        for (int e = 0; e < L; e++) bits[e] = (w[eu[e]] + w[ev[e]] >= th);\n    } else if (mode == 5) {\n        // Product threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000000);\n        for (int e = 0; e < L; e++) {\n            long long v = 1LL * w[eu[e]] * w[ev[e]];\n            bits[e] = (v >= th);\n        }\n    } else if (mode == 6) {\n        // Interval/circle graph\n        vector<double> x(N);\n        for (int i = 0; i < N; i++) x[i] = rng.next_double();\n        bool circle = (rng.next_u64() & 1ULL);\n        double th = rng.next_double() * 0.85;\n        for (int e = 0; e < L; e++) {\n            double d = fabs(x[eu[e]] - x[ev[e]]);\n            if (circle) d = min(d, 1.0 - d);\n            bits[e] = (d <= th);\n        }\n    } else if (mode == 7) {\n        // XOR of two partitions\n        int K1 = rng.next_int(2, min(7, N));\n        int K2 = rng.next_int(2, min(7, N));\n        auto g1 = random_group_ids(N, K1, rng);\n        auto g2 = random_group_ids(N, K2, rng);\n        for (int e = 0; e < L; e++) {\n            bool a = (g1[eu[e]] == g1[ev[e]]);\n            bool b = (g2[eu[e]] == g2[ev[e]]);\n            bits[e] = (uint8_t)(a ^ b);\n        }\n    } else if (mode == 8) {\n        // Threshold insertion style\n        vector<uint8_t> dom(N, 0);\n        double p1 = 0.15 + 0.7 * rng.next_double();\n        for (int i = 1; i < N; i++) dom[i] = (uint8_t)(rng.next_double() < p1);\n        for (int e = 0; e < L; e++) bits[e] = dom[ev[e]];\n    } else {\n        // Hub threshold\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000);\n        for (int e = 0; e < L; e++) bits[e] = (max(w[eu[e]], w[ev[e]]) >= th);\n    }\n\n    // occasional complement\n    if (rng.next_double() < 0.08) {\n        for (int e = 0; e < L; e++) bits[e] ^= 1;\n    }\n\n    // small perturbation\n    double pmax = (eps >= 0.25 ? 0.05 : 0.07);\n    if (rng.next_double() < 0.85) {\n        double pf = rng.next_double() * pmax;\n        uint64_t th = prob_to_u64(pf);\n        for (int e = 0; e < L; e++) {\n            if (rng.next_u64() < th) bits[e] ^= 1;\n        }\n    }\n\n    return make_graph_from_bits(std::move(bits), N, eu, ev);\n}\n\nCodebook build_codebook(int N, int M, double eps, int C, RNG& rng) {\n    Codebook cb;\n    cb.N = N;\n    build_edges(N, cb.eu, cb.ev);\n    cb.L = (int)cb.eu.size();\n    init_block_meta(cb);\n\n    vector<Graph> cand;\n    cand.reserve(C);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve((size_t)C * 3);\n\n    int attempts = 0;\n    int maxAttempts = C * 30;\n\n    while ((int)cand.size() < C && attempts < maxAttempts) {\n        Graph g = generate_candidate_graph(N, cb.eu, cb.ev, rng, eps);\n\n        if (eps >= 0.22) {\n            int th = (eps >= 0.30 ? max(3, N / 4) : max(3, N / 6));\n            if (g.uniq_sig < th && rng.next_double() < 0.75) {\n                attempts++;\n                continue;\n            }\n        }\n\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        attempts++;\n    }\n\n    // fallback: edge-prefix\n    for (int m = 0; (int)cand.size() < C && m <= cb.L; m++) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < m; e++) bits[e] = 1;\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n    }\n\n    // fallback: random bits\n    int extra = 0;\n    while ((int)cand.size() < C && extra < C * 10) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < cb.L; e++) bits[e] = (uint8_t)(rng.next_u64() & 1ULL);\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        extra++;\n    }\n\n    if (cand.empty()) {\n        vector<uint8_t> bits(cb.L, 0);\n        cand.push_back(make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev));\n    }\n\n    int Cn = (int)cand.size();\n\n    // Distance in sorted-feature space\n    double a = max(0.0, 1.0 - 2.0 * eps);\n    double w1 = (0.04 + 1.0 * a * a) / ((double)N * N);\n    double w2 = (eps < 0.25 ? (0.002 + 0.3 * a * a * a * a) / ((double)N * N * N * N) : 0.0);\n\n    auto dist_idx = [&](int ia, int ib) -> double {\n        const auto& A = cand[ia];\n        const auto& B = cand[ib];\n        double s = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)A.deg_sorted[i] - (double)B.deg_sorted[i];\n            s += d * d;\n        }\n        if (w1 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd_sorted[i] - (double)B.nd_sorted[i];\n                s += w1 * d * d;\n            }\n        }\n        if (w2 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd2_sorted[i] - (double)B.nd2_sorted[i];\n                s += w2 * d * d;\n            }\n        }\n        return s;\n    };\n\n    vector<int> selected;\n    selected.reserve(M);\n    vector<char> used(Cn, false);\n\n    int imin = 0, imax = 0;\n    for (int i = 1; i < Cn; i++) {\n        if (cand[i].edges < cand[imin].edges) imin = i;\n        if (cand[i].edges > cand[imax].edges) imax = i;\n    }\n    selected.push_back(imin);\n    used[imin] = true;\n    if ((int)selected.size() < M && imax != imin) {\n        selected.push_back(imax);\n        used[imax] = true;\n    }\n\n    vector<double> minDist(Cn, 1e300);\n    for (int i = 0; i < Cn; i++) {\n        double d = 1e300;\n        for (int s : selected) d = min(d, dist_idx(i, s));\n        minDist[i] = d;\n    }\n\n    double lambdaUniq = (eps >= 0.25 ? 0.5 : (eps >= 0.15 ? 0.3 : 0.1));\n\n    while ((int)selected.size() < M && (int)selected.size() < Cn) {\n        int best = -1;\n        double bestVal = -1.0;\n        for (int i = 0; i < Cn; i++) {\n            if (used[i]) continue;\n            double qual = 1.0 + lambdaUniq * ((double)cand[i].uniq_sig / max(1, N));\n            double val = minDist[i] * qual;\n            if (val > bestVal) {\n                bestVal = val;\n                best = i;\n            }\n        }\n        if (best == -1) break;\n        selected.push_back(best);\n        used[best] = true;\n\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i]) {\n                double d = dist_idx(i, best);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    int uniqueSel = (int)selected.size();\n    if (uniqueSel == 0) {\n        selected.push_back(0);\n        uniqueSel = 1;\n    }\n    while ((int)selected.size() < M) {\n        selected.push_back(selected[(int)selected.size() % uniqueSel]);\n    }\n\n    cb.distinct = min(uniqueSel, M);\n    cb.graphs.reserve(M);\n    for (int i = 0; i < M; i++) cb.graphs.push_back(cand[selected[i]]);\n    return cb;\n}\n\nvoid extract_features_from_string(\n    const string& H, const Codebook& cb, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2, vector<int>& outBlk\n) {\n    int N = cb.N, L = cb.L, B = cb.B, FB = cb.FB;\n\n    if ((int)outDeg.size() != N) {\n        outDeg.assign(N, 0);\n        outNd.assign(N, 0);\n        outNd2.assign(N, 0);\n    }\n    if ((int)outBlk.size() != FB) outBlk.assign(FB, 0);\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.ord[i] = i;\n    sort(w.ord.begin(), w.ord.end(), [&](int a, int b) {\n        if (w.deg[a] != w.deg[b]) return w.deg[a] < w.deg[b];\n        if (w.nd[a] != w.nd[b]) return w.nd[a] < w.nd[b];\n        if (w.nd2[a] != w.nd2[b]) return w.nd2[a] < w.nd2[b];\n        return a < b; // query labels are already shuffled randomly by judge\n    });\n\n    for (int pos = 0; pos < N; pos++) {\n        int v = w.ord[pos];\n        outDeg[pos] = w.deg[v];\n        outNd[pos] = w.nd[v];\n        outNd2[pos] = w.nd2[v];\n        w.bin[v] = (long long)pos * B / N;\n    }\n\n    fill(outBlk.begin(), outBlk.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            int bu = w.bin[u], bv = w.bin[v];\n            if (bu > bv) swap(bu, bv);\n            int id = cb.pairId[bu * B + bv];\n            outBlk[id]++;\n        }\n    }\n}\n\nvoid sample_noisy_features(\n    const Graph& g, const Codebook& cb, double eps, uint64_t flipThr,\n    RNG& rng, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2, vector<int>& outBlk\n) {\n    int N = cb.N, L = cb.L, B = cb.B, FB = cb.FB;\n\n    if ((int)outDeg.size() != N) {\n        outDeg.assign(N, 0);\n        outNd.assign(N, 0);\n        outNd2.assign(N, 0);\n    }\n    if ((int)outBlk.size() != FB) outBlk.assign(FB, 0);\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    if (eps <= 0.0) {\n        for (int e = 0; e < L; e++) {\n            uint8_t b = g.bits[e];\n            w.bits[e] = b;\n            if (b) {\n                int u = cb.eu[e], v = cb.ev[e];\n                w.deg[u]++;\n                w.deg[v]++;\n            }\n        }\n    } else {\n        for (int e = 0; e < L; e++) {\n            uint8_t b = g.bits[e];\n            if (rng.next_u64() < flipThr) b ^= 1;\n            w.bits[e] = b;\n            if (b) {\n                int u = cb.eu[e], v = cb.ev[e];\n                w.deg[u]++;\n                w.deg[v]++;\n            }\n        }\n    }\n\n    fill(w.nd.begin(), w.nd.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    // Random tiebreak keys emulate random vertex shuffling in actual judge\n    for (int i = 0; i < N; i++) {\n        w.ord[i] = i;\n        w.key[i] = rng.next_u64();\n    }\n    sort(w.ord.begin(), w.ord.end(), [&](int a, int b) {\n        if (w.deg[a] != w.deg[b]) return w.deg[a] < w.deg[b];\n        if (w.nd[a] != w.nd[b]) return w.nd[a] < w.nd[b];\n        if (w.nd2[a] != w.nd2[b]) return w.nd2[a] < w.nd2[b];\n        if (w.key[a] != w.key[b]) return w.key[a] < w.key[b];\n        return a < b;\n    });\n\n    for (int pos = 0; pos < N; pos++) {\n        int v = w.ord[pos];\n        outDeg[pos] = w.deg[v];\n        outNd[pos] = w.nd[v];\n        outNd2[pos] = w.nd2[v];\n        w.bin[v] = (long long)pos * B / N;\n    }\n\n    fill(outBlk.begin(), outBlk.end(), 0);\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            int bu = w.bin[u], bv = w.bin[v];\n            if (bu > bv) swap(bu, bv);\n            int id = cb.pairId[bu * B + bv];\n            outBlk[id]++;\n        }\n    }\n}\n\nProtoBank calibrate_prototypes(const Codebook& cb, double eps, int S, RNG& rng) {\n    ProtoBank pb;\n    pb.M = (int)cb.graphs.size();\n    pb.N = cb.N;\n    pb.S = (eps <= 0.0 ? 1 : max(1, S));\n    pb.FB = cb.FB;\n\n    size_t sampleN = (size_t)pb.M * pb.S * pb.N;\n    size_t sampleB = (size_t)pb.M * pb.S * pb.FB;\n\n    pb.sdeg.assign(sampleN, 0);\n    pb.snd.assign(sampleN, 0);\n    pb.snd2.assign(sampleN, 0);\n    pb.sblk.assign(sampleB, 0);\n\n    pb.cdeg.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd2.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cblk.assign((size_t)pb.M * pb.FB, 0.0f);\n\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N), ob(cb.FB);\n    vector<double> sumD(cb.N), sumN(cb.N), sumN2(cb.N), sumB(cb.FB);\n\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int k = 0; k < pb.M; k++) {\n        fill(sumD.begin(), sumD.end(), 0.0);\n        fill(sumN.begin(), sumN.end(), 0.0);\n        fill(sumN2.begin(), sumN2.end(), 0.0);\n        fill(sumB.begin(), sumB.end(), 0.0);\n\n        for (int s = 0; s < pb.S; s++) {\n            sample_noisy_features(cb.graphs[k], cb, eps, flipThr, rng, w, od, on, on2, ob);\n\n            size_t baseN = ((size_t)k * pb.S + s) * pb.N;\n            size_t baseB = ((size_t)k * pb.S + s) * pb.FB;\n\n            for (int i = 0; i < pb.N; i++) {\n                pb.sdeg[baseN + i] = (int16_t)od[i];\n                pb.snd[baseN + i] = (int32_t)on[i];\n                pb.snd2[baseN + i] = (int32_t)on2[i];\n                sumD[i] += od[i];\n                sumN[i] += on[i];\n                sumN2[i] += on2[i];\n            }\n            for (int b = 0; b < pb.FB; b++) {\n                pb.sblk[baseB + b] = (uint16_t)ob[b];\n                sumB[b] += ob[b];\n            }\n        }\n\n        for (int i = 0; i < pb.N; i++) {\n            pb.cdeg[(size_t)k * pb.N + i] = (float)(sumD[i] / pb.S);\n            pb.cnd[(size_t)k * pb.N + i] = (float)(sumN[i] / pb.S);\n            pb.cnd2[(size_t)k * pb.N + i] = (float)(sumN2[i] / pb.S);\n        }\n        for (int b = 0; b < pb.FB; b++) {\n            pb.cblk[(size_t)k * pb.FB + b] = (float)(sumB[b] / pb.S);\n        }\n    }\n\n    // Global variances\n    double varD = 0.0, varN1 = 0.0, varN2 = 0.0;\n    vector<double> varB(pb.FB, 0.0);\n\n    for (int k = 0; k < pb.M; k++) {\n        for (int s = 0; s < pb.S; s++) {\n            size_t baseN = ((size_t)k * pb.S + s) * pb.N;\n            size_t baseB = ((size_t)k * pb.S + s) * pb.FB;\n            size_t cN = (size_t)k * pb.N;\n            size_t cB = (size_t)k * pb.FB;\n\n            for (int i = 0; i < pb.N; i++) {\n                double d0 = (double)pb.sdeg[baseN + i] - (double)pb.cdeg[cN + i];\n                double d1 = (double)pb.snd[baseN + i] - (double)pb.cnd[cN + i];\n                double d2 = (double)pb.snd2[baseN + i] - (double)pb.cnd2[cN + i];\n                varD += d0 * d0;\n                varN1 += d1 * d1;\n                varN2 += d2 * d2;\n            }\n            for (int b = 0; b < pb.FB; b++) {\n                double db = (double)pb.sblk[baseB + b] - (double)pb.cblk[cB + b];\n                varB[b] += db * db;\n            }\n        }\n    }\n\n    double cntN = (double)pb.M * pb.S * pb.N;\n    double cntB = (double)pb.M * pb.S;\n    if (cntN <= 0) cntN = 1.0;\n    if (cntB <= 0) cntB = 1.0;\n\n    varD /= cntN;\n    varN1 /= cntN;\n    varN2 /= cntN;\n    for (int b = 0; b < pb.FB; b++) varB[b] /= cntB;\n\n    // Baseline floor (stability)\n    double baseD = max(0.0, (cb.N - 1) * eps * (1.0 - eps));\n    varD = max(varD, 0.5 * baseD);\n\n    pb.invD = 1.0 / (varD + 1.0);\n    pb.invN1 = 1.0 / (varN1 + 1.0);\n    pb.invN2 = 1.0 / (varN2 + 1.0);\n\n    pb.invB.assign(pb.FB, 1.0);\n    for (int b = 0; b < pb.FB; b++) {\n        double baseB = 0.35 * cb.blockCap[b] * eps * (1.0 - eps);\n        double vb = max(varB[b], baseB);\n        pb.invB[b] = 1.0 / (vb + 1.0);\n    }\n\n    return pb;\n}\n\nint decode_with_param(\n    const vector<int>& od, const vector<int>& on, const vector<int>& on2, const vector<int>& ob,\n    const ProtoBank& pb, const DecodeParam& prm\n) {\n    int M = pb.M, N = pb.N, S = pb.S, FB = pb.FB;\n\n    double cD = pb.invD;\n    double cN1 = prm.m1 * pb.invN1;\n    double cN2 = prm.m2 * pb.invN2;\n    double cB = prm.mB;\n\n    int bestK = 0;\n    double bestScore = 1e300;\n\n    for (int k = 0; k < M; k++) {\n        double best1 = 1e300, best2 = 1e300;\n\n        for (int s = 0; s < S; s++) {\n            size_t baseN = ((size_t)k * S + s) * N;\n            size_t baseB = ((size_t)k * S + s) * FB;\n\n            const int16_t* pd = pb.sdeg.data() + baseN;\n            const int32_t* pn = pb.snd.data() + baseN;\n            const int32_t* p2 = pb.snd2.data() + baseN;\n            const uint16_t* pbk = pb.sblk.data() + baseB;\n\n            double dsum = 0.0;\n\n            for (int i = 0; i < N; i++) {\n                double d = (double)od[i] - (double)pd[i];\n                dsum += cD * d * d;\n            }\n            if (cN1 != 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on[i] - (double)pn[i];\n                    dsum += cN1 * d * d;\n                }\n            }\n            if (cN2 != 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on2[i] - (double)p2[i];\n                    dsum += cN2 * d * d;\n                }\n            }\n            if (cB != 0.0) {\n                for (int b = 0; b < FB; b++) {\n                    double d = (double)ob[b] - (double)pbk[b];\n                    dsum += cB * pb.invB[b] * d * d;\n                }\n            }\n\n            if (dsum < best1) {\n                best2 = best1;\n                best1 = dsum;\n            } else if (dsum < best2) {\n                best2 = dsum;\n            }\n        }\n\n        if (!prm.useSecond || best2 > 1e299) best2 = best1;\n\n        // center distance\n        size_t cN = (size_t)k * N;\n        size_t cBidx = (size_t)k * FB;\n        const float* cd = pb.cdeg.data() + cN;\n        const float* cn = pb.cnd.data() + cN;\n        const float* c2 = pb.cnd2.data() + cN;\n        const float* cbk = pb.cblk.data() + cBidx;\n\n        double cdist = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)od[i] - (double)cd[i];\n            cdist += cD * d * d;\n        }\n        if (cN1 != 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on[i] - (double)cn[i];\n                cdist += cN1 * d * d;\n            }\n        }\n        if (cN2 != 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on2[i] - (double)c2[i];\n                cdist += cN2 * d * d;\n            }\n        }\n        if (cB != 0.0) {\n            for (int b = 0; b < FB; b++) {\n                double d = (double)ob[b] - (double)cbk[b];\n                cdist += cB * pb.invB[b] * d * d;\n            }\n        }\n\n        double score = prm.a1 * best1 + prm.a2 * best2 + prm.a3 * cdist;\n        if (score < bestScore) {\n            bestScore = score;\n            bestK = k;\n        }\n    }\n\n    return bestK;\n}\n\ndouble evaluate_codebook(\n    const Codebook& cb, const ProtoBank& pb, const DecodeParam& prm,\n    double eps, int T, RNG& rng\n) {\n    if (cb.distinct < pb.M) return -1e100;\n    if (T <= 0) return -1e100;\n\n    int err = 0;\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N), ob(cb.FB);\n\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int t = 0; t < T; t++) {\n        int s = rng.next_int(0, pb.M - 1);\n        sample_noisy_features(cb.graphs[s], cb, eps, flipThr, rng, w, od, on, on2, ob);\n        int p = decode_with_param(od, on, on2, ob, pb, prm);\n        if (p != s) err++;\n    }\n\n    double q = (double)err / (double)T;\n    double st = sqrt(max(1e-12, q * (1.0 - q) / T));\n    double qu = min(1.0, q + 1.1 * st + 0.5 / T); // conservative\n    double survive = max(0.0, 1.0 - 0.1 * qu);\n    return pow(survive, 100.0) / (double)cb.N;\n}\n\nvector<int> choose_candidate_Ns(int M, double eps) {\n    // unlabeled graph counts A000088 (0..10)\n    static const vector<long long> unl = {\n        0LL, 1LL, 1LL, 2LL, 4LL, 11LL, 34LL, 156LL, 1044LL, 12346LL, 274668LL\n    };\n\n    int nlb = 4;\n    while (nlb + 1 < (int)unl.size() && unl[nlb] < M) nlb++;\n\n    vector<int> Ns;\n    auto add = [&](int n) {\n        n = max(4, min(100, n));\n        if (find(Ns.begin(), Ns.end(), n) == Ns.end()) Ns.push_back(n);\n    };\n\n    add(nlb);\n\n    if (eps < 0.04) {\n        add(nlb + 1); add(8); add(10); add(14); add(20); add(28);\n    } else if (eps < 0.10) {\n        add(max(nlb, 8)); add(12); add(18); add(26); add(36); add(48); add(62);\n    } else if (eps < 0.18) {\n        add(max(nlb, 9)); add(16); add(24); add(34); add(46); add(62); add(80);\n    } else if (eps < 0.26) {\n        int base = (int)llround(18.0 + 0.45 * M);\n        add(max(nlb, 12)); add(base - 10); add(base); add(base + 12); add(78); add(92); add(100);\n    } else if (eps < 0.33) {\n        int base = (int)llround(24.0 + 0.55 * M);\n        add(max(nlb, 16)); add(base - 10); add(base); add(base + 10); add(88); add(100);\n    } else {\n        int base = (int)llround(30.0 + 0.60 * M);\n        add(max(nlb, 20)); add(base - 8); add(base); add(base + 8); add(96); add(100);\n    }\n\n    sort(Ns.begin(), Ns.end());\n    Ns.erase(unique(Ns.begin(), Ns.end()), Ns.end());\n    return Ns;\n}\n\nDecodeParam degree_only_param() {\n    DecodeParam p;\n    p.m1 = 0.0; p.m2 = 0.0; p.mB = 0.0;\n    p.a1 = 1.0; p.a2 = 0.0; p.a3 = 0.0;\n    p.useSecond = false;\n    p.name = \"deg_only\";\n    return p;\n}\n\nDecodeParam block_heavy_param() {\n    DecodeParam p;\n    p.m1 = 0.2; p.m2 = 0.0; p.mB = 1.2;\n    p.a1 = 0.60; p.a2 = 0.20; p.a3 = 0.20;\n    p.useSecond = true;\n    p.name = \"block_heavy\";\n    return p;\n}\n\nDecodeParam default_param(double eps) {\n    DecodeParam p;\n    if (eps < 0.08) {\n        p.m1 = 1.0; p.m2 = 0.7; p.mB = 0.1;\n        p.a1 = 0.70; p.a2 = 0.10; p.a3 = 0.20;\n    } else if (eps < 0.20) {\n        p.m1 = 1.0; p.m2 = 0.4; p.mB = 0.5;\n        p.a1 = 0.65; p.a2 = 0.15; p.a3 = 0.20;\n    } else if (eps < 0.30) {\n        p.m1 = 0.8; p.m2 = 0.15; p.mB = 0.9;\n        p.a1 = 0.60; p.a2 = 0.20; p.a3 = 0.20;\n    } else {\n        p.m1 = 0.6; p.m2 = 0.0; p.mB = 1.1;\n        p.a1 = 0.55; p.a2 = 0.25; p.a3 = 0.20;\n    }\n    p.useSecond = true;\n    p.name = \"default\";\n    return p;\n}\n\nvector<DecodeParam> make_param_candidates(double eps, const DecodeParam& defp) {\n    vector<DecodeParam> v;\n    v.push_back(defp);\n    v.push_back(degree_only_param());\n\n    auto push = [&](double m1, double m2, double mB, double a1, double a2, double a3, bool s, string nm) {\n        DecodeParam p;\n        p.m1 = m1; p.m2 = m2; p.mB = mB;\n        p.a1 = a1; p.a2 = a2; p.a3 = a3;\n        p.useSecond = s;\n        p.name = nm;\n        v.push_back(p);\n    };\n\n    if (eps < 0.10) {\n        push(1.0, 0.4, 0.0, 0.75, 0.05, 0.20, true, \"low1\");\n        push(1.0, 0.8, 0.1, 0.65, 0.15, 0.20, true, \"low2\");\n        push(1.0, 0.0, 0.2, 0.70, 0.10, 0.20, true, \"low3\");\n    } else if (eps < 0.25) {\n        push(1.0, 0.3, 0.7, 0.62, 0.18, 0.20, true, \"mid1\");\n        push(0.8, 0.0, 0.9, 0.64, 0.16, 0.20, true, \"mid2\");\n        push(1.0, 0.0, 0.4, 0.72, 0.08, 0.20, true, \"mid3\");\n        push(0.8, 0.2, 0.2, 0.70, 0.10, 0.20, true, \"mid4\");\n    } else {\n        push(0.0, 0.0, 1.2, 0.65, 0.15, 0.20, true, \"high1\");\n        push(0.4, 0.0, 1.0, 0.60, 0.20, 0.20, true, \"high2\");\n        push(0.8, 0.0, 0.5, 0.65, 0.15, 0.20, true, \"high3\");\n        push(0.6, 0.0, 0.0, 0.80, 0.00, 0.20, false, \"high4\");\n        v.push_back(block_heavy_param());\n    }\n\n    return v;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - t0).count();\n    };\n\n    uint64_t epsInt = (uint64_t)llround(eps * 100.0);\n    uint64_t baseSeed = 0x1234abcddcba4321ULL ^ (uint64_t)M * 10007ULL ^ epsInt * 1000003ULL;\n\n    vector<int> Ns = choose_candidate_Ns(M, eps);\n    if (eps > 0.22) reverse(Ns.begin(), Ns.end());\n\n    DecodeParam pDef = default_param(eps);\n    DecodeParam pDeg = degree_only_param();\n    DecodeParam pBlk = block_heavy_param();\n\n    double bestEst = -1e100;\n    Codebook bestCb;\n    DecodeParam bestInitParam = pDef;\n    bool haveBest = false;\n\n    long long searchDeadline = 2900;\n\n    for (int ni = 0; ni < (int)Ns.size(); ni++) {\n        int N = Ns[ni];\n        int tries = (eps < 0.10 ? 1 : (eps < 0.25 ? 2 : 3));\n\n        for (int att = 0; att < tries; att++) {\n            if (elapsed_ms() > searchDeadline) break;\n\n            int C = max(500, M * 10);\n            if (eps > 0.20) C += M * 4;\n            if (N <= 12) C += 300;\n            C += att * 80;\n            C = min(C, 1800);\n\n            RNG rngBuild(baseSeed + 1000003ULL * (uint64_t)N + 1009ULL * (uint64_t)att + 97ULL * (uint64_t)ni + 11ULL);\n            Codebook cb = build_codebook(N, M, eps, C, rngBuild);\n            if (cb.distinct < M) continue;\n\n            int Se = (eps < 0.08 ? 3 : (eps < 0.20 ? 4 : 5));\n            if (M > 80) Se++;\n            if (eps > 0.30) Se++;\n            if (elapsed_ms() > 2200) Se = max(3, Se - 1);\n\n            RNG rngCal(baseSeed + 2000003ULL * (uint64_t)N + 1237ULL * (uint64_t)att + 17ULL);\n            ProtoBank pb = calibrate_prototypes(cb, eps, Se, rngCal);\n\n            int T = (eps < 0.08 ? 140 : (eps < 0.20 ? 180 : 220));\n            if (M > 80) T += 40;\n            T = max(100, T - att * 20);\n            if (elapsed_ms() > 2400) T = max(90, T - 50);\n\n            uint64_t evalSeed = baseSeed + 3000017ULL * (uint64_t)N + 2713ULL * (uint64_t)att + 233ULL * (uint64_t)ni;\n\n            RNG reA(evalSeed);\n            double est = evaluate_codebook(cb, pb, pDef, eps, T, reA);\n            DecodeParam selParam = pDef;\n\n            if (eps >= 0.14 && elapsed_ms() < searchDeadline - 250) {\n                RNG reB(evalSeed);\n                double estB = evaluate_codebook(cb, pb, pDeg, eps, max(60, T / 2), reB);\n                if (estB > est) {\n                    est = estB;\n                    selParam = pDeg;\n                }\n            }\n            if (eps >= 0.22 && elapsed_ms() < searchDeadline - 250) {\n                RNG reC(evalSeed);\n                double estC = evaluate_codebook(cb, pb, pBlk, eps, max(60, T / 2), reC);\n                if (estC > est) {\n                    est = estC;\n                    selParam = pBlk;\n                }\n            }\n\n            if (est > bestEst) {\n                bestEst = est;\n                bestCb = std::move(cb);\n                bestInitParam = selParam;\n                haveBest = true;\n            }\n        }\n        if (elapsed_ms() > searchDeadline) break;\n    }\n\n    if (!haveBest || bestCb.graphs.empty() || bestCb.distinct < M) {\n        vector<int> fallbackNs = {100, 90, 80, 70, 60, 50, 40, 30, 20, 12, 8};\n        for (int n : fallbackNs) {\n            RNG rb(baseSeed + 777ULL * (uint64_t)n + 99991ULL);\n            Codebook cb = build_codebook(n, M, eps, max(900, M * 14), rb);\n            if (bestCb.graphs.empty()) bestCb = cb;\n            if (cb.distinct >= M) {\n                bestCb = std::move(cb);\n                break;\n            }\n        }\n        bestInitParam = pDef;\n    }\n\n    int Sf;\n    if (eps < 0.05) Sf = 8;\n    else if (eps < 0.15) Sf = 12;\n    else if (eps < 0.25) Sf = 16;\n    else if (eps < 0.35) Sf = 20;\n    else Sf = 24;\n    if (M > 80) Sf += 2;\n    if (elapsed_ms() > 3200) Sf = max(8, Sf - 4);\n    if (elapsed_ms() > 3900) Sf = max(6, Sf / 2);\n\n    RNG rngFinal(baseSeed ^ 0x9e3779b97f4a7c15ULL);\n    ProtoBank pbFinal = calibrate_prototypes(bestCb, eps, Sf, rngFinal);\n\n    DecodeParam bestParam = bestInitParam;\n\n    // Lightweight parameter tuning\n    if (elapsed_ms() < 3600) {\n        auto pcands = make_param_candidates(eps, bestParam);\n        int Tt = (eps < 0.15 ? 50 : 70);\n        if (M > 80) Tt += 20;\n        if (elapsed_ms() > 3300) Tt = max(40, Tt - 20);\n\n        double bestPEst = -1e100;\n        for (int i = 0; i < (int)pcands.size(); i++) {\n            if (elapsed_ms() > 4400) break;\n            RNG rt(baseSeed + 5555555ULL); // same seed for fair comparison\n            double est = evaluate_codebook(bestCb, pbFinal, pcands[i], eps, Tt, rt);\n            if (est > bestPEst) {\n                bestPEst = est;\n                bestParam = pcands[i];\n            }\n        }\n    }\n\n    // Output codebook\n    cout << bestCb.N << '\\n';\n    for (int k = 0; k < M; k++) {\n        string s(bestCb.L, '0');\n        const auto& bits = bestCb.graphs[k].bits;\n        for (int e = 0; e < bestCb.L; e++) {\n            if (bits[e]) s[e] = '1';\n        }\n        cout << s << '\\n';\n    }\n    cout.flush();\n\n    bool useExact = (eps <= 0.0);\n    unordered_map<uint64_t, int> exactMap;\n    if (useExact) {\n        exactMap.reserve((size_t)M * 2);\n        for (int k = 0; k < M; k++) {\n            uint64_t h = hash_sorted3(\n                bestCb.graphs[k].deg_sorted,\n                bestCb.graphs[k].nd_sorted,\n                bestCb.graphs[k].nd2_sorted\n            );\n            if (!exactMap.count(h)) exactMap[h] = k;\n        }\n    }\n\n    FeatureWork qwork(bestCb.N, bestCb.L);\n    vector<int> od(bestCb.N), on(bestCb.N), on2(bestCb.N), ob(bestCb.FB);\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) return 0;\n\n        extract_features_from_string(H, bestCb, qwork, od, on, on2, ob);\n\n        int ans = 0;\n        if (useExact) {\n            uint64_t h = hash_sorted3(od, on, on2);\n            auto it = exactMap.find(h);\n            if (it != exactMap.end()) ans = it->second;\n            else ans = decode_with_param(od, on, on2, ob, pbFinal, bestParam);\n        } else {\n            ans = decode_with_param(od, on, on2, ob, pbFinal, bestParam);\n        }\n\n        if (ans < 0) ans = 0;\n        if (ans >= M) ans = M - 1;\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;\nstatic constexpr int UNREACH = 1'000'000'000;\nstatic constexpr ll DISCONNECT_UNIT = 100'000'000LL;\n\nstruct Edge {\n    int u, v, w;\n    int cell = 0;\n    double imp = 0.0;\n};\n\nint N, M, D, K;\nint GRID = 10;\n\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj; // (to, edge id)\nvector<int> X, Y, degv;\n\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\nvector<int> samples;\nint S = 0;\nvector<vector<int>> baseDist;\nvector<int> tmpDist;\n\n// current solution state\nvector<int> dayOf;               // edge -> day [0..D-1]\nvector<int> cntDay;              // day -> count\nvector<vector<int>> incCnt;      // vertex, day -> #incident edges repaired that day\nvector<vector<int>> dayEdges;    // day -> edge list\nvector<int> posInDay;            // edge -> position in dayEdges[dayOf[edge]]\nvector<ll> dayScore;             // approximate score per day\n\nvector<int> seen;\nint seenToken = 1;\n\ninline int rnd_int(int n) {\n    return (int)(rng() % (uint32_t)n);\n}\ninline double rnd01() {\n    return (rng() + 0.5) * (1.0 / 4294967296.0);\n}\n\nvoid dijkstra_full_parent(int src, vector<int>& dist, vector<int>& parent) {\n    fill(dist.begin(), dist.end(), UNREACH);\n    fill(parent.begin(), parent.end(), -1);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                parent[to] = eid;\n                pq.push({nd, to});\n            } else if (nd == dist[to] && parent[to] != -1) {\n                // deterministic tie-break\n                if (eid < parent[to]) parent[to] = eid;\n            }\n        }\n    }\n}\n\nvoid dijkstra_ban_day(int src, int banDay, vector<int>& dist) {\n    fill(dist.begin(), dist.end(), UNREACH);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            if (dayOf[eid] == banDay) continue;\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                pq.push({nd, to});\n            }\n        }\n    }\n}\n\n// ordered pairs across different connected components after removing banDay edges.\n// 0 means connected.\nll disconnected_cross_pairs(int banDay) {\n    static vector<int> q;\n    if ((int)q.size() < N) q.resize(N);\n\n    ll sameOrdered = 0;\n    for (int st = 0; st < N; st++) {\n        if (seen[st] == seenToken) continue;\n        int head = 0, tail = 0;\n        q[tail++] = st;\n        seen[st] = seenToken;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (auto [to, eid] : adj[v]) {\n                if (dayOf[eid] == banDay) continue;\n                if (seen[to] == seenToken) continue;\n                seen[to] = seenToken;\n                q[tail++] = to;\n            }\n        }\n        sameOrdered += 1LL * sz * (sz - 1);\n    }\n\n    seenToken++;\n    if (seenToken == INT_MAX) {\n        fill(seen.begin(), seen.end(), 0);\n        seenToken = 1;\n    }\n\n    ll totalOrdered = 1LL * N * (N - 1);\n    return totalOrdered - sameOrdered;\n}\n\nll compute_day_score(int day) {\n    // Strong connectivity penalty to avoid hidden catastrophic solutions.\n    ll crossPairs = disconnected_cross_pairs(day);\n    if (crossPairs > 0) {\n        return crossPairs * DISCONNECT_UNIT;\n    }\n\n    ll sum = 0;\n    for (int si = 0; si < S; si++) {\n        dijkstra_ban_day(samples[si], day, tmpDist);\n        const auto& b = baseDist[si];\n        for (int v = 0; v < N; v++) {\n            sum += (ll)tmpDist[v] - b[v];\n        }\n    }\n    return sum;\n}\n\nll evaluate_total(vector<ll>& outDayScore) {\n    outDayScore.assign(D, 0);\n    ll tot = 0;\n    for (int d = 0; d < D; d++) {\n        outDayScore[d] = compute_day_score(d);\n        tot += outDayScore[d];\n    }\n    return tot;\n}\n\nvector<int> select_samples(int cnt) {\n    cnt = min(cnt, N);\n    vector<int> res;\n    vector<double> minD2(N, 1e100);\n    vector<char> used(N, false);\n\n    int first = 0;\n    for (int i = 1; i < N; i++) {\n        if (degv[i] > degv[first]) first = i;\n    }\n\n    for (int it = 0; it < cnt; it++) {\n        int cur = -1;\n        if (it == 0) {\n            cur = first;\n        } else {\n            double best = -1.0;\n            for (int v = 0; v < N; v++) {\n                if (used[v]) continue;\n                if (minD2[v] > best) {\n                    best = minD2[v];\n                    cur = v;\n                }\n            }\n        }\n        used[cur] = true;\n        res.push_back(cur);\n\n        for (int v = 0; v < N; v++) {\n            if (used[v]) continue;\n            double dx = (double)X[v] - X[cur];\n            double dy = (double)Y[v] - Y[cur];\n            double d2 = dx * dx + dy * dy;\n            if (d2 < minD2[v]) minD2[v] = d2;\n        }\n    }\n\n    return res;\n}\n\nvector<int> build_initial_schedule(double alpha, double beta, double gamma) {\n    vector<int> assign(M, -1);\n    vector<int> cnt(D, 0);\n    vector<vector<int>> inc(N, vector<int>(D, 0));\n    int C = GRID * GRID;\n    vector<vector<int>> cellCnt(C, vector<int>(D, 0));\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n\n    vector<double> key(M);\n    for (int e = 0; e < M; e++) {\n        key[e] = edges[e].imp + (double)(rng() & 2047) * 1e-6;\n    }\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (key[a] != key[b]) return key[a] > key[b];\n        return a < b;\n    });\n\n    double maxImp = 1e-9;\n    for (int e = 0; e < M; e++) maxImp = max(maxImp, edges[e].imp);\n\n    for (int eid : order) {\n        const Edge& E = edges[eid];\n        int u = E.u, v = E.v, c = E.cell;\n        double impf = 1.0 + E.imp / maxImp;\n\n        int bestDay = -1;\n        double bestP = 1e100;\n\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] >= K) continue;\n            if (inc[u][d] >= degv[u] - 1) continue;\n            if (inc[v][d] >= degv[v] - 1) continue;\n\n            double p = alpha * cnt[d]\n                     + beta * impf * (inc[u][d] + inc[v][d])\n                     + gamma * cellCnt[c][d];\n            if (p < bestP) {\n                bestP = p;\n                bestDay = d;\n            }\n        }\n\n        // If hard constraints block all days, relax slightly with heavy penalty.\n        if (bestDay == -1) {\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] >= K) continue;\n                double viol = 0.0;\n                if (inc[u][d] >= degv[u] - 1) viol += 1000.0;\n                if (inc[v][d] >= degv[v] - 1) viol += 1000.0;\n                double p = alpha * cnt[d]\n                         + beta * impf * (inc[u][d] + inc[v][d])\n                         + gamma * cellCnt[c][d]\n                         + viol;\n                if (p < bestP) {\n                    bestP = p;\n                    bestDay = d;\n                }\n            }\n        }\n\n        if (bestDay == -1) {\n            // very defensive fallback\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] < K) {\n                    bestDay = d;\n                    break;\n                }\n            }\n            if (bestDay == -1) bestDay = 0;\n        }\n\n        assign[eid] = bestDay;\n        cnt[bestDay]++;\n        inc[u][bestDay]++;\n        inc[v][bestDay]++;\n        cellCnt[c][bestDay]++;\n    }\n\n    return assign;\n}\n\nvoid build_state_from_assignment() {\n    cntDay.assign(D, 0);\n    incCnt.assign(N, vector<int>(D, 0));\n    dayEdges.assign(D, vector<int>());\n    posInDay.assign(M, -1);\n\n    for (int e = 0; e < M; e++) {\n        int d = dayOf[e];\n        cntDay[d]++;\n        int u = edges[e].u, v = edges[e].v;\n        incCnt[u][d]++;\n        incCnt[v][d]++;\n        posInDay[e] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(e);\n    }\n}\n\ninline void day_remove_edge(int e, int d) {\n    int p = posInDay[e];\n    int last = dayEdges[d].back();\n    dayEdges[d][p] = last;\n    posInDay[last] = p;\n    dayEdges[d].pop_back();\n}\n\ninline void day_add_edge(int e, int d) {\n    posInDay[e] = (int)dayEdges[d].size();\n    dayEdges[d].push_back(e);\n}\n\nvoid apply_move(int e, int from, int to) {\n    day_remove_edge(e, from);\n    day_add_edge(e, to);\n\n    dayOf[e] = to;\n    cntDay[from]--;\n    cntDay[to]++;\n\n    int u = edges[e].u, v = edges[e].v;\n    incCnt[u][from]--;\n    incCnt[v][from]--;\n    incCnt[u][to]++;\n    incCnt[v][to]++;\n}\n\nvoid apply_swap(int e, int f, int d1, int d2) {\n    // e: d1 -> d2, f: d2 -> d1\n    int pe = posInDay[e];\n    int pf = posInDay[f];\n\n    dayEdges[d1][pe] = f;\n    posInDay[f] = pe;\n    dayEdges[d2][pf] = e;\n    posInDay[e] = pf;\n\n    dayOf[e] = d2;\n    dayOf[f] = d1;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    incCnt[eu][d1]--;\n    incCnt[ev][d1]--;\n    incCnt[eu][d2]++;\n    incCnt[ev][d2]++;\n\n    incCnt[fu][d2]--;\n    incCnt[fv][d2]--;\n    incCnt[fu][d1]++;\n    incCnt[fv][d1]++;\n}\n\nbool can_move_edge(int e, int to) {\n    int from = dayOf[e];\n    if (from == to) return false;\n    if (cntDay[to] >= K) return false;\n    int u = edges[e].u, v = edges[e].v;\n    if (incCnt[u][to] + 1 > degv[u] - 1) return false;\n    if (incCnt[v][to] + 1 > degv[v] - 1) return false;\n    return true;\n}\n\nbool can_swap_edges(int e, int f) {\n    int d1 = dayOf[e];\n    int d2 = dayOf[f];\n    if (d1 == d2) return false;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    int vv[4] = {eu, ev, fu, fv};\n    sort(vv, vv + 4);\n    int m = (int)(unique(vv, vv + 4) - vv);\n\n    for (int i = 0; i < m; i++) {\n        int x = vv[i];\n        int nd1 = incCnt[x][d1] - (eu == x) - (ev == x) + (fu == x) + (fv == x);\n        int nd2 = incCnt[x][d2] - (fu == x) - (fv == x) + (eu == x) + (ev == x);\n        if (nd1 > degv[x] - 1) return false;\n        if (nd2 > degv[x] - 1) return false;\n    }\n    return true;\n}\n\nint day_with_max_score() {\n    int id = 0;\n    for (int d = 1; d < D; d++) {\n        if (dayScore[d] > dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_move(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (cntDay[d] >= K) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_swap(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (dayEdges[d].empty()) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    adj.assign(N, {});\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        adj[u].push_back({v, i});\n        adj[v].push_back({u, i});\n    }\n\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n    }\n\n    degv.assign(N, 0);\n    for (int v = 0; v < N; v++) degv[v] = (int)adj[v].size();\n\n    // edge cell id\n    for (int e = 0; e < M; e++) {\n        int mx = X[edges[e].u] + X[edges[e].v]; // [0,2000]\n        int my = Y[edges[e].u] + Y[edges[e].v];\n        int gx = min(GRID - 1, mx * GRID / 2001);\n        int gy = min(GRID - 1, my * GRID / 2001);\n        edges[e].cell = gx * GRID + gy;\n    }\n\n    int sampleTarget = 14;\n    if (N > 850 || M > 2500) sampleTarget = 12;\n    S = min(N, sampleTarget);\n\n    samples = select_samples(S);\n\n    baseDist.assign(S, vector<int>(N, UNREACH));\n    vector<double> imp(M, 0.0);\n\n    vector<int> dist(N), parent(N);\n    for (int si = 0; si < S; si++) {\n        int src = samples[si];\n        dijkstra_full_parent(src, dist, parent);\n        baseDist[si] = dist;\n        for (int v = 0; v < N; v++) {\n            if (v == src) continue;\n            int pe = parent[v];\n            if (pe >= 0) imp[pe] += 1.0;\n        }\n    }\n\n    for (int e = 0; e < M; e++) {\n        imp[e] += 1000.0 / edges[e].w;\n        imp[e] += 0.1 * (1.0 / degv[edges[e].u] + 1.0 / degv[edges[e].v]);\n        edges[e].imp = imp[e];\n    }\n\n    dayOf.assign(M, 0);\n    tmpDist.assign(N, UNREACH);\n    seen.assign(N, 0);\n    seenToken = 1;\n\n    vector<array<double,3>> params = {\n        {1.0, 4.0, 1.8},\n        {0.8, 5.0, 0.7},\n        {1.2, 3.2, 2.6}\n    };\n\n    vector<int> bestAssignInit;\n    vector<ll> bestDayScoreInit;\n    ll bestTotInit = (1LL << 62);\n\n    for (auto p : params) {\n        auto initAssign = build_initial_schedule(p[0], p[1], p[2]);\n        dayOf = initAssign;\n        vector<ll> ds;\n        ll tot = evaluate_total(ds);\n        if (tot < bestTotInit) {\n            bestTotInit = tot;\n            bestAssignInit = move(initAssign);\n            bestDayScoreInit = move(ds);\n        }\n    }\n\n    dayOf = bestAssignInit;\n    dayScore = bestDayScoreInit;\n    ll currentTotal = bestTotInit;\n\n    build_state_from_assignment();\n\n    vector<int> bestAssign = dayOf;\n    ll bestTotal = currentTotal;\n\n    const double TIME_LIMIT = 5.60;\n    const double T0 = 5e6;\n    const double T1 = 1e3;\n    const double logT0 = log(T0);\n    const double logT1 = log(T1);\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= TIME_LIMIT) break;\n        }\n        iter++;\n\n        bool generated = false;\n        bool isMove = false;\n        int e = -1, f = -1, toDay = -1;\n\n        for (int tr = 0; tr < 25 && !generated; tr++) {\n            int mode = rnd_int(100);\n\n            if (mode < 35) {\n                // targeted move: bad day -> good day\n                int d1 = day_with_max_score();\n                if (dayEdges[d1].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                int d2 = day_with_min_score_move(d1);\n                if (d2 < 0) continue;\n                if (!can_move_edge(e, d2)) continue;\n                isMove = true;\n                toDay = d2;\n                generated = true;\n\n            } else if (mode < 65) {\n                // targeted swap: bad day <-> good day\n                int d1 = day_with_max_score();\n                int d2 = day_with_min_score_swap(d1);\n                if (d2 < 0) continue;\n                if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                f = dayEdges[d2][rnd_int((int)dayEdges[d2].size())];\n                if (!can_swap_edges(e, f)) continue;\n                isMove = false;\n                generated = true;\n\n            } else {\n                // random\n                e = rnd_int(M);\n                if (rnd_int(2) == 0) {\n                    int d2 = rnd_int(D);\n                    if (!can_move_edge(e, d2)) continue;\n                    isMove = true;\n                    toDay = d2;\n                    generated = true;\n                } else {\n                    f = rnd_int(M);\n                    if (e == f) continue;\n                    if (!can_swap_edges(e, f)) continue;\n                    isMove = false;\n                    generated = true;\n                }\n            }\n        }\n\n        if (!generated) continue;\n\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        double temp = exp(logT0 + (logT1 - logT0) * progress);\n\n        if (isMove) {\n            int from = dayOf[e];\n            int to = toDay;\n\n            ll oldA = dayScore[from];\n            ll oldB = dayScore[to];\n\n            apply_move(e, from, to);\n\n            ll newA = compute_day_score(from);\n            ll newB = compute_day_score(to);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[from] = newA;\n                dayScore[to] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_move(e, to, from); // revert\n            }\n\n        } else {\n            int d1 = dayOf[e];\n            int d2 = dayOf[f];\n\n            ll oldA = dayScore[d1];\n            ll oldB = dayScore[d2];\n\n            apply_swap(e, f, d1, d2);\n\n            ll newA = compute_day_score(d1);\n            ll newB = compute_day_score(d2);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[d1] = newA;\n                dayScore[d2] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_swap(e, f, d2, d1); // revert\n            }\n        }\n    }\n\n    dayOf = bestAssign;\n\n    // defensive validity check\n    bool ok = true;\n    vector<int> checkCnt(D, 0);\n    for (int e = 0; e < M; e++) {\n        if (dayOf[e] < 0 || dayOf[e] >= D) ok = false;\n        else checkCnt[dayOf[e]]++;\n    }\n    for (int d = 0; d < D; d++) if (checkCnt[d] > K) ok = false;\n\n    if (!ok) {\n        // guaranteed feasible fallback\n        for (int e = 0; e < M; e++) dayOf[e] = e % D;\n    }\n\n    for (int e = 0; e < M; e++) {\n        if (e) cout << ' ';\n        cout << (dayOf[e] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seg { int s, stride; };\n\nstruct LayerData {\n    vector<int> X, Y;\n    vector<int> allowed; // x*D+y\n    int base = 0;\n    int cap = 0;\n};\n\nstruct Occupancy {\n    vector<char> occ;\n    int vol = 0;\n    int zadj = 0;\n    int adj6 = 0;\n    array<int, 14> zcnt{};\n    array<int, 14> xcnt{};\n    array<int, 14> ycnt{};\n};\n\nstruct Solution {\n    long double score = 1e100L;\n    int n = 0;\n    vector<int> b1, b2;\n};\n\nstruct Pt { int x, y, z; };\nstruct Rot { int p[3], s[3]; };\n\nstruct ShapeGroup {\n    int k = 0;\n    bool isLine = false;\n    vector<array<int, 8>> plc; // first k entries are used\n};\n\nint D, N;\nint SX, SY, SZ;\n\narray<vector<string>, 2> F, Rv;\narray<vector<LayerData>, 2> LAY;\narray<int, 2> VminObj, VmaxObj;\narray<vector<int>, 2> ColLife;\n\nvector<Rot> ROTS;\nvector<vector<Seg>> allSegs; // all lines length L>=3 (all orientations merged)\nShapeGroup cubeGroup;\nvector<ShapeGroup> groups3, groups4;\n\nvector<vector<int>> neighbors;\nvector<int> parityCell;\nvector<unsigned char> CX, CY, CZ;\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline int clampi(int v, int lo, int hi) {\n    return v < lo ? lo : (v > hi ? hi : v);\n}\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++) if (p[i] > p[j]) inv++;\n    return (inv % 2 == 0 ? 1 : -1);\n}\n\nvoid build_rotations() {\n    ROTS.clear();\n    vector<array<int,3>> perms = {\n        {0,1,2}, {0,2,1}, {1,0,2}, {1,2,0}, {2,0,1}, {2,1,0}\n    };\n    for (auto perm : perms) {\n        int pp = perm_parity(perm);\n        for (int sx : {-1, 1}) for (int sy : {-1, 1}) for (int sz : {-1, 1}) {\n            int det = pp * sx * sy * sz;\n            if (det != 1) continue;\n            Rot r;\n            r.p[0] = perm[0]; r.p[1] = perm[1]; r.p[2] = perm[2];\n            r.s[0] = sx;      r.s[1] = sy;      r.s[2] = sz;\n            ROTS.push_back(r);\n        }\n    }\n}\n\nPt rotate_pt(const Pt& a, const Rot& r) {\n    int v[3] = {a.x, a.y, a.z};\n    return Pt{r.s[0] * v[r.p[0]], r.s[1] * v[r.p[1]], r.s[2] * v[r.p[2]]};\n}\n\nvector<Pt> normalize_pts(vector<Pt> v) {\n    int mnx = 1e9, mny = 1e9, mnz = 1e9;\n    for (auto& p : v) {\n        mnx = min(mnx, p.x);\n        mny = min(mny, p.y);\n        mnz = min(mnz, p.z);\n    }\n    for (auto& p : v) {\n        p.x -= mnx;\n        p.y -= mny;\n        p.z -= mnz;\n    }\n    sort(v.begin(), v.end(), [](const Pt& a, const Pt& b) {\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    return v;\n}\n\nstring encode_pts_text(const vector<Pt>& v) {\n    string s;\n    s.reserve(v.size() * 12);\n    for (auto& p : v) {\n        s += to_string(p.x); s.push_back(',');\n        s += to_string(p.y); s.push_back(',');\n        s += to_string(p.z); s.push_back(';');\n    }\n    return s;\n}\n\npair<string, vector<Pt>> canonical_repr(const vector<Pt>& cells) {\n    string bestKey;\n    vector<Pt> best;\n    bool first = true;\n    for (auto& r : ROTS) {\n        vector<Pt> t;\n        t.reserve(cells.size());\n        for (auto& p : cells) t.push_back(rotate_pt(p, r));\n        t = normalize_pts(move(t));\n        string key = encode_pts_text(t);\n        if (first || key < bestKey) {\n            first = false;\n            bestKey = move(key);\n            best = move(t);\n        }\n    }\n    return {bestKey, best};\n}\n\nvector<vector<Pt>> enumerate_free_shapes(int K) {\n    static const int dx[6] = {1,-1,0,0,0,0};\n    static const int dy[6] = {0,0,1,-1,0,0};\n    static const int dz[6] = {0,0,0,0,1,-1};\n\n    vector<vector<vector<Pt>>> by(K + 1);\n    by[1].push_back(vector<Pt>{{0,0,0}});\n\n    for (int s = 1; s < K; s++) {\n        unordered_map<string, vector<Pt>> mp;\n        mp.reserve(1024);\n\n        for (const auto& sh : by[s]) {\n            unordered_set<long long> have;\n            have.reserve(sh.size() * 5 + 16);\n\n            for (auto& p : sh) {\n                long long code = ((long long)(p.x + 32) << 40)\n                               ^ ((long long)(p.y + 32) << 20)\n                               ^ (long long)(p.z + 32);\n                have.insert(code);\n            }\n\n            set<tuple<int,int,int>> cand;\n            for (auto& p : sh) {\n                for (int d = 0; d < 6; d++) {\n                    int nx = p.x + dx[d], ny = p.y + dy[d], nz = p.z + dz[d];\n                    long long code = ((long long)(nx + 32) << 40)\n                                   ^ ((long long)(ny + 32) << 20)\n                                   ^ (long long)(nz + 32);\n                    if (!have.count(code)) cand.emplace(nx, ny, nz);\n                }\n            }\n\n            for (auto [nx, ny, nz] : cand) {\n                vector<Pt> ns = sh;\n                ns.push_back({nx, ny, nz});\n                auto [key, canon] = canonical_repr(ns);\n                if (mp.find(key) == mp.end()) {\n                    mp.emplace(key, move(canon));\n                }\n            }\n        }\n\n        by[s + 1].reserve(mp.size());\n        for (auto& kv : mp) by[s + 1].push_back(move(kv.second));\n    }\n\n    return by[K];\n}\n\nbool consecutive_unique(vector<int> v) {\n    sort(v.begin(), v.end());\n    for (int i = 1; i < (int)v.size(); i++) if (v[i] == v[i - 1]) return false;\n    return v.back() - v.front() + 1 == (int)v.size();\n}\n\nbool is_line_shape(const vector<Pt>& sh) {\n    int k = (int)sh.size();\n    if (k <= 1) return true;\n\n    bool lineX = true, lineY = true, lineZ = true;\n    for (auto& p : sh) {\n        if (p.y != sh[0].y || p.z != sh[0].z) lineX = false;\n        if (p.x != sh[0].x || p.z != sh[0].z) lineY = false;\n        if (p.x != sh[0].x || p.y != sh[0].y) lineZ = false;\n    }\n\n    if (lineX) {\n        vector<int> xs; xs.reserve(k);\n        for (auto& p : sh) xs.push_back(p.x);\n        if (consecutive_unique(xs)) return true;\n    }\n    if (lineY) {\n        vector<int> ys; ys.reserve(k);\n        for (auto& p : sh) ys.push_back(p.y);\n        if (consecutive_unique(ys)) return true;\n    }\n    if (lineZ) {\n        vector<int> zs; zs.reserve(k);\n        for (auto& p : sh) zs.push_back(p.z);\n        if (consecutive_unique(zs)) return true;\n    }\n    return false;\n}\n\nvector<ShapeGroup> build_groups_from_shapes(const vector<vector<Pt>>& shapes, int k) {\n    vector<ShapeGroup> gs;\n\n    for (auto& sh : shapes) {\n        unordered_map<string, vector<Pt>> oriMap;\n        oriMap.reserve(64);\n\n        for (auto& r : ROTS) {\n            vector<Pt> t;\n            t.reserve(k);\n            for (auto& p : sh) t.push_back(rotate_pt(p, r));\n            t = normalize_pts(move(t));\n            string key = encode_pts_text(t);\n            if (oriMap.find(key) == oriMap.end()) {\n                oriMap.emplace(key, move(t));\n            }\n        }\n\n        ShapeGroup g;\n        g.k = k;\n        g.isLine = is_line_shape(sh);\n\n        for (auto& kv : oriMap) {\n            const auto& o = kv.second;\n            int mx = 0, my = 0, mz = 0;\n            for (auto& p : o) {\n                mx = max(mx, p.x);\n                my = max(my, p.y);\n                mz = max(mz, p.z);\n            }\n\n            for (int ox = 0; ox + mx < D; ox++) {\n                for (int oy = 0; oy + my < D; oy++) {\n                    for (int oz = 0; oz + mz < D; oz++) {\n                        array<int,8> arr{};\n                        for (int i = 0; i < k; i++) {\n                            arr[i] = idx3(ox + o[i].x, oy + o[i].y, oz + o[i].z);\n                        }\n                        g.plc.push_back(arr);\n                    }\n                }\n            }\n        }\n\n        if (!g.plc.empty()) gs.push_back(move(g));\n    }\n\n    return gs;\n}\n\nvoid precompute() {\n    SX = D * D;\n    SY = D;\n    SZ = 1;\n    N = D * D * D;\n\n    CX.assign(N, 0);\n    CY.assign(N, 0);\n    CZ.assign(N, 0);\n\n    for (int obj = 0; obj < 2; obj++) {\n        LAY[obj].assign(D, LayerData{});\n        int vmin = 0, vmax = 0;\n\n        for (int z = 0; z < D; z++) {\n            LayerData ld;\n            for (int x = 0; x < D; x++) if (F[obj][z][x] == '1') ld.X.push_back(x);\n            for (int y = 0; y < D; y++) if (Rv[obj][z][y] == '1') ld.Y.push_back(y);\n\n            int a = (int)ld.X.size();\n            int b = (int)ld.Y.size();\n            ld.base = max(a, b);\n            ld.cap = a * b - ld.base;\n            ld.allowed.reserve(a * b);\n            for (int x : ld.X) for (int y : ld.Y) ld.allowed.push_back(x * D + y);\n\n            vmin += ld.base;\n            vmax += a * b;\n            LAY[obj][z] = move(ld);\n        }\n\n        VminObj[obj] = vmin;\n        VmaxObj[obj] = vmax;\n\n        ColLife[obj].assign(D * D, 0);\n        for (int z = 0; z < D; z++) {\n            for (int idxy : LAY[obj][z].allowed) ColLife[obj][idxy]++;\n        }\n    }\n\n    parityCell.assign(N, 0);\n    neighbors.assign(N, {});\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        CX[id] = (unsigned char)x;\n        CY[id] = (unsigned char)y;\n        CZ[id] = (unsigned char)z;\n\n        parityCell[id] = (x + y + z) & 1;\n        auto& nb = neighbors[id];\n        if (x > 0) nb.push_back(id - SX);\n        if (x + 1 < D) nb.push_back(id + SX);\n        if (y > 0) nb.push_back(id - SY);\n        if (y + 1 < D) nb.push_back(id + SY);\n        if (z > 0) nb.push_back(id - SZ);\n        if (z + 1 < D) nb.push_back(id + SZ);\n    }\n\n    allSegs.assign(D + 1, {});\n    for (int L = 3; L <= D; L++) {\n        auto& v = allSegs[L];\n        v.reserve(3 * (D - L + 1) * D * D);\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int s = idx3(x, y, z);\n            if (x + L <= D) v.push_back({s, SX});\n            if (y + L <= D) v.push_back({s, SY});\n            if (z + L <= D) v.push_back({s, SZ});\n        }\n    }\n\n    cubeGroup = ShapeGroup{};\n    cubeGroup.k = 8;\n    cubeGroup.isLine = false;\n    for (int x = 0; x + 1 < D; x++) for (int y = 0; y + 1 < D; y++) for (int z = 0; z + 1 < D; z++) {\n        array<int,8> c = {\n            idx3(x, y, z), idx3(x + 1, y, z), idx3(x, y + 1, z), idx3(x + 1, y + 1, z),\n            idx3(x, y, z + 1), idx3(x + 1, y, z + 1), idx3(x, y + 1, z + 1), idx3(x + 1, y + 1, z + 1)\n        };\n        cubeGroup.plc.push_back(c);\n    }\n\n    build_rotations();\n    auto sh3 = enumerate_free_shapes(3);\n    auto sh4 = enumerate_free_shapes(4);\n    groups3 = build_groups_from_shapes(sh3, 3);\n    groups4 = build_groups_from_shapes(sh4, 4);\n}\n\nvector<int> allocate_add(int obj, int target, int mode, mt19937_64& rng) {\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    target = max(lo, min(hi, target));\n\n    int need = target - lo;\n    vector<int> add(D, 0);\n    if (need <= 0) return add;\n\n    int totalCap = hi - lo;\n    if (totalCap <= 0) return add;\n\n    if (mode == 1) {\n        vector<int> slots;\n        slots.reserve(totalCap);\n        for (int z = 0; z < D; z++) {\n            int c = LAY[obj][z].cap;\n            for (int t = 0; t < c; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < need; i++) add[slots[i]]++;\n        return add;\n    }\n\n    vector<long double> frac(D, -1.0L);\n    int used = 0;\n    for (int z = 0; z < D; z++) {\n        int cap = LAY[obj][z].cap;\n        if (!cap) continue;\n        long double ex = (long double)need * (long double)cap / (long double)totalCap;\n        int a = (int)floor(ex);\n        a = min(a, cap);\n        add[z] = a;\n        used += a;\n        frac[z] = ex - a + (long double)(rng() % 1000) * 1e-12L;\n    }\n\n    int rem = need - used;\n    vector<int> ord(D);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int p, int q) { return frac[p] > frac[q]; });\n\n    while (rem > 0) {\n        bool any = false;\n        for (int z : ord) {\n            if (!rem) break;\n            int cap = LAY[obj][z].cap;\n            if (add[z] < cap) {\n                add[z]++;\n                rem--;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n\n    if (rem > 0) {\n        vector<int> slots;\n        for (int z = 0; z < D; z++) {\n            int cap = LAY[obj][z].cap;\n            for (int t = add[z]; t < cap; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < rem && i < (int)slots.size(); i++) add[slots[i]]++;\n    }\n\n    return add;\n}\n\n// nLeft >= nRight\nvector<int> surjection_dp(const vector<vector<int>>& w, mt19937_64& rng) {\n    int nLeft = (int)w.size();\n    int nRight = (int)w[0].size();\n    int M = 1 << nRight;\n    const int NEG = -1000000000;\n\n    vector<int> dp(M, NEG), ndp(M, NEG);\n    vector<int> parMask((nLeft + 1) * M, -1);\n    vector<short> parChoice((nLeft + 1) * M, -1);\n\n    dp[0] = 0;\n    for (int i = 0; i < nLeft; i++) {\n        fill(ndp.begin(), ndp.end(), NEG);\n        int base = (i + 1) * M;\n\n        for (int mask = 0; mask < M; mask++) {\n            int cur = dp[mask];\n            if (cur <= NEG / 2) continue;\n            for (int j = 0; j < nRight; j++) {\n                int m2 = mask | (1 << j);\n                int val = cur + w[i][j];\n                if (val > ndp[m2] || (val == ndp[m2] && (rng() & 1ULL))) {\n                    ndp[m2] = val;\n                    parMask[base + m2] = mask;\n                    parChoice[base + m2] = (short)j;\n                }\n            }\n        }\n\n        dp.swap(ndp);\n    }\n\n    int full = M - 1;\n    vector<int> assign(nLeft, 0);\n\n    if (dp[full] <= NEG / 2) {\n        for (int i = 0; i < nLeft; i++) assign[i] = i % nRight;\n        return assign;\n    }\n\n    int mask = full;\n    for (int i = nLeft; i >= 1; i--) {\n        int pos = i * M + mask;\n        short c = parChoice[pos];\n        int pm = parMask[pos];\n        if (c < 0 || pm < 0) {\n            for (int t = 0; t < nLeft; t++) assign[t] = t % nRight;\n            return assign;\n        }\n        assign[i - 1] = (int)c;\n        mask = pm;\n    }\n\n    return assign;\n}\n\nvoid compute_features(Occupancy& oc) {\n    oc.zcnt.fill(0);\n    oc.xcnt.fill(0);\n    oc.ycnt.fill(0);\n\n    int adj6 = 0, zadj = 0;\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        if (!oc.occ[id]) continue;\n\n        oc.xcnt[x]++;\n        oc.ycnt[y]++;\n        oc.zcnt[z]++;\n\n        if (x + 1 < D && oc.occ[id + SX]) adj6++;\n        if (y + 1 < D && oc.occ[id + SY]) adj6++;\n        if (z + 1 < D && oc.occ[id + SZ]) { adj6++; zadj++; }\n    }\n    oc.adj6 = adj6;\n    oc.zadj = zadj;\n}\n\n// style:\n// 0 = DP surjection + continuity bias\n// 1 = grouped shift + continuity bias\n// 2 = random surjection\nOccupancy build_occ_target(int obj, int target, int style, mt19937_64& rng) {\n    Occupancy oc;\n    oc.occ.assign(N, 0);\n    oc.vol = 0;\n\n    int allocMode = (style == 2 ? 1 : 0);\n    vector<int> addz = allocate_add(obj, target, allocMode, rng);\n\n    vector<char> prevXY(D * D, 0), usedXY(D * D, 0);\n\n    for (int z = 0; z < D; z++) {\n        const auto& ld = LAY[obj][z];\n        int a = (int)ld.X.size();\n        int b = (int)ld.Y.size();\n        int m = ld.base + addz[z];\n\n        fill(usedXY.begin(), usedXY.end(), 0);\n        int edgeCount = 0;\n\n        auto put_edge = [&](int x, int y) {\n            int idxy = x * D + y;\n            if (usedXY[idxy]) return;\n            usedXY[idxy] = 1;\n            edgeCount++;\n            int id = idx3(x, y, z);\n            if (!oc.occ[id]) {\n                oc.occ[id] = 1;\n                oc.vol++;\n            }\n        };\n\n        int effStyle = style;\n        if (effStyle == 0 && min(a, b) > 11) effStyle = 1; // speed guard\n\n        // minimal cover\n        if (effStyle == 0) {\n            if (a >= b) {\n                vector<vector<int>> w(a, vector<int>(b, 0));\n                for (int i = 0; i < a; i++) {\n                    int x = ld.X[i];\n                    for (int j = 0; j < b; j++) {\n                        int y = ld.Y[j];\n                        int idxy = x * D + y;\n                        int val = (prevXY[idxy] ? 1000 : 0);\n                        val += ColLife[obj][idxy] * 4;\n                        val += (int)(rng() % 31);\n                        w[i][j] = val;\n                    }\n                }\n                auto assign = surjection_dp(w, rng);\n                for (int i = 0; i < a; i++) put_edge(ld.X[i], ld.Y[assign[i]]);\n            } else {\n                vector<vector<int>> w(b, vector<int>(a, 0));\n                for (int j = 0; j < b; j++) {\n                    int y = ld.Y[j];\n                    for (int i = 0; i < a; i++) {\n                        int x = ld.X[i];\n                        int idxy = x * D + y;\n                        int val = (prevXY[idxy] ? 1000 : 0);\n                        val += ColLife[obj][idxy] * 4;\n                        val += (int)(rng() % 31);\n                        w[j][i] = val;\n                    }\n                }\n                auto assign = surjection_dp(w, rng);\n                for (int j = 0; j < b; j++) put_edge(ld.X[assign[j]], ld.Y[j]);\n            }\n        } else if (effStyle == 1) {\n            vector<int> Xv = ld.X, Yv = ld.Y;\n            if (rng() & 1ULL) reverse(Xv.begin(), Xv.end());\n            if (rng() & 1ULL) reverse(Yv.begin(), Yv.end());\n\n            if (a >= b) {\n                int best = INT_MIN;\n                vector<int> bestSh;\n                for (int sh = 0; sh < b; sh++) {\n                    int mat = 0;\n                    for (int j = 0; j < a; j++) {\n                        int g = (int)((long long)j * b / a);\n                        int x = Xv[j];\n                        int y = Yv[(g + sh) % b];\n                        int idxy = x * D + y;\n                        mat += (prevXY[idxy] ? 10 : 0);\n                        mat += ColLife[obj][idxy];\n                    }\n                    if (mat > best) { best = mat; bestSh = {sh}; }\n                    else if (mat == best) bestSh.push_back(sh);\n                }\n                int shift = bestSh[(size_t)(rng() % bestSh.size())];\n                for (int j = 0; j < a; j++) {\n                    int g = (int)((long long)j * b / a);\n                    put_edge(Xv[j], Yv[(g + shift) % b]);\n                }\n            } else {\n                int best = INT_MIN;\n                vector<int> bestSh;\n                for (int sh = 0; sh < a; sh++) {\n                    int mat = 0;\n                    for (int j = 0; j < b; j++) {\n                        int g = (int)((long long)j * a / b);\n                        int x = Xv[(g + sh) % a];\n                        int y = Yv[j];\n                        int idxy = x * D + y;\n                        mat += (prevXY[idxy] ? 10 : 0);\n                        mat += ColLife[obj][idxy];\n                    }\n                    if (mat > best) { best = mat; bestSh = {sh}; }\n                    else if (mat == best) bestSh.push_back(sh);\n                }\n                int shift = bestSh[(size_t)(rng() % bestSh.size())];\n                for (int j = 0; j < b; j++) {\n                    int g = (int)((long long)j * a / b);\n                    put_edge(Xv[(g + shift) % a], Yv[j]);\n                }\n            }\n        } else {\n            if (a >= b) {\n                vector<int> Xv = ld.X;\n                shuffle(Xv.begin(), Xv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(a);\n                for (int y : ld.Y) pool.push_back(y);\n                for (int t = 0; t < a - b; t++) pool.push_back(ld.Y[(int)(rng() % b)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < a; j++) put_edge(Xv[j], pool[j]);\n            } else {\n                vector<int> Yv = ld.Y;\n                shuffle(Yv.begin(), Yv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(b);\n                for (int x : ld.X) pool.push_back(x);\n                for (int t = 0; t < b - a; t++) pool.push_back(ld.X[(int)(rng() % a)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < b; j++) put_edge(pool[j], Yv[j]);\n            }\n        }\n\n        // extras\n        int extra = m - edgeCount;\n        if (extra > 0) {\n            vector<int> cand;\n            cand.reserve(ld.allowed.size());\n            for (int idxy : ld.allowed) if (!usedXY[idxy]) cand.push_back(idxy);\n\n            if (extra >= (int)cand.size()) {\n                for (int idxy : cand) put_edge(idxy / D, idxy % D);\n            } else if (effStyle == 2) {\n                shuffle(cand.begin(), cand.end(), rng);\n                for (int t = 0; t < extra; t++) {\n                    int idxy = cand[t];\n                    put_edge(idxy / D, idxy % D);\n                }\n            } else {\n                for (int t = 0; t < extra; t++) {\n                    int bestId = -1, bestV = INT_MIN;\n                    for (int idxy : cand) {\n                        if (usedXY[idxy]) continue;\n                        int x = idxy / D, y = idxy % D;\n                        int sc = 0;\n                        sc += (prevXY[idxy] ? (effStyle == 0 ? 120 : 60) : 0);\n                        int adj = 0;\n                        if (x > 0 && usedXY[(x - 1) * D + y]) adj++;\n                        if (x + 1 < D && usedXY[(x + 1) * D + y]) adj++;\n                        if (y > 0 && usedXY[x * D + (y - 1)]) adj++;\n                        if (y + 1 < D && usedXY[x * D + (y + 1)]) adj++;\n                        sc += adj * (effStyle == 0 ? 12 : 8);\n                        sc += ColLife[obj][idxy] * (effStyle == 0 ? 2 : 1);\n                        sc += (int)(rng() % 16);\n                        if (sc > bestV) {\n                            bestV = sc;\n                            bestId = idxy;\n                        }\n                    }\n                    if (bestId < 0) break;\n                    put_edge(bestId / D, bestId % D);\n                }\n            }\n        }\n\n        prevXY = usedXY;\n    }\n\n    compute_features(oc);\n    return oc;\n}\n\nvector<Occupancy> generate_candidates(int obj, mt19937_64& rng) {\n    vector<Occupancy> cands;\n\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    int span = hi - lo;\n\n    if (span == 0) {\n        cands.push_back(build_occ_target(obj, lo, 0, rng));\n        cands.push_back(build_occ_target(obj, lo, 1, rng));\n        cands.push_back(build_occ_target(obj, lo, 2, rng));\n        return cands;\n    }\n\n    int softCap = (D <= 8 ? 52 : (D <= 11 ? 46 : 40));\n\n    vector<int> targets;\n    for (int q = 0; q <= 10; q++) targets.push_back(lo + (int)((long long)span * q / 10));                  // uniform\n    for (int q = 0; q <= 8; q++) targets.push_back(lo + (int)((long long)span * q * q / 64));               // low-biased\n    for (int q = 0; q <= 8; q++) targets.push_back(lo + (int)((long long)span * (64 - (8 - q)*(8 - q)) / 64)); // high-biased\n\n    targets.push_back(lo);\n    targets.push_back(lo + span / 4);\n    targets.push_back(lo + span / 2);\n    targets.push_back(lo + (3 * span) / 4);\n    targets.push_back(hi);\n\n    sort(targets.begin(), targets.end());\n    targets.erase(unique(targets.begin(), targets.end()), targets.end());\n\n    for (int T : targets) {\n        if ((int)cands.size() >= softCap) break;\n\n        if (T <= lo + max(1, span / 3)) {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            cands.push_back(build_occ_target(obj, T, 1, rng));\n            cands.push_back(build_occ_target(obj, T, 2, rng));\n        } else if (T >= lo + (2 * span) / 3) {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            if ((int)cands.size() < softCap) cands.push_back(build_occ_target(obj, T, 1, rng));\n        } else {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            if ((int)cands.size() < softCap) cands.push_back(build_occ_target(obj, T, 2, rng));\n        }\n    }\n\n    for (int t = 0; t < 8 && (int)cands.size() < softCap + 8; t++) {\n        long double u = (long double)(rng() % 1000000) / 1000000.0L;\n        if (t & 1) u = 1.0L - (1.0L - u) * (1.0L - u);\n        else u = u * u;\n        int T = lo + (int)llround((long double)span * u);\n\n        int styleRoll = (int)(rng() % 100);\n        int style = (styleRoll < 56 ? 0 : (styleRoll < 78 ? 1 : 2));\n        cands.push_back(build_occ_target(obj, T, style, rng));\n    }\n\n    return cands;\n}\n\nvector<int> pack_line_best_idx(const vector<char>& freeCells, int L, mt19937_64& rng, int tries = 2) {\n    const auto& pls = allSegs[L];\n\n    vector<int> valid;\n    valid.reserve(pls.size());\n\n    for (int i = 0; i < (int)pls.size(); i++) {\n        const auto& sg = pls[i];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!freeCells[p]) { ok = false; break; }\n        }\n        if (ok) valid.push_back(i);\n    }\n\n    if (valid.empty()) return {};\n\n    vector<int> best;\n    vector<int> rareOrder;\n\n    if (tries >= 2) {\n        vector<int> freq(N, 0);\n        for (int id : valid) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            for (int t = 0; t < L; t++, p += sg.stride) freq[p]++;\n        }\n\n        vector<pair<long long,int>> scored;\n        scored.reserve(valid.size());\n        for (int id : valid) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            int s = 0;\n            for (int t = 0; t < L; t++, p += sg.stride) s += freq[p];\n            long long key = (long long)s * 2048LL + (long long)(rng() & 2047ULL);\n            scored.push_back({key, id});\n        }\n        sort(scored.begin(), scored.end(), [](auto& a, auto& b){ return a.first < b.first; });\n        rareOrder.reserve(scored.size());\n        for (auto& p : scored) rareOrder.push_back(p.second);\n    }\n\n    for (int tr = 0; tr < tries; tr++) {\n        vector<int> order;\n        if (tr == 0 && !rareOrder.empty()) order = rareOrder;\n        else {\n            order = valid;\n            shuffle(order.begin(), order.end(), rng);\n        }\n\n        vector<char> tmp = freeCells;\n        vector<int> sel;\n        sel.reserve(order.size() / max(1, L) + 1);\n\n        for (int id : order) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            bool ok = true;\n            for (int t = 0; t < L; t++, p += sg.stride) {\n                if (!tmp[p]) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            sel.push_back(id);\n            p = sg.s;\n            for (int t = 0; t < L; t++, p += sg.stride) tmp[p] = 0;\n        }\n\n        if (sel.size() > best.size()) best.swap(sel);\n    }\n\n    return best;\n}\n\nvector<int> pack_group_best(const vector<char>& freeCells, const ShapeGroup& g, mt19937_64& rng, int tries = 2) {\n    int k = g.k;\n    const auto& pls = g.plc;\n\n    vector<int> valid;\n    valid.reserve(pls.size());\n\n    for (int i = 0; i < (int)pls.size(); i++) {\n        const auto& a = pls[i];\n        bool ok = true;\n        for (int t = 0; t < k; t++) {\n            if (!freeCells[a[t]]) { ok = false; break; }\n        }\n        if (ok) valid.push_back(i);\n    }\n\n    if (valid.empty()) return {};\n\n    vector<int> best;\n    vector<int> rareOrder;\n\n    if (tries >= 2) {\n        vector<int> freq(N, 0);\n        for (int id : valid) {\n            const auto& a = pls[id];\n            for (int t = 0; t < k; t++) freq[a[t]]++;\n        }\n\n        vector<pair<long long,int>> scored;\n        scored.reserve(valid.size());\n        for (int id : valid) {\n            const auto& a = pls[id];\n            int s = 0;\n            for (int t = 0; t < k; t++) s += freq[a[t]];\n            long long key = (long long)s * 2048LL + (long long)(rng() & 2047ULL);\n            scored.push_back({key, id});\n        }\n        sort(scored.begin(), scored.end(), [](auto& p, auto& q){ return p.first < q.first; });\n        rareOrder.reserve(scored.size());\n        for (auto& p : scored) rareOrder.push_back(p.second);\n    }\n\n    for (int tr = 0; tr < tries; tr++) {\n        vector<int> order;\n        if (tr == 0 && !rareOrder.empty()) order = rareOrder;\n        else {\n            order = valid;\n            shuffle(order.begin(), order.end(), rng);\n        }\n\n        vector<char> tmp = freeCells;\n        vector<int> sel;\n        sel.reserve(order.size() / max(1, k) + 1);\n\n        for (int id : order) {\n            const auto& a = pls[id];\n            bool ok = true;\n            for (int t = 0; t < k; t++) {\n                if (!tmp[a[t]]) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            sel.push_back(id);\n            for (int t = 0; t < k; t++) tmp[a[t]] = 0;\n        }\n\n        if (sel.size() > best.size()) best.swap(sel);\n    }\n\n    return best;\n}\n\nvector<pair<int,int>> max_domino_matching(const vector<char>& freeCells) {\n    vector<int> lid(N, -1), rid(N, -1);\n    vector<int> Lc, Rc;\n    Lc.reserve(N); Rc.reserve(N);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i]) continue;\n        if (parityCell[i] == 0) {\n            lid[i] = (int)Lc.size();\n            Lc.push_back(i);\n        } else {\n            rid[i] = (int)Rc.size();\n            Rc.push_back(i);\n        }\n    }\n\n    int Ls = (int)Lc.size();\n    int Rs = (int)Rc.size();\n\n    vector<vector<int>> g(Ls);\n    for (int u = 0; u < Ls; u++) {\n        int c = Lc[u];\n        auto& adj = g[u];\n        for (int nb : neighbors[c]) {\n            if (!freeCells[nb]) continue;\n            int v = rid[nb];\n            if (v != -1) adj.push_back(v);\n        }\n    }\n\n    vector<int> dist(Ls), matchL(Ls, -1), matchR(Rs, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(dist.begin(), dist.end(), -1);\n        bool found = false;\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                int u2 = matchR[v];\n                if (u2 == -1) {\n                    found = true;\n                } else if (dist[u2] == -1) {\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n            }\n        }\n        return found;\n    };\n\n    auto dfs = [&](auto&& self, int u) -> bool {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && self(self, u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int u = 0; u < Ls; u++) if (matchL[u] == -1) dfs(dfs, u);\n    }\n\n    vector<pair<int,int>> pairs;\n    pairs.reserve(Ls);\n    for (int u = 0; u < Ls; u++) {\n        if (matchL[u] != -1) pairs.push_back({Lc[u], Rc[matchL[u]]});\n    }\n    return pairs;\n}\n\nvector<vector<int>> extract_components(const vector<char>& freeCells) {\n    vector<char> vis(N, 0);\n    vector<vector<int>> comps;\n    vector<int> q;\n    q.reserve(256);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i] || vis[i]) continue;\n        q.clear();\n        q.push_back(i);\n        vis[i] = 1;\n\n        vector<int> comp;\n        comp.reserve(16);\n\n        for (int qi = 0; qi < (int)q.size(); qi++) {\n            int v = q[qi];\n            comp.push_back(v);\n            for (int nb : neighbors[v]) {\n                if (freeCells[nb] && !vis[nb]) {\n                    vis[nb] = 1;\n                    q.push_back(nb);\n                }\n            }\n        }\n        comps.push_back(move(comp));\n    }\n\n    return comps;\n}\n\nstring canonical_key_component(const vector<int>& cells) {\n    int k = (int)cells.size();\n\n    vector<Pt> pts;\n    pts.reserve(k);\n    for (int id : cells) pts.push_back({(int)CX[id], (int)CY[id], (int)CZ[id]});\n\n    string best;\n    bool first = true;\n    vector<Pt> t;\n    t.reserve(k);\n\n    for (const auto& r : ROTS) {\n        t.clear();\n        int mnx = 1e9, mny = 1e9, mnz = 1e9;\n        for (const auto& p : pts) {\n            Pt q = rotate_pt(p, r);\n            mnx = min(mnx, q.x);\n            mny = min(mny, q.y);\n            mnz = min(mnz, q.z);\n            t.push_back(q);\n        }\n\n        for (auto& q : t) {\n            q.x -= mnx;\n            q.y -= mny;\n            q.z -= mnz;\n        }\n\n        sort(t.begin(), t.end(), [](const Pt& a, const Pt& b) {\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        string key;\n        key.resize(3 * k);\n        int pos = 0;\n        for (auto& q : t) {\n            key[pos++] = (char)q.x;\n            key[pos++] = (char)q.y;\n            key[pos++] = (char)q.z;\n        }\n\n        if (first || key < best) {\n            first = false;\n            best = move(key);\n        }\n    }\n\n    return best;\n}\n\nvoid small_component_match(\n    vector<char>& free1, vector<char>& free2,\n    vector<int>& b1, vector<int>& b2,\n    int& id, int& sharedVol, long double& sharedTerm,\n    int threshold,\n    mt19937_64& rng\n) {\n    int c1 = 0, c2 = 0;\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) c1++;\n        if (free2[i]) c2++;\n    }\n    int mn = min(c1, c2);\n    if (mn < 3 || mn > threshold) return;\n\n    auto comps1 = extract_components(free1);\n    auto comps2 = extract_components(free2);\n\n    unordered_map<string, vector<int>> mp1, mp2;\n    mp1.reserve(comps1.size() * 2 + 1);\n    mp2.reserve(comps2.size() * 2 + 1);\n\n    for (int i = 0; i < (int)comps1.size(); i++) {\n        int s = (int)comps1[i].size();\n        if (s < 3) continue;\n        string key = canonical_key_component(comps1[i]);\n        key.push_back((char)(unsigned char)s); // size tag\n        mp1[key].push_back(i);\n    }\n    for (int i = 0; i < (int)comps2.size(); i++) {\n        int s = (int)comps2[i].size();\n        if (s < 3) continue;\n        string key = canonical_key_component(comps2[i]);\n        key.push_back((char)(unsigned char)s);\n        mp2[key].push_back(i);\n    }\n\n    for (auto& kv : mp1) {\n        auto it = mp2.find(kv.first);\n        if (it == mp2.end()) continue;\n\n        auto& v1 = kv.second;\n        auto& v2 = it->second;\n        shuffle(v1.begin(), v1.end(), rng);\n        shuffle(v2.begin(), v2.end(), rng);\n\n        int s = min((int)v1.size(), (int)v2.size());\n        for (int t = 0; t < s; t++) {\n            int i1 = v1[t], i2 = v2[t];\n            int sz = (int)comps1[i1].size();\n\n            ++id;\n            for (int c : comps1[i1]) {\n                b1[c] = id;\n                free1[c] = 0;\n            }\n            for (int c : comps2[i2]) {\n                b2[c] = id;\n                free2[c] = 0;\n            }\n\n            sharedVol += sz;\n            sharedTerm += 1.0L / (long double)sz;\n        }\n    }\n}\n\nSolution make_solution(const Occupancy& o1, const Occupancy& o2, mt19937_64& rng) {\n    vector<char> free1 = o1.occ;\n    vector<char> free2 = o2.occ;\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int id = 0;\n    int sharedVol = 0;\n    long double sharedTerm = 0.0L;\n\n    auto apply_line_pair = [&](int L, int tries) {\n        if (L < 3) return;\n        auto s1 = pack_line_best_idx(free1, L, rng, tries);\n        auto s2 = pack_line_best_idx(free2, L, rng, tries);\n\n        int s = min((int)s1.size(), (int)s2.size());\n        if (s == 0) return;\n\n        if ((int)s1.size() > s) { shuffle(s1.begin(), s1.end(), rng); s1.resize(s); }\n        if ((int)s2.size() > s) { shuffle(s2.begin(), s2.end(), rng); s2.resize(s); }\n\n        const auto& pls = allSegs[L];\n        for (int i = 0; i < s; i++) {\n            ++id;\n            const auto& A = pls[s1[i]];\n            int p = A.s;\n            for (int t = 0; t < L; t++, p += A.stride) {\n                b1[p] = id;\n                free1[p] = 0;\n            }\n\n            const auto& B = pls[s2[i]];\n            p = B.s;\n            for (int t = 0; t < L; t++, p += B.stride) {\n                b2[p] = id;\n                free2[p] = 0;\n            }\n\n            sharedVol += L;\n            sharedTerm += 1.0L / (long double)L;\n        }\n    };\n\n    auto apply_group_pair = [&](const ShapeGroup& g, int tries) {\n        auto s1 = pack_group_best(free1, g, rng, tries);\n        auto s2 = pack_group_best(free2, g, rng, tries);\n\n        int s = min((int)s1.size(), (int)s2.size());\n        if (s == 0) return;\n\n        if ((int)s1.size() > s) { shuffle(s1.begin(), s1.end(), rng); s1.resize(s); }\n        if ((int)s2.size() > s) { shuffle(s2.begin(), s2.end(), rng); s2.resize(s); }\n\n        int k = g.k;\n        for (int i = 0; i < s; i++) {\n            ++id;\n            const auto& A = g.plc[s1[i]];\n            const auto& B = g.plc[s2[i]];\n            for (int t = 0; t < k; t++) {\n                b1[A[t]] = id;\n                free1[A[t]] = 0;\n            }\n            for (int t = 0; t < k; t++) {\n                b2[B[t]] = id;\n                free2[B[t]] = 0;\n            }\n            sharedVol += k;\n            sharedTerm += 1.0L / (long double)k;\n        }\n    };\n\n    int variant = (int)(rng() % 5);\n\n    if (variant == 0) {\n        for (int L = D; L >= 9; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n        for (int L = min(8, D); L >= 5; L--) apply_line_pair(L, 2);\n    } else if (variant == 1) {\n        apply_group_pair(cubeGroup, 2);\n        for (int L = D; L >= 5; L--) apply_line_pair(L, 2);\n    } else if (variant == 2) {\n        for (int L = D; L >= 5; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n    } else if (variant == 3) {\n        for (int L = D; L >= 6; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n        if (D >= 5) apply_line_pair(5, 2);\n    } else {\n        for (int L = D; L >= 7; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 1);\n        for (int L = min(6, D); L >= 5; L--) apply_line_pair(L, 2);\n    }\n\n    // tetracubes\n    vector<int> ord4(groups4.size());\n    iota(ord4.begin(), ord4.end(), 0);\n    int p4 = (int)(rng() % 4);\n    if (p4 == 0) {\n        shuffle(ord4.begin(), ord4.end(), rng);\n    } else if (p4 == 1) {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            return groups4[i].plc.size() < groups4[j].plc.size();\n        });\n    } else if (p4 == 2) {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            return groups4[i].plc.size() > groups4[j].plc.size();\n        });\n    } else {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            if (groups4[i].isLine != groups4[j].isLine) return groups4[i].isLine > groups4[j].isLine;\n            return groups4[i].plc.size() < groups4[j].plc.size();\n        });\n    }\n    for (int idx : ord4) {\n        int tries = 2;\n        if (groups4[idx].isLine && (rng() % 100) < 30) tries = 3;\n        apply_group_pair(groups4[idx], tries);\n    }\n\n    // tricubes\n    vector<int> ord3(groups3.size());\n    iota(ord3.begin(), ord3.end(), 0);\n    if ((rng() & 1ULL) == 0) {\n        sort(ord3.begin(), ord3.end(), [&](int i, int j) {\n            if (groups3[i].isLine != groups3[j].isLine) return groups3[i].isLine > groups3[j].isLine;\n            return groups3[i].plc.size() < groups3[j].plc.size();\n        });\n    } else {\n        shuffle(ord3.begin(), ord3.end(), rng);\n    }\n    for (int idx : ord3) apply_group_pair(groups3[idx], 2);\n\n    auto free_count = [&](const vector<char>& f) {\n        int c = 0;\n        for (char v : f) c += (v != 0);\n        return c;\n    };\n\n    // cheap exact component matching only for small leftovers\n    int fmin = min(free_count(free1), free_count(free2));\n    if (fmin <= 180) {\n        small_component_match(free1, free2, b1, b2, id, sharedVol, sharedTerm, 180, rng);\n    }\n\n    // domino\n    auto d1 = max_domino_matching(free1);\n    auto d2 = max_domino_matching(free2);\n    int sd = min((int)d1.size(), (int)d2.size());\n\n    if (sd > 0) {\n        if ((int)d1.size() > sd) { shuffle(d1.begin(), d1.end(), rng); d1.resize(sd); }\n        if ((int)d2.size() > sd) { shuffle(d2.begin(), d2.end(), rng); d2.resize(sd); }\n\n        for (int i = 0; i < sd; i++) {\n            ++id;\n            auto [a, b] = d1[i];\n            b1[a] = id; b1[b] = id;\n            free1[a] = 0; free1[b] = 0;\n\n            auto [c, d] = d2[i];\n            b2[c] = id; b2[d] = id;\n            free2[c] = 0; free2[d] = 0;\n\n            sharedVol += 2;\n            sharedTerm += 0.5L;\n        }\n    }\n\n    fmin = min(free_count(free1), free_count(free2));\n    if (fmin <= 64) {\n        small_component_match(free1, free2, b1, b2, id, sharedVol, sharedTerm, 64, rng);\n    }\n\n    // monomino fallback\n    vector<int> rem1, rem2;\n    rem1.reserve(N); rem2.reserve(N);\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) rem1.push_back(i);\n        if (free2[i]) rem2.push_back(i);\n    }\n\n    shuffle(rem1.begin(), rem1.end(), rng);\n    shuffle(rem2.begin(), rem2.end(), rng);\n\n    int sm = min((int)rem1.size(), (int)rem2.size());\n    for (int i = 0; i < sm; i++) {\n        ++id;\n        b1[rem1[i]] = id;\n        b2[rem2[i]] = id;\n        sharedVol += 1;\n        sharedTerm += 1.0L;\n    }\n    for (int i = sm; i < (int)rem1.size(); i++) {\n        ++id;\n        b1[rem1[i]] = id;\n    }\n    for (int i = sm; i < (int)rem2.size(); i++) {\n        ++id;\n        b2[rem2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = (long double)(o1.vol + o2.vol - 2 * sharedVol) + sharedTerm;\n    return sol;\n}\n\nbool check_silhouette_one(const vector<int>& b, int obj) {\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) {\n            bool seen = false;\n            for (int y = 0; y < D; y++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (F[obj][z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; y++) {\n            bool seen = false;\n            for (int x = 0; x < D; x++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (Rv[obj][z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nbool check_silhouette(const Solution& sol) {\n    if ((int)sol.b1.size() != N || (int)sol.b2.size() != N) return false;\n    return check_silhouette_one(sol.b1, 0) && check_silhouette_one(sol.b2, 1);\n}\n\nSolution fallback_simple() {\n    vector<int> b1(N, 0), b2(N, 0);\n    vector<int> c1, c2;\n    c1.reserve(N); c2.reserve(N);\n\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (F[0][z][x] == '1' && Rv[0][z][y] == '1') c1.push_back(idx3(x, y, z));\n        if (F[1][z][x] == '1' && Rv[1][z][y] == '1') c2.push_back(idx3(x, y, z));\n    }\n\n    int id = 0;\n    int m = min((int)c1.size(), (int)c2.size());\n    for (int i = 0; i < m; i++) {\n        ++id;\n        b1[c1[i]] = id;\n        b2[c2[i]] = id;\n    }\n    for (int i = m; i < (int)c1.size(); i++) {\n        ++id;\n        b1[c1[i]] = id;\n    }\n    for (int i = m; i < (int)c2.size(); i++) {\n        ++id;\n        b2[c2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = 1e99L;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        Rv[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> Rv[i][z];\n    }\n\n    precompute();\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count()\n        ^ ((uint64_t)D * 1000003ULL)\n    );\n\n    const double TL = 5.35;\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    Solution best;\n    const long double INF = 1e100L;\n\n    Occupancy bestO1, bestO2;\n    bool haveBestOcc = false;\n\n    int overlapL = max(VminObj[0], VminObj[1]);\n    int overlapU = min(VmaxObj[0], VmaxObj[1]);\n    bool hasOverlap = (overlapL <= overlapU);\n\n    auto try_pair = [&](const Occupancy& o1, const Occupancy& o2, int repsBase) -> long double {\n        if (elapsed() >= TL) return INF;\n\n        int mn = min(o1.vol, o2.vol);\n        long double lb = fabsl((long double)o1.vol - (long double)o2.vol) + 1.0L / (long double)mn;\n        if (lb + 1e-12L >= best.score) return INF;\n\n        int reps = repsBase;\n        if (best.score < INF / 2) {\n            if (lb < best.score * 0.72L) reps = max(reps, 2);\n            if (lb < best.score * 0.58L) reps = max(reps, 3);\n        }\n        if (elapsed() > TL * 0.90) reps = 1;\n\n        long double localBest = INF;\n        for (int t = 0; t < reps; t++) {\n            if (elapsed() >= TL) break;\n            Solution cur = make_solution(o1, o2, rng);\n            localBest = min(localBest, cur.score);\n            if (cur.score < best.score) {\n                best = move(cur);\n                bestO1 = o1;\n                bestO2 = o2;\n                haveBestOcc = true;\n            }\n        }\n        return localBest;\n    };\n\n    // initial\n    {\n        int t1, t2;\n        if (hasOverlap) {\n            t1 = overlapL;\n            t2 = overlapL;\n        } else if (VmaxObj[0] < VminObj[1]) {\n            t1 = VmaxObj[0];\n            t2 = VminObj[1];\n        } else {\n            t1 = VminObj[0];\n            t2 = VmaxObj[1];\n        }\n        Occupancy o1 = build_occ_target(0, t1, 0, rng);\n        Occupancy o2 = build_occ_target(1, t2, 0, rng);\n        try_pair(o1, o2, 3);\n    }\n\n    vector<Occupancy> cand1, cand2;\n    if (elapsed() < TL * 0.35) {\n        cand1 = generate_candidates(0, rng);\n        cand2 = generate_candidates(1, rng);\n    } else {\n        cand1.push_back(build_occ_target(0, VminObj[0], 0, rng));\n        cand2.push_back(build_occ_target(1, VminObj[1], 0, rng));\n    }\n\n    auto l1arr = [&](const array<int,14>& a, const array<int,14>& b) {\n        int s = 0;\n        for (int i = 0; i < D; i++) s += abs(a[i] - b[i]);\n        return s;\n    };\n\n    struct PairCand {\n        int i, j;\n        int dZ;\n        int dXY;\n        int zmin;\n        int amin;\n        long double lb;\n        uint64_t tie;\n    };\n\n    vector<PairCand> plist;\n    plist.reserve((int)cand1.size() * (int)cand2.size());\n\n    for (int i = 0; i < (int)cand1.size(); i++) {\n        for (int j = 0; j < (int)cand2.size(); j++) {\n            int mn = min(cand1[i].vol, cand2[j].vol);\n            long double lb = fabsl((long double)cand1[i].vol - (long double)cand2[j].vol)\n                           + 1.0L / (long double)mn;\n\n            int dZ = l1arr(cand1[i].zcnt, cand2[j].zcnt);\n            int dXY = l1arr(cand1[i].xcnt, cand2[j].xcnt) + l1arr(cand1[i].ycnt, cand2[j].ycnt);\n            int zmin = min(cand1[i].zadj, cand2[j].zadj);\n            int amin = min(cand1[i].adj6, cand2[j].adj6);\n\n            plist.push_back({i, j, dZ, dXY, zmin, amin, lb, rng()});\n        }\n    }\n\n    sort(plist.begin(), plist.end(), [](const PairCand& a, const PairCand& b) {\n        if (fabsl(a.lb - b.lb) > 1e-12L) return a.lb < b.lb;\n        if (a.dZ != b.dZ) return a.dZ < b.dZ;\n        if (a.dXY != b.dXY) return a.dXY < b.dXY;\n        if (a.zmin != b.zmin) return a.zmin > b.zmin;\n        if (a.amin != b.amin) return a.amin > b.amin;\n        return a.tie < b.tie;\n    });\n\n    vector<tuple<long double,int,int>> records;\n    int initLimit = min((int)plist.size(), (D <= 8 ? 260 : (D <= 11 ? 220 : 180)));\n\n    for (int p = 0; p < initLimit; p++) {\n        if (elapsed() >= TL * 0.60) break;\n        const auto& pc = plist[p];\n        int reps = (p < 26 ? 2 : 1);\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], reps);\n        if (sc < INF / 10) records.emplace_back(sc, pc.i, pc.j);\n    }\n\n    if (records.empty() && !plist.empty() && elapsed() < TL) {\n        const auto& pc = plist[0];\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], 1);\n        if (sc < INF / 10) records.emplace_back(sc, pc.i, pc.j);\n    }\n\n    sort(records.begin(), records.end(), [](const auto& A, const auto& B) {\n        return get<0>(A) < get<0>(B);\n    });\n\n    vector<pair<int,int>> eliteIdx;\n    int eN = min((int)records.size(), 40);\n    for (int i = 0; i < eN; i++) eliteIdx.push_back({get<1>(records[i]), get<2>(records[i])});\n\n    struct DynPair {\n        Occupancy o1, o2;\n        long double sc;\n    };\n    vector<DynPair> dyn;\n\n    auto add_dyn = [&](const Occupancy& o1, const Occupancy& o2, long double sc) {\n        if (!(sc < INF / 10)) return;\n        if ((int)dyn.size() < 10) {\n            dyn.push_back({o1, o2, sc});\n        } else {\n            int worst = 0;\n            for (int i = 1; i < (int)dyn.size(); i++) if (dyn[i].sc > dyn[worst].sc) worst = i;\n            if (sc < dyn[worst].sc) dyn[worst] = {o1, o2, sc};\n        }\n    };\n\n    for (int i = 0; i < min((int)records.size(), 8); i++) {\n        int ii = get<1>(records[i]), jj = get<2>(records[i]);\n        add_dyn(cand1[ii], cand2[jj], get<0>(records[i]));\n    }\n\n    double phase1End = TL * 0.92;\n\n    while (elapsed() < phase1End) {\n        int r = (int)(rng() % 100);\n\n        if (!eliteIdx.empty() && r < 50) {\n            auto [i, j] = eliteIdx[(size_t)(rng() % eliteIdx.size())];\n            int reps = ((rng() % 100) < 25 ? 2 : 1);\n            try_pair(cand1[i], cand2[j], reps);\n        } else if (!dyn.empty() && r < 78) {\n            int idp = (int)(rng() % dyn.size());\n            int reps = ((rng() % 100) < 30 ? 2 : 1);\n            long double sc = try_pair(dyn[idp].o1, dyn[idp].o2, reps);\n            dyn[idp].sc = min(dyn[idp].sc, sc);\n        } else {\n            int style1Roll = (int)(rng() % 100);\n            int style1 = (style1Roll < 56 ? 0 : (style1Roll < 78 ? 1 : 2));\n            int style2;\n            if ((rng() % 100) < 72) style2 = style1;\n            else {\n                int rr = (int)(rng() % 100);\n                style2 = (rr < 56 ? 0 : (rr < 78 ? 1 : 2));\n            }\n\n            int t1, t2;\n\n            if (haveBestOcc && (rng() % 100) < 35) {\n                int span1 = max(1, (VmaxObj[0] - VminObj[0]) / 20);\n                int span2 = max(1, (VmaxObj[1] - VminObj[1]) / 20);\n                int d1 = (int)(rng() % (2 * span1 + 1)) - span1;\n                int d2 = (int)(rng() % (2 * span2 + 1)) - span2;\n                t1 = clampi(bestO1.vol + d1, VminObj[0], VmaxObj[0]);\n                t2 = clampi(bestO2.vol + d2, VminObj[1], VmaxObj[1]);\n            } else if (hasOverlap && (rng() % 100) < 88) {\n                int span = overlapU - overlapL;\n                long double u = (long double)(rng() % 1000000) / 1000000.0L;\n                if ((rng() & 1ULL) == 0) u = u * u;\n                else u = 1.0L - (1.0L - u) * (1.0L - u);\n                int T = overlapL + (int)llround((long double)span * u);\n\n                int jit = max(0, span / 12);\n                int d1 = (jit ? (int)(rng() % (2 * jit + 1)) - jit : 0);\n                int d2 = (jit ? (int)(rng() % (2 * jit + 1)) - jit : 0);\n\n                t1 = clampi(T + d1, VminObj[0], VmaxObj[0]);\n                t2 = clampi(T + d2, VminObj[1], VmaxObj[1]);\n            } else if (VmaxObj[0] < VminObj[1]) {\n                int a = min(8, VmaxObj[0] - VminObj[0]);\n                int b = min(8, VmaxObj[1] - VminObj[1]);\n                t1 = VmaxObj[0] - (a ? (int)(rng() % (a + 1)) : 0);\n                t2 = VminObj[1] + (b ? (int)(rng() % (b + 1)) : 0);\n            } else if (VmaxObj[1] < VminObj[0]) {\n                int a = min(8, VmaxObj[0] - VminObj[0]);\n                int b = min(8, VmaxObj[1] - VminObj[1]);\n                t1 = VminObj[0] + (a ? (int)(rng() % (a + 1)) : 0);\n                t2 = VmaxObj[1] - (b ? (int)(rng() % (b + 1)) : 0);\n            } else {\n                int span1 = VmaxObj[0] - VminObj[0];\n                int span2 = VmaxObj[1] - VminObj[1];\n                long double u1 = (long double)(rng() % 1000000) / 1000000.0L;\n                long double u2 = (long double)(rng() % 1000000) / 1000000.0L;\n                if ((rng() & 1ULL) == 0) u1 = u1 * u1;\n                if ((rng() & 1ULL) == 0) u2 = u2 * u2;\n                t1 = VminObj[0] + (int)llround((long double)span1 * u1);\n                t2 = VminObj[1] + (int)llround((long double)span2 * u2);\n            }\n\n            Occupancy o1 = build_occ_target(0, t1, style1, rng);\n            Occupancy o2 = build_occ_target(1, t2, style2, rng);\n\n            long double sc = try_pair(o1, o2, 1);\n            if (sc < best.score * 1.28L) add_dyn(o1, o2, sc);\n        }\n    }\n\n    // Final intensification (repack best occupancy pairs)\n    vector<pair<Occupancy, Occupancy>> focus;\n    if (haveBestOcc) focus.push_back({bestO1, bestO2});\n\n    for (int i = 0; i < min((int)records.size(), 8); i++) {\n        int ii = get<1>(records[i]), jj = get<2>(records[i]);\n        focus.push_back({cand1[ii], cand2[jj]});\n    }\n\n    sort(dyn.begin(), dyn.end(), [](const DynPair& a, const DynPair& b) { return a.sc < b.sc; });\n    for (int i = 0; i < min((int)dyn.size(), 5); i++) {\n        focus.push_back({dyn[i].o1, dyn[i].o2});\n    }\n\n    while (elapsed() < TL && !focus.empty()) {\n        auto& pp = focus[(size_t)(rng() % focus.size())];\n        Solution cur = make_solution(pp.first, pp.second, rng);\n        if (cur.score < best.score) {\n            best = move(cur);\n            bestO1 = pp.first;\n            bestO2 = pp.second;\n            haveBestOcc = true;\n        }\n    }\n\n    if (best.n == 0 || !check_silhouette(best)) {\n        best = fallback_simple();\n    }\n\n    cout << best.n << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b2[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(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    using ll = long long;\n    static constexpr ll INF = (1LL << 62);\n    static constexpr int MAXN = 105;\n    static constexpr int MAXM = 305;\n    static constexpr int RAD = 5000;\n\n    int N, M, K;\n\n    struct Edge {\n        int u, v, w;\n    };\n\n    vector<int> x, y;\n    vector<Edge> edges;\n    vector<int> a, b;\n\n    vector<vector<pair<int, int>>> g; // (to, edge_id)\n    vector<vector<int>> incident;\n    vector<int> edgeOrder; // edge ids sorted by w\n\n    vector<vector<uint16_t>> distSR; // [N][K]\n\n    // resident -> candidates within 5000 (dist, station), sorted by dist\n    vector<vector<pair<uint16_t, int>>> cand;\n\n    // station -> residents within 5000 (dist, resident), sorted by dist\n    vector<vector<pair<uint16_t, int>>> byStation;\n    vector<vector<int>> coverResidents; // station -> residents\n\n    // APSP\n    vector<vector<ll>> spDist;\n    vector<vector<int>> prevNode;\n    vector<vector<int>> prevEdge;\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point startTime;\n\n    struct Key {\n        uint64_t lo = 0, hi = 0;\n        bool operator==(const Key &o) const noexcept {\n            return lo == o.lo && hi == o.hi;\n        }\n    };\n    struct KeyHash {\n        size_t operator()(const Key &k) const noexcept {\n            size_t h1 = std::hash<uint64_t>{}(k.lo);\n            size_t h2 = std::hash<uint64_t>{}(k.hi);\n            return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));\n        }\n    };\n\n    unordered_map<Key, ll, KeyHash> cacheFast;\n    unordered_map<Key, ll, KeyHash> cacheExact;\n\n    struct Solution {\n        bool feasible = false;\n        ll cost = INF;\n        vector<int> P;\n        vector<char> B;\n    };\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static int ceilDistInt(int x1, int y1, int x2, int y2) {\n        long long dx = 1LL * x1 - x2;\n        long long dy = 1LL * y1 - y2;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)std::sqrt((double)sq);\n        while (1LL * d * d < sq) ++d;\n        while (d > 0 && 1LL * (d - 1) * (d - 1) >= sq) --d;\n        return d;\n    }\n\n    Key makeKey(const vector<char> &active) const {\n        Key k;\n        for (int i = 0; i < N; i++) {\n            if (!active[i]) continue;\n            if (i < 64) k.lo |= (1ULL << i);\n            else k.hi |= (1ULL << (i - 64));\n        }\n        return k;\n    }\n\n    bool sameState(const vector<char> &A, const vector<char> &B) const {\n        if ((int)A.size() != N || (int)B.size() != N) return false;\n        for (int i = 0; i < N; i++) {\n            if (A[i] != B[i]) return false;\n        }\n        return true;\n    }\n\n    void addUniqueState(vector<vector<char>> &vec, const vector<char> &st) {\n        for (auto &v : vec) {\n            if (sameState(v, st)) return;\n        }\n        vec.push_back(st);\n    }\n\n    void pushPool(vector<pair<ll, vector<char>>> &pool, const vector<char> &st, ll cost, int lim = 14) {\n        for (auto &p : pool) {\n            if (sameState(p.second, st)) {\n                if (cost < p.first) p.first = cost;\n                sort(pool.begin(), pool.end(), [](auto &L, auto &R) { return L.first < R.first; });\n                if ((int)pool.size() > lim) pool.resize(lim);\n                return;\n            }\n        }\n        pool.push_back({cost, st});\n        sort(pool.begin(), pool.end(), [](auto &L, auto &R) { return L.first < R.first; });\n        if ((int)pool.size() > lim) pool.resize(lim);\n    }\n\n    void readInput() {\n        cin >> N >> M >> K;\n        x.resize(N);\n        y.resize(N);\n        for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(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            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        }\n\n        a.resize(K);\n        b.resize(K);\n        for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n        edgeOrder.resize(M);\n        iota(edgeOrder.begin(), edgeOrder.end(), 0);\n        sort(edgeOrder.begin(), edgeOrder.end(),\n             [&](int e1, int e2) { return edges[e1].w < edges[e2].w; });\n    }\n\n    void precomputeDistances() {\n        distSR.assign(N, vector<uint16_t>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                int d = ceilDistInt(x[i], y[i], a[k], b[k]);\n                if (d > 65535) d = 65535;\n                distSR[i][k] = (uint16_t)d;\n            }\n        }\n\n        cand.assign(K, {});\n        byStation.assign(N, {});\n\n        for (int k = 0; k < K; k++) {\n            auto &v = cand[k];\n            v.reserve(N);\n            for (int i = 0; i < N; i++) {\n                int d = distSR[i][k];\n                if (d <= RAD) v.push_back({(uint16_t)d, i});\n            }\n            sort(v.begin(), v.end(), [](auto &L, auto &R) {\n                if (L.first != R.first) return L.first < R.first;\n                return L.second < R.second;\n            });\n\n            // safety fallback\n            if (v.empty()) {\n                int bestI = 0, bestD = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    int d = distSR[i][k];\n                    if (d < bestD) bestD = d, bestI = i;\n                }\n                v.push_back({(uint16_t)bestD, bestI});\n            }\n\n            for (auto &pr : v) {\n                byStation[pr.second].push_back({pr.first, k});\n            }\n        }\n\n        coverResidents.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            auto &bs = byStation[i];\n            sort(bs.begin(), bs.end(), [](auto &L, auto &R) {\n                if (L.first != R.first) return L.first < R.first;\n                return L.second < R.second;\n            });\n            coverResidents[i].reserve(bs.size());\n            for (auto &pr : bs) coverResidents[i].push_back(pr.second);\n        }\n    }\n\n    void precomputeShortestPaths() {\n        spDist.assign(N, vector<ll>(N, INF));\n        prevNode.assign(N, vector<int>(N, -1));\n        prevEdge.assign(N, vector<int>(N, -1));\n\n        for (int s = 0; s < N; s++) {\n            vector<ll> d(N, INF);\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            d[s] = 0;\n            prevNode[s][s] = s;\n            prevEdge[s][s] = -1;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n                if (cd != d[v]) continue;\n\n                for (auto [to, eid] : g[v]) {\n                    ll nd = cd + edges[eid].w;\n                    if (nd < d[to]) {\n                        d[to] = nd;\n                        prevNode[s][to] = v;\n                        prevEdge[s][to] = eid;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n            spDist[s] = move(d);\n        }\n    }\n\n    bool buildPNearest(const vector<char> &active, int P[]) {\n        for (int i = 0; i < N; i++) P[i] = 0;\n\n        for (int k = 0; k < K; k++) {\n            int chosen = -1, d = 0;\n            for (auto &pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return false;\n            if (d > P[chosen]) P[chosen] = d;\n        }\n        return true;\n    }\n\n    void shrinkPArray(int P[], bool full) {\n        vector<int> cnt(K, 0);\n\n        for (int i = 0; i < N; i++) {\n            int pi = P[i];\n            if (pi <= 0) continue;\n            for (auto &pr : byStation[i]) {\n                int d = pr.first, k = pr.second;\n                if (d > pi) break;\n                cnt[k]++;\n            }\n        }\n\n        int maxPass = full ? 1000 : 2;\n        for (int pass = 0; pass < maxPass; pass++) {\n            bool changed = false;\n\n            for (int i = 0; i < N; i++) {\n                int old = P[i];\n                if (old <= 0) continue;\n\n                int req = 0;\n                for (auto &pr : byStation[i]) {\n                    int d = pr.first, k = pr.second;\n                    if (d > old) break;\n                    if (cnt[k] == 1 && d > req) req = d;\n                }\n\n                if (req < old) {\n                    for (auto &pr : byStation[i]) {\n                        int d = pr.first, k = pr.second;\n                        if (d > old) break;\n                        if (d > req) cnt[k]--;\n                    }\n                    P[i] = req;\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    ll pruneAlive(vector<char> &alive, const vector<int> &terminals) {\n        vector<int> deg(N, 0);\n        vector<char> isTerm(N, 0);\n        for (int v : terminals) isTerm[v] = 1;\n\n        ll cost = 0;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            cost += edges[eid].w;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        return cost;\n    }\n\n    ll steinerKMB(const int terminals[], int t, vector<char> *outB) {\n        if (outB) outB->assign(M, 0);\n        if (t <= 1) return 0;\n\n        ll minD[MAXN];\n        int parent[MAXN];\n        bool used[MAXN];\n        for (int i = 0; i < t; i++) {\n            minD[i] = INF;\n            parent[i] = -1;\n            used[i] = false;\n        }\n        minD[0] = 0;\n\n        // Prim on metric closure\n        for (int it = 0; it < t; it++) {\n            int v = -1;\n            for (int i = 0; i < t; i++) {\n                if (!used[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            if (v == -1) return INF;\n            used[v] = true;\n\n            int tv = terminals[v];\n            for (int j = 0; j < t; j++) {\n                if (used[j]) continue;\n                ll nd = spDist[tv][terminals[j]];\n                if (nd < minD[j]) {\n                    minD[j] = nd;\n                    parent[j] = v;\n                }\n            }\n        }\n\n        unsigned char marked[MAXM] = {};\n        unsigned char alive[MAXM] = {};\n\n        // expand closure MST edges\n        for (int i = 1; i < t; i++) {\n            int s = terminals[parent[i]];\n            int cur = terminals[i];\n            while (cur != s) {\n                int eid = prevEdge[s][cur];\n                if (eid < 0) return INF;\n                marked[eid] = 1;\n                cur = prevNode[s][cur];\n            }\n        }\n\n        DSU dsu(N);\n        ll cost = 0;\n        for (int eid : edgeOrder) {\n            if (!marked[eid]) continue;\n            auto &e = edges[eid];\n            if (dsu.merge(e.u, e.v)) {\n                alive[eid] = 1;\n                cost += e.w;\n            }\n        }\n\n        // prune non-terminal leaves\n        int deg[MAXN] = {};\n        bool isTerm[MAXN] = {};\n        for (int i = 0; i < t; i++) isTerm[terminals[i]] = true;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) {\n            if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        if (outB) {\n            outB->assign(M, 0);\n            for (int eid = 0; eid < M; eid++) if (alive[eid]) (*outB)[eid] = 1;\n        }\n\n        return cost;\n    }\n\n    ll steinerRootUnion(const vector<int> &terminals, vector<char> &outB) {\n        outB.assign(M, 0);\n        for (int t : terminals) {\n            if (t == 0) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevEdge[0][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[0][cur];\n            }\n        }\n        return pruneAlive(outB, terminals);\n    }\n\n    ll steinerSPH(const vector<int> &terminals, int startTerm, vector<char> &outB) {\n        outB.assign(M, 0);\n        if ((int)terminals.size() <= 1) return 0;\n\n        vector<char> inTree(N, 0), isTerm(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n        if (!isTerm[startTerm]) startTerm = 0;\n        inTree[startTerm] = 1;\n\n        while (true) {\n            ll bestD = INF;\n            int bestSrc = -1, bestTerm = -1;\n\n            for (int t : terminals) {\n                if (inTree[t]) continue;\n                for (int v = 0; v < N; v++) {\n                    if (!inTree[v]) continue;\n                    ll d = spDist[v][t];\n                    if (d < bestD) {\n                        bestD = d;\n                        bestSrc = v;\n                        bestTerm = t;\n                    }\n                }\n            }\n\n            if (bestTerm == -1) break;\n\n            int cur = bestTerm;\n            inTree[cur] = 1;\n            while (cur != bestSrc) {\n                int eid = prevEdge[bestSrc][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[bestSrc][cur];\n                inTree[cur] = 1;\n            }\n        }\n\n        return pruneAlive(outB, terminals);\n    }\n\n    ll steinerBestFinal(const int terminals[], int t, vector<char> &outB) {\n        outB.assign(M, 0);\n        if (t <= 1) return 0;\n\n        vector<char> bestB;\n        ll best = steinerKMB(terminals, t, &bestB);\n\n        vector<int> tv(terminals, terminals + t);\n\n        vector<char> b2;\n        ll c2 = steinerRootUnion(tv, b2);\n        if (c2 < best) {\n            best = c2;\n            bestB = b2;\n        }\n\n        int far = -1, near = -1;\n        ll farD = -1, nearD = INF;\n        for (int v : tv) {\n            ll d = spDist[0][v];\n            if (d > farD) farD = d, far = v;\n            if (v != 0 && d < nearD) nearD = d, near = v;\n        }\n\n        vector<int> starts;\n        starts.push_back(0);\n        if (far != -1) starts.push_back(far);\n        if (near != -1) starts.push_back(near);\n        if (t > 1) {\n            for (int r = 0; r < 2; r++) {\n                starts.push_back(terminals[1 + (rng() % (t - 1))]);\n            }\n        }\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int s : starts) {\n            vector<char> bs;\n            ll cs = steinerSPH(tv, s, bs);\n            if (cs < best) {\n                best = cs;\n                bestB = bs;\n            }\n        }\n\n        outB = move(bestB);\n        return best;\n    }\n\n    ll evaluateFast(const vector<char> &active) {\n        Key key = makeKey(active);\n        auto it = cacheFast.find(key);\n        if (it != cacheFast.end()) return it->second;\n\n        if (cacheFast.size() > 120000) cacheFast.clear();\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) {\n            cacheFast.emplace(key, INF);\n            return INF;\n        }\n\n        ll power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge = steinerKMB(terminals, t, nullptr);\n        ll ret = (edge >= INF / 2 ? INF : power + edge);\n        cacheFast.emplace(key, ret);\n        return ret;\n    }\n\n    ll evaluateExactKMB(const vector<char> &active) {\n        Key key = makeKey(active);\n        auto it = cacheExact.find(key);\n        if (it != cacheExact.end()) return it->second;\n\n        if (cacheExact.size() > 80000) cacheExact.clear();\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) {\n            cacheExact.emplace(key, INF);\n            return INF;\n        }\n\n        shrinkPArray(P, true);\n\n        ll power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge = steinerKMB(terminals, t, nullptr);\n        ll ret = (edge >= INF / 2 ? INF : power + edge);\n        cacheExact.emplace(key, ret);\n        return ret;\n    }\n\n    double initScore(int dist, int st, double lambda) const {\n        return 1.0 * dist * dist + lambda * (double)spDist[0][st];\n    }\n\n    vector<char> makeInitAssign(double lambda) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n\n        for (int k = 0; k < K; k++) {\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    vector<char> makeInitRepair(double lambda, const vector<int> &order) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            int k = order[idx];\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                if (active[pr.second]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    void repairActive(vector<char> &active, double lambda) {\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (auto &pr : cand[k]) {\n                if (active[pr.second]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto &pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n    }\n\n    bool initCoverCnt(const vector<char> &active, vector<int> &cnt) {\n        cnt.assign(K, 0);\n        for (int i = 0; i < N; i++) {\n            if (!active[i]) continue;\n            for (int k : coverResidents[i]) cnt[k]++;\n        }\n        for (int k = 0; k < K; k++) if (cnt[k] == 0) return false;\n        return true;\n    }\n\n    bool canOffCoverage(int st, const vector<int> &cnt) const {\n        for (int k : coverResidents[st]) if (cnt[k] == 1) return false;\n        return true;\n    }\n\n    bool canSwapCoverage(int offSt, int onSt, const vector<int> &cnt) const {\n        for (int k : coverResidents[offSt]) {\n            if (cnt[k] == 1 && distSR[onSt][k] > RAD) return false;\n        }\n        return true;\n    }\n\n    void applyOnCoverage(int st, vector<char> &active, vector<int> &cnt) {\n        if (active[st]) return;\n        active[st] = 1;\n        for (int k : coverResidents[st]) cnt[k]++;\n    }\n\n    void applyOffCoverage(int st, vector<char> &active, vector<int> &cnt) {\n        if (!active[st]) return;\n        active[st] = 0;\n        for (int k : coverResidents[st]) cnt[k]--;\n    }\n\n    pair<vector<char>, ll> hillClimb1(vector<char> active, int maxIter, double endTime) {\n        ll cur = evaluateFast(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateFast(active);\n        }\n\n        for (int it = 0; it < maxIter && elapsed() < endTime; it++) {\n            ll best = cur;\n            int bestFlip = -1;\n\n            vector<int> ord;\n            ord.reserve(N - 1);\n            for (int i = 1; i < N; i++) ord.push_back(i);\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int i : ord) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n\n            if (bestFlip == -1) break;\n            active[bestFlip] ^= 1;\n            cur = best;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> localSearchWithSwap(vector<char> active, double endTime) {\n        ll cur = evaluateFast(active);\n        if (cur >= INF / 2) {\n            repairActive(active, 0.05);\n            cur = evaluateFast(active);\n        }\n\n        while (elapsed() < endTime) {\n            bool improved = false;\n\n            // 1-flip steepest\n            ll best = cur;\n            int bestFlip = -1;\n\n            vector<int> ord;\n            ord.reserve(N - 1);\n            for (int i = 1; i < N; i++) ord.push_back(i);\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int i : ord) {\n                if (elapsed() >= endTime) break;\n                active[i] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n                if (c < best) {\n                    best = c;\n                    bestFlip = i;\n                }\n            }\n\n            if (bestFlip != -1) {\n                active[bestFlip] ^= 1;\n                cur = best;\n                improved = true;\n                continue;\n            }\n\n            // swap\n            vector<int> on, off;\n            for (int i = 1; i < N; i++) {\n                if (active[i]) on.push_back(i);\n                else off.push_back(i);\n            }\n            if (on.empty() || off.empty()) break;\n\n            ll bestSwap = cur;\n            int bi = -1, bj = -1;\n            long long pairs = 1LL * on.size() * off.size();\n\n            if (pairs <= 2800) {\n                for (int i : on) {\n                    if (elapsed() >= endTime) break;\n                    for (int j : off) {\n                        if (elapsed() >= endTime) break;\n                        active[i] ^= 1;\n                        active[j] ^= 1;\n                        ll c = evaluateFast(active);\n                        active[i] ^= 1;\n                        active[j] ^= 1;\n                        if (c < bestSwap) {\n                            bestSwap = c;\n                            bi = i; bj = j;\n                        }\n                    }\n                }\n            } else {\n                int trials = 2800;\n                for (int tr = 0; tr < trials && elapsed() < endTime; tr++) {\n                    int i = on[rng() % on.size()];\n                    int j = off[rng() % off.size()];\n                    active[i] ^= 1;\n                    active[j] ^= 1;\n                    ll c = evaluateFast(active);\n                    active[i] ^= 1;\n                    active[j] ^= 1;\n                    if (c < bestSwap) {\n                        bestSwap = c;\n                        bi = i; bj = j;\n                    }\n                }\n            }\n\n            if (bi != -1) {\n                active[bi] ^= 1;\n                active[bj] ^= 1;\n                cur = bestSwap;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> exactRefineState(vector<char> active, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) {\n            repairActive(active, 0.05);\n            initCoverCnt(active, cnt);\n        }\n\n        ll cur = evaluateExactKMB(active);\n        if (cur >= INF / 2) return {active, cur};\n\n        int rounds = 0;\n        while (elapsed() < endTime && rounds < 8) {\n            rounds++;\n            bool improved = false;\n\n            // remove first-improvement\n            vector<int> onList;\n            for (int i = 1; i < N; i++) if (active[i]) onList.push_back(i);\n            shuffle(onList.begin(), onList.end(), rng);\n\n            for (int i : onList) {\n                if (elapsed() >= endTime) break;\n                if (!canOffCoverage(i, cnt)) continue;\n\n                active[i] = 0;\n                ll c = evaluateExactKMB(active);\n                active[i] = 1;\n\n                if (c < cur) {\n                    applyOffCoverage(i, active, cnt);\n                    cur = c;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) continue;\n\n            // sampled swap\n            vector<int> offList;\n            for (int i = 1; i < N; i++) if (!active[i]) offList.push_back(i);\n\n            if (!onList.empty() && !offList.empty()) {\n                int trials = min<ll>(70, 1LL * onList.size() * offList.size());\n                for (int tr = 0; tr < trials && elapsed() < endTime; tr++) {\n                    int i = onList[rng() % onList.size()];\n                    int j = offList[rng() % offList.size()];\n                    if (!canSwapCoverage(i, j, cnt)) continue;\n\n                    active[i] = 0;\n                    active[j] = 1;\n                    ll c = evaluateExactKMB(active);\n                    active[i] = 1;\n                    active[j] = 0;\n\n                    if (c < cur) {\n                        applyOffCoverage(i, active, cnt);\n                        applyOnCoverage(j, active, cnt);\n                        cur = c;\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n            if (improved) continue;\n\n            // sampled add\n            offList.clear();\n            for (int i = 1; i < N; i++) if (!active[i]) offList.push_back(i);\n            shuffle(offList.begin(), offList.end(), rng);\n            int addTrials = min<int>(16, offList.size());\n\n            for (int idx = 0; idx < addTrials && elapsed() < endTime; idx++) {\n                int j = offList[idx];\n                active[j] = 1;\n                ll c = evaluateExactKMB(active);\n                active[j] = 0;\n\n                if (c < cur) {\n                    applyOnCoverage(j, active, cnt);\n                    cur = c;\n                    improved = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    Solution buildSolution(const vector<char> &active, bool fullShrink, bool strongEdge) {\n        Solution sol;\n        sol.P.assign(N, 0);\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) return sol;\n\n        shrinkPArray(P, fullShrink);\n\n        ll power = 0;\n        int terminals[MAXN];\n        int t = 0;\n        terminals[t++] = 0;\n\n        for (int i = 0; i < N; i++) {\n            sol.P[i] = P[i];\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edgeCost;\n        if (strongEdge) edgeCost = steinerBestFinal(terminals, t, sol.B);\n        else edgeCost = steinerKMB(terminals, t, &sol.B);\n\n        if (edgeCost >= INF / 2) return sol;\n\n        sol.feasible = true;\n        sol.cost = power + edgeCost;\n        return sol;\n    }\n\n    void solve() {\n        readInput();\n        startTime = chrono::steady_clock::now();\n\n        precomputeDistances();\n        precomputeShortestPaths();\n\n        cacheFast.reserve(1 << 15);\n        cacheExact.reserve(1 << 14);\n        cacheFast.max_load_factor(0.7f);\n        cacheExact.max_load_factor(0.7f);\n\n        vector<char> allOn(N, 1);\n        allOn[0] = 1;\n\n        ll bestFastCost = evaluateFast(allOn);\n        vector<char> bestFastState = allOn;\n\n        vector<pair<ll, vector<char>>> pool;\n        pushPool(pool, allOn, bestFastCost, 14);\n\n        // time budgets\n        const double T_INIT  = 0.45;\n        const double T_SWAP  = 1.00;\n        const double T_KICK  = 1.55;\n        const double T_EXACT = 1.87;\n\n        // init states\n        vector<int> ord(K), ordRev, ordRnd1, ordRnd2;\n        iota(ord.begin(), ord.end(), 0);\n        ordRev = ord;\n        reverse(ordRev.begin(), ordRev.end());\n        ordRnd1 = ord; shuffle(ordRnd1.begin(), ordRnd1.end(), rng);\n        ordRnd2 = ord; shuffle(ordRnd2.begin(), ordRnd2.end(), rng);\n\n        vector<vector<char>> inits;\n        addUniqueState(inits, allOn);\n\n        for (double lam : {0.00, 0.02, 0.05, 0.10, 0.20}) {\n            addUniqueState(inits, makeInitAssign(lam));\n        }\n        for (double lam : {0.00, 0.04, 0.10, 0.20}) {\n            addUniqueState(inits, makeInitRepair(lam, ord));\n            addUniqueState(inits, makeInitRepair(lam, ordRev));\n        }\n        addUniqueState(inits, makeInitRepair(0.08, ordRnd1));\n        addUniqueState(inits, makeInitRepair(0.12, ordRnd2));\n\n        for (auto st : inits) {\n            if (elapsed() >= T_INIT) break;\n            repairActive(st, 0.05);\n            auto res = hillClimb1(st, 12, T_INIT);\n            if (res.second < bestFastCost) {\n                bestFastCost = res.second;\n                bestFastState = res.first;\n            }\n            pushPool(pool, res.first, res.second, 14);\n        }\n\n        // intensify top states\n        if (elapsed() < T_SWAP) {\n            int use = min<int>(2, pool.size());\n            for (int i = 0; i < use && elapsed() < T_SWAP; i++) {\n                double lim = min(T_SWAP, elapsed() + (i == 0 ? 0.13 : 0.10));\n                auto res = localSearchWithSwap(pool[i].second, lim);\n                if (res.second < bestFastCost) {\n                    bestFastCost = res.second;\n                    bestFastState = res.first;\n                }\n                pushPool(pool, res.first, res.second, 14);\n            }\n        }\n\n        // random kick + short climb\n        while (elapsed() < T_KICK) {\n            vector<char> trial;\n\n            if (!pool.empty() && (rng() % 100) < 80) {\n                int lim = min<int>(5, pool.size());\n                trial = pool[rng() % lim].second;\n            } else {\n                trial = bestFastState;\n            }\n\n            int flips = 2 + (rng() % 4); // 2..5\n            for (int t = 0; t < flips; t++) {\n                int idx = 1 + (rng() % (N - 1));\n                trial[idx] ^= 1;\n            }\n            repairActive(trial, 0.08);\n\n            auto res = hillClimb1(trial, 8, T_KICK);\n\n            if (elapsed() < T_KICK && (rng() % 100) < 30) {\n                double lim = min(T_KICK, elapsed() + 0.03);\n                auto sw = localSearchWithSwap(res.first, lim);\n                if (sw.second < res.second) res = sw;\n            }\n\n            if (res.second < bestFastCost) {\n                bestFastCost = res.second;\n                bestFastState = res.first;\n            }\n            pushPool(pool, res.first, res.second, 14);\n        }\n\n        // exact candidate set\n        vector<vector<char>> exactCand;\n        addUniqueState(exactCand, bestFastState);\n        addUniqueState(exactCand, allOn);\n        for (int i = 0; i < (int)pool.size() && i < 10; i++) {\n            addUniqueState(exactCand, pool[i].second);\n        }\n\n        vector<pair<ll, vector<char>>> exactPool;\n        for (auto st : exactCand) {\n            if (elapsed() > T_EXACT - 0.12) break;\n            repairActive(st, 0.05);\n            ll c = evaluateExactKMB(st);\n            pushPool(exactPool, st, c, 12);\n        }\n        if (exactPool.empty()) {\n            ll c = evaluateExactKMB(allOn);\n            pushPool(exactPool, allOn, c, 12);\n        }\n\n        sort(exactPool.begin(), exactPool.end(),\n             [](auto &L, auto &R) { return L.first < R.first; });\n\n        // exact polishing\n        vector<vector<char>> polished;\n        int polishCnt = min<int>(4, exactPool.size());\n        for (int i = 0; i < polishCnt && elapsed() < T_EXACT; i++) {\n            double slice = (i == 0 ? 0.12 : 0.08);\n            auto res = exactRefineState(exactPool[i].second, min(T_EXACT, elapsed() + slice));\n            ll c = evaluateExactKMB(res.first);\n            pushPool(exactPool, res.first, c, 12);\n            polished.push_back(res.first);\n        }\n\n        sort(exactPool.begin(), exactPool.end(),\n             [](auto &L, auto &R) { return L.first < R.first; });\n\n        vector<char> bestExactState = exactPool[0].second;\n\n        // final assembly\n        vector<vector<char>> finals;\n        addUniqueState(finals, bestExactState);\n        addUniqueState(finals, bestFastState);\n        addUniqueState(finals, allOn);\n        for (auto &st : polished) addUniqueState(finals, st);\n        for (int i = 0; i < (int)exactPool.size() && i < 8; i++) addUniqueState(finals, exactPool[i].second);\n        for (int i = 0; i < (int)pool.size() && i < 5; i++) addUniqueState(finals, pool[i].second);\n\n        Solution bestSol;\n        for (auto st : finals) {\n            if (elapsed() > 1.985) break;\n            repairActive(st, 0.05);\n            auto sol = buildSolution(st, true, true);\n            if (sol.feasible && (!bestSol.feasible || sol.cost < bestSol.cost)) {\n                bestSol = move(sol);\n            }\n        }\n\n        if (!bestSol.feasible) {\n            auto sol = buildSolution(allOn, true, true);\n            if (sol.feasible) bestSol = move(sol);\n        }\n        if (!bestSol.feasible) {\n            auto sol = buildSolution(allOn, true, false);\n            if (sol.feasible) bestSol = move(sol);\n        }\n        if (!bestSol.feasible) {\n            bestSol.feasible = true;\n            bestSol.P.assign(N, 0);\n            bestSol.B.assign(M, 0);\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << bestSol.P[i];\n        }\n        cout << '\\n';\n\n        for (int j = 0; j < M; j++) {\n            if (j) cout << ' ';\n            cout << int(bestSol.B[j]);\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}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TOT = N * (N + 1) / 2; // 465\nstatic constexpr int MAXV = TOT - 1;\n\nusing Board = array<array<int, N>, N>;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nstruct Policy {\n    bool mirror = false;\n    array<uint8_t, 3> pm{};      // path mode for zones: top/mid/bottom\n    array<uint8_t, N> row_mode{}; // per-row order mode\n};\n\nstruct EvalRes {\n    int K = (int)1e9;\n    int E = (int)1e9;\n    vector<Move> ops;\n};\n\nstruct Cand {\n    Policy p;\n    int K = (int)1e9;\n    uint64_t key = 0;\n};\n\nstatic int POS_ID[N][N];\nstatic uint64_t ZOB[TOT][TOT];\n\nstatic uint64_t splitmix64(uint64_t& x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstatic void init_tables() {\n    for (int x = 0; x < N; ++x) for (int y = 0; y < N; ++y) POS_ID[x][y] = -1;\n    int id = 0;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) POS_ID[x][y] = id++;\n    }\n\n    uint64_t seed = 0x1234567890abcdefULL;\n    for (int p = 0; p < TOT; ++p) {\n        for (int v = 0; v < TOT; ++v) {\n            ZOB[p][v] = splitmix64(seed);\n        }\n    }\n}\n\nstatic inline bool same_unordered(const Move& a, const Move& b) {\n    return (a.x1 == b.x1 && a.y1 == b.y1 && a.x2 == b.x2 && a.y2 == b.y2) ||\n           (a.x1 == b.x2 && a.y1 == b.y2 && a.x2 == b.x1 && a.y2 == b.y1);\n}\n\nstatic vector<Move> compress_ops(const vector<Move>& ops) {\n    vector<Move> st;\n    st.reserve(ops.size());\n    for (const auto& mv : ops) {\n        if (!st.empty() && same_unordered(st.back(), mv)) st.pop_back();\n        else st.push_back(mv);\n    }\n    return st;\n}\n\nstatic inline int calcE(const Board& b) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int p = b[x][y];\n            if (p > b[x + 1][y]) ++E;\n            if (p > b[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nstatic int calcE_after_ops(const Board& init, const vector<Move>& ops) {\n    Board b = init;\n    for (const auto& m : ops) {\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b);\n}\n\nstatic Board mirror_board(const Board& init) {\n    Board b{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            b[x][y] = init[x][x - y];\n        }\n    }\n    return b;\n}\n\nstatic void unmirror_ops(vector<Move>& ops) {\n    for (auto& m : ops) {\n        m.y1 = m.x1 - m.y1;\n        m.y2 = m.x2 - m.y2;\n    }\n}\n\nstatic inline int parent_threshold(const Board& b, int x, int y) {\n    if (x == 0) return -1;\n    int t = -1;\n    if (y > 0) t = max(t, b[x - 1][y - 1]);\n    if (y < x) t = max(t, b[x - 1][y]);\n    return t;\n}\n\nstatic inline void find_min_cone(const Board& b, int x, int y, int& sx, int& sy, int& val) {\n    val = INT_MAX;\n    sx = x; sy = y;\n    for (int r = x; r < N; ++r) {\n        int cmax = y + (r - x);\n        for (int c = y; c <= cmax; ++c) {\n            int v = b[r][c];\n            if (v < val) {\n                val = v;\n                sx = r;\n                sy = c;\n            }\n        }\n    }\n}\n\n// row_mode:\n// 0 asc\n// 1 desc\n// 2 edges-in\n// 3 center-out\n// 4 min source depth (static)\n// 5 max source depth (static)\n// 6 min source value (static)\n// 7 parent-threshold asc\n// 8 parent-threshold desc\nstatic vector<int> build_order(const Board& b, int x, int mode) {\n    vector<int> ord;\n    ord.reserve(x + 1);\n\n    if (mode == 0) {\n        for (int y = 0; y <= x; ++y) ord.push_back(y);\n        return ord;\n    }\n    if (mode == 1) {\n        for (int y = x; y >= 0; --y) ord.push_back(y);\n        return ord;\n    }\n    if (mode == 2) {\n        int l = 0, r = x;\n        while (l <= r) {\n            ord.push_back(l++);\n            if (l <= r) ord.push_back(r--);\n        }\n        return ord;\n    }\n    if (mode == 3) {\n        int mid = x / 2;\n        ord.push_back(mid);\n        for (int d = 1; (int)ord.size() < x + 1; ++d) {\n            int L = mid - d;\n            int R = mid + d;\n            if (L >= 0) ord.push_back(L);\n            if ((int)ord.size() >= x + 1) break;\n            if (R <= x) ord.push_back(R);\n        }\n        return ord;\n    }\n\n    vector<tuple<int,int,int>> key; // k1,k2,y\n    key.reserve(x + 1);\n\n    if (mode == 4 || mode == 5 || mode == 6) {\n        for (int y = 0; y <= x; ++y) {\n            int sx, sy, val;\n            find_min_cone(b, x, y, sx, sy, val);\n            int dep = sx - x;\n            if (mode == 4) key.emplace_back(dep, val, y);\n            else if (mode == 5) key.emplace_back(-dep, val, y);\n            else key.emplace_back(val, dep, y);\n        }\n    } else if (mode == 7 || mode == 8) {\n        for (int y = 0; y <= x; ++y) {\n            int t = parent_threshold(b, x, y);\n            if (mode == 7) key.emplace_back(t, y, y);\n            else key.emplace_back(-t, y, y);\n        }\n    } else {\n        for (int y = 0; y <= x; ++y) ord.push_back(y);\n        return ord;\n    }\n\n    sort(key.begin(), key.end(), [](const auto& a, const auto& b) {\n        if (get<0>(a) != get<0>(b)) return get<0>(a) < get<0>(b);\n        if (get<1>(a) != get<1>(b)) return get<1>(a) < get<1>(b);\n        return get<2>(a) < get<2>(b);\n    });\n    for (auto& t : key) ord.push_back(get<2>(t));\n    return ord;\n}\n\nstatic inline void push_move(Board& b, vector<Move>& st, int x1, int y1, int x2, int y2) {\n    swap(b[x1][y1], b[x2][y2]);\n    Move mv{x1, y1, x2, y2};\n    if (!st.empty() && same_unordered(st.back(), mv)) st.pop_back();\n    else st.push_back(mv);\n}\n\n// path_mode:\n// 2 greedy: if both possible choose larger parent to push down\n// 4/5/6: DP path with different penalties\nstatic int move_greedy(Board& b, vector<Move>& st, int sx, int sy, int tx, int ty, int mode) {\n    int cx = sx, cy = sy;\n    int steps = 0;\n    while (cx > tx) {\n        int rem = cx - tx;\n        int delta = cy - ty;\n\n        bool canL = (delta > 0);     // (cx-1, cy-1)\n        bool canR = (delta < rem);   // (cx-1, cy)\n\n        bool goL;\n        if (canL && !canR) goL = true;\n        else if (!canL && canR) goL = false;\n        else {\n            int lv = b[cx - 1][cy - 1];\n            int rv = b[cx - 1][cy];\n            if (mode == 0) goL = true;\n            else if (mode == 1) goL = false;\n            else if (mode == 3) goL = (lv <= rv);\n            else goL = (lv >= rv); // mode 2 (default)\n        }\n\n        int nx = cx - 1;\n        int ny = goL ? (cy - 1) : cy;\n        push_move(b, st, cx, cy, nx, ny);\n        cx = nx; cy = ny;\n        ++steps;\n    }\n    return steps;\n}\n\nstatic inline int dp_penalty(const Board& b, int r, int c, int mode) {\n    int v = b[r][c];\n    int small = MAXV - v; // smaller value => bigger penalty to push down\n\n    if (mode == 4) return small;\n    if (mode == 5) return small * (N - r);\n\n    // mode == 6\n    int need_above = r * (r + 1) / 2;\n    int late = max(0, need_above - v);\n    return small + late * 8 + (N - r) * 2;\n}\n\nstatic int move_dp(Board& b, vector<Move>& st, int sx, int sy, int tx, int ty, int mode) {\n    static int dist[N][N];\n    static int pred[N][N];\n    constexpr int INF = 1e9;\n\n    for (int r = tx; r <= sx; ++r) {\n        int cmin = ty;\n        int cmax = ty + (r - tx);\n        for (int c = cmin; c <= cmax; ++c) {\n            dist[r][c] = INF;\n            pred[r][c] = -1;\n        }\n    }\n    dist[tx][ty] = 0;\n\n    for (int r = tx + 1; r <= sx; ++r) {\n        int cmin = ty;\n        int cmax = ty + (r - tx);\n        for (int c = cmin; c <= cmax; ++c) {\n            int best = INF, bp = -1, bpv = -1;\n\n            if (c <= ty + (r - 1 - tx) && dist[r - 1][c] < INF) {\n                int cand = dist[r - 1][c] + dp_penalty(b, r - 1, c, mode);\n                int pv = b[r - 1][c];\n                if (cand < best || (cand == best && pv > bpv)) {\n                    best = cand; bp = c; bpv = pv;\n                }\n            }\n            if (c - 1 >= ty && dist[r - 1][c - 1] < INF) {\n                int cand = dist[r - 1][c - 1] + dp_penalty(b, r - 1, c - 1, mode);\n                int pv = b[r - 1][c - 1];\n                if (cand < best || (cand == best && pv > bpv)) {\n                    best = cand; bp = c - 1; bpv = pv;\n                }\n            }\n\n            dist[r][c] = best;\n            pred[r][c] = bp;\n        }\n    }\n\n    int cx = sx, cy = sy;\n    int steps = 0;\n    while (cx > tx) {\n        int pcy = pred[cx][cy];\n        if (pcy < 0) pcy = (cy > ty ? cy - 1 : cy); // safety fallback\n        push_move(b, st, cx, cy, cx - 1, pcy);\n        cy = pcy;\n        --cx;\n        ++steps;\n    }\n    return steps;\n}\n\nstatic inline int path_mode_for_row(const Policy& p, int x) {\n    if (x < 8) return p.pm[0];\n    if (x < 20) return p.pm[1];\n    return p.pm[2];\n}\n\nstatic EvalRes run_policy(const Board& init, const Policy& pol, bool output_ops) {\n    Board b = pol.mirror ? mirror_board(init) : init;\n    vector<Move> st;\n    st.reserve(7000);\n\n    for (int x = 0; x < N; ++x) {\n        int mode = (int)pol.row_mode[x];\n        vector<int> ord = build_order(b, x, mode);\n        int pm = path_mode_for_row(pol, x);\n\n        for (int y : ord) {\n            int sx, sy, val;\n            find_min_cone(b, x, y, sx, sy, val);\n\n            if (pm >= 4) move_dp(b, st, sx, sy, x, y, pm);\n            else move_greedy(b, st, sx, sy, x, y, pm);\n        }\n    }\n\n    EvalRes r;\n    r.K = (int)st.size();\n    r.E = calcE(b);\n    if (output_ops) {\n        if (pol.mirror) unmirror_ops(st);\n        r.ops = std::move(st);\n    }\n    return r;\n}\n\nstatic uint64_t hash_policy(const Policy& p) {\n    uint64_t h = 0xcbf29ce484222325ULL;\n    auto mix = [&](uint64_t x) {\n        h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    };\n    mix((uint64_t)p.mirror);\n    mix(p.pm[0]); mix(p.pm[1]); mix(p.pm[2]);\n    for (int x = 0; x < N; ++x) mix(p.row_mode[x]);\n    return h;\n}\n\nstatic void add_pool(vector<Cand>& pool, const Cand& c, int pool_max) {\n    for (auto& e : pool) {\n        if (e.key == c.key) {\n            if (c.K < e.K) e = c;\n            return;\n        }\n    }\n\n    if ((int)pool.size() < pool_max) {\n        pool.push_back(c);\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < (int)pool.size(); ++i) {\n        if (pool[i].K > pool[worst].K) worst = i;\n    }\n    if (c.K < pool[worst].K) pool[worst] = c;\n}\n\nstatic bool check_skip1(const Board& init, const vector<Move>& ops, int s1) {\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == s1) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b) == 0;\n}\n\nstatic bool check_skip2(const Board& init, const vector<Move>& ops, int s1, int s2) {\n    if (s1 > s2) swap(s1, s2);\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == s1 || i == s2) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b) == 0;\n}\n\ntemplate<class Elapsed>\nstatic void remove_state_loops(const Board& init, vector<Move>& ops, Elapsed elapsed, double limit_sec) {\n    if ((int)ops.size() < 4) return;\n\n    for (int iter = 0; iter < 4; ++iter) {\n        if (elapsed() > limit_sec) return;\n\n        array<int, TOT> arr{};\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                arr[POS_ID[x][y]] = init[x][y];\n            }\n        }\n\n        uint64_t h = 0;\n        for (int p = 0; p < TOT; ++p) h ^= ZOB[p][arr[p]];\n\n        unordered_map<uint64_t, int> first;\n        first.reserve(ops.size() * 2 + 16);\n        first[h] = 0;\n\n        bool changed = false;\n        for (int i = 0; i < (int)ops.size(); ++i) {\n            if (elapsed() > limit_sec) return;\n\n            const auto& m = ops[i];\n            int p1 = POS_ID[m.x1][m.y1];\n            int p2 = POS_ID[m.x2][m.y2];\n            int v1 = arr[p1], v2 = arr[p2];\n\n            h ^= ZOB[p1][v1] ^ ZOB[p1][v2] ^ ZOB[p2][v1] ^ ZOB[p2][v2];\n            swap(arr[p1], arr[p2]);\n\n            auto it = first.find(h);\n            if (it != first.end()) {\n                int j = it->second; // same state after j ops and after i+1 ops\n                if (i + 1 > j) {\n                    ops.erase(ops.begin() + j, ops.begin() + i + 1);\n                    changed = true;\n                }\n                break;\n            } else {\n                first.emplace(h, i + 1);\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\ntemplate<class Elapsed>\nstatic void prune_ops(const Board& init, vector<Move>& ops, Elapsed elapsed, double limit_sec, mt19937& rng) {\n    if (ops.empty()) return;\n\n    ops = compress_ops(ops);\n    remove_state_loops(init, ops, elapsed, limit_sec);\n\n    // single deletion (forward)\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (elapsed() > limit_sec) return;\n        if (check_skip1(init, ops, i)) {\n            ops.erase(ops.begin() + i);\n            --i;\n        }\n    }\n\n    // adjacent pair deletion\n    for (int i = 0; i + 1 < (int)ops.size(); ++i) {\n        if (elapsed() > limit_sec) return;\n        if (check_skip2(init, ops, i, i + 1)) {\n            ops.erase(ops.begin() + i, ops.begin() + i + 2);\n            i = max(-1, i - 2);\n        }\n    }\n\n    // random pair deletion\n    for (int t = 0; t < 220; ++t) {\n        if (elapsed() > limit_sec) return;\n        int n = (int)ops.size();\n        if (n < 2) break;\n        int i = (int)(rng() % n);\n        int j = (int)(rng() % n);\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n\n        if (check_skip2(init, ops, i, j)) {\n            ops.erase(ops.begin() + j);\n            ops.erase(ops.begin() + i);\n        }\n    }\n\n    // single deletion (backward)\n    for (int i = (int)ops.size() - 1; i >= 0; --i) {\n        if (elapsed() > limit_sec) return;\n        if (check_skip1(init, ops, i)) {\n            ops.erase(ops.begin() + i);\n        }\n    }\n\n    ops = compress_ops(ops);\n    remove_state_loops(init, ops, elapsed, limit_sec);\n}\n\nstatic Policy make_safe_policy(bool mir) {\n    Policy p;\n    p.mirror = mir;\n    p.pm = {2, 2, 2};\n    p.row_mode.fill(0);\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_tables();\n\n    Board init{};\n    uint64_t seed = 1469598103934665603ULL;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n            seed ^= (uint64_t)(init[x][y] + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32) ^ 0x9e3779b9u));\n\n    using Clock = chrono::steady_clock;\n    const auto start = Clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(Clock::now() - start).count();\n    };\n\n    constexpr double SEARCH_T = 1.48;\n    constexpr double FINAL_T  = 1.90;\n\n    const int POOL_MAX = 14;\n    vector<Cand> pool;\n    pool.reserve(POOL_MAX + 4);\n\n    unordered_map<uint64_t, int> cache; // key -> K (E==0), -1 (E>0)\n    cache.reserve(1 << 14);\n\n    auto sort_pool = [&]() {\n        sort(pool.begin(), pool.end(), [](const Cand& a, const Cand& b) {\n            return a.K < b.K;\n        });\n    };\n\n    auto eval_policy = [&](const Policy& p, int& outK) -> bool {\n        uint64_t key = hash_policy(p);\n        auto it = cache.find(key);\n        if (it != cache.end()) {\n            if (it->second < 0) return false;\n            outK = it->second;\n            add_pool(pool, Cand{p, outK, key}, POOL_MAX);\n            return true;\n        }\n\n        EvalRes r = run_policy(init, p, false);\n        if (r.E == 0) {\n            outK = r.K;\n            cache.emplace(key, outK);\n            add_pool(pool, Cand{p, outK, key}, POOL_MAX);\n            return true;\n        } else {\n            cache.emplace(key, -1);\n            return false;\n        }\n    };\n\n    // Safe baselines\n    {\n        int k;\n        eval_policy(make_safe_policy(false), k);\n        eval_policy(make_safe_policy(true), k);\n    }\n\n    vector<int> row_modes = {0,1,2,3,4,5,6,7,8};\n    vector<int> path_modes = {2,4,5,6};\n\n    // Seed row patterns\n    vector<array<uint8_t, N>> patterns;\n    {\n        array<uint8_t, N> a{};\n\n        auto push_all = [&](int m) {\n            a.fill((uint8_t)m);\n            patterns.push_back(a);\n        };\n        push_all(0);\n        push_all(2);\n        push_all(3);\n        push_all(4);\n        push_all(6);\n        push_all(7);\n\n        for (int x = 0; x < N; ++x) {\n            if (x < 8) a[x] = 0;\n            else if (x < 18) a[x] = 2;\n            else a[x] = 4;\n        }\n        patterns.push_back(a);\n\n        for (int x = 0; x < N; ++x) {\n            if (x < 8) a[x] = 3;\n            else if (x < 18) a[x] = 2;\n            else a[x] = 0;\n        }\n        patterns.push_back(a);\n\n        for (int x = 0; x < N; ++x) a[x] = (x & 1) ? 2 : 3;\n        patterns.push_back(a);\n\n        for (int x = 0; x < N; ++x) {\n            if (x < 10) a[x] = 7;\n            else if (x < 20) a[x] = 2;\n            else a[x] = 5;\n        }\n        patterns.push_back(a);\n\n        for (int x = 0; x < N; ++x) {\n            if (x < 10) a[x] = 0;\n            else if (x < 20) a[x] = 6;\n            else a[x] = 5;\n        }\n        patterns.push_back(a);\n    }\n\n    vector<array<uint8_t, 3>> path_profiles = {\n        array<uint8_t,3>{2,2,2},\n        array<uint8_t,3>{4,4,4},\n        array<uint8_t,3>{5,5,5},\n        array<uint8_t,3>{6,6,6},\n        array<uint8_t,3>{4,2,2},\n        array<uint8_t,3>{5,4,2},\n        array<uint8_t,3>{6,4,2},\n        array<uint8_t,3>{2,4,6},\n        array<uint8_t,3>{2,5,4},\n        array<uint8_t,3>{4,6,2}\n    };\n\n    // Deterministic seeds\n    bool stop = false;\n    for (int mir = 0; mir < 2 && !stop; ++mir) {\n        for (auto& pp : path_profiles) {\n            for (auto& rm : patterns) {\n                if (elapsed() > SEARCH_T) { stop = true; break; }\n                Policy p;\n                p.mirror = (bool)mir;\n                p.pm = pp;\n                p.row_mode = rm;\n                int k;\n                eval_policy(p, k);\n            }\n            if (stop) break;\n        }\n    }\n\n    if (pool.empty()) {\n        int k;\n        eval_policy(make_safe_policy(false), k);\n    }\n\n    sort_pool();\n\n    // Coordinate descent on top starts\n    {\n        vector<Cand> starts = pool;\n        sort(starts.begin(), starts.end(), [](const Cand& a, const Cand& b) { return a.K < b.K; });\n        if ((int)starts.size() > 3) starts.resize(3);\n\n        for (auto cur : starts) {\n            if (elapsed() > SEARCH_T) break;\n\n            for (int pass = 0; pass < 2; ++pass) {\n                if (elapsed() > SEARCH_T) break;\n                bool improved = false;\n\n                // optimize zone path modes\n                for (int z = 0; z < 3; ++z) {\n                    if (elapsed() > SEARCH_T) break;\n                    int bestK = cur.K;\n                    uint8_t bestPm = cur.p.pm[z];\n\n                    for (int pm : path_modes) {\n                        if (pm == cur.p.pm[z]) continue;\n                        Policy np = cur.p;\n                        np.pm[z] = (uint8_t)pm;\n                        int nk;\n                        if (eval_policy(np, nk) && nk < bestK) {\n                            bestK = nk;\n                            bestPm = (uint8_t)pm;\n                        }\n                    }\n                    if (bestPm != cur.p.pm[z]) {\n                        cur.p.pm[z] = bestPm;\n                        cur.K = bestK;\n                        improved = true;\n                    }\n                }\n\n                // optimize row modes (forward/backward)\n                for (int i = 0; i < N; ++i) {\n                    if (elapsed() > SEARCH_T) break;\n                    int x = (pass == 0 ? i : (N - 1 - i));\n\n                    int bestK = cur.K;\n                    uint8_t bestMode = cur.p.row_mode[x];\n\n                    for (int m : row_modes) {\n                        if (m == cur.p.row_mode[x]) continue;\n                        Policy np = cur.p;\n                        np.row_mode[x] = (uint8_t)m;\n                        int nk;\n                        if (eval_policy(np, nk) && nk < bestK) {\n                            bestK = nk;\n                            bestMode = (uint8_t)m;\n                        }\n                    }\n\n                    if (bestMode != cur.p.row_mode[x]) {\n                        cur.p.row_mode[x] = bestMode;\n                        cur.K = bestK;\n                        improved = true;\n                    }\n                }\n\n                // mirror toggle\n                if (elapsed() <= SEARCH_T) {\n                    Policy np = cur.p;\n                    np.mirror = !np.mirror;\n                    int nk;\n                    if (eval_policy(np, nk) && nk < cur.K) {\n                        cur = Cand{np, nk, hash_policy(np)};\n                        improved = true;\n                    }\n                }\n\n                add_pool(pool, cur, POOL_MAX);\n                if (!improved) break;\n            }\n        }\n    }\n\n    // Random mutation search\n    {\n        int it = 0;\n        while (elapsed() < SEARCH_T) {\n            if (pool.empty()) break;\n            if ((it & 31) == 0) sort_pool();\n\n            int top = min((int)pool.size(), 6);\n            const Cand& base = pool[(int)(rng() % top)];\n            Policy np = base.p;\n\n            if ((rng() % 100) < 18) np.mirror = !np.mirror;\n\n            if ((rng() % 100) < 45) {\n                int z = (int)(rng() % 3);\n                np.pm[z] = (uint8_t)path_modes[(int)(rng() % path_modes.size())];\n            }\n            if ((rng() % 100) < 20) {\n                int z = (int)(rng() % 3);\n                np.pm[z] = (uint8_t)path_modes[(int)(rng() % path_modes.size())];\n            }\n\n            int mut = 1 + (int)(rng() % 4);\n            if ((rng() % 100) < 10) mut += 4;\n\n            for (int i = 0; i < mut; ++i) {\n                int x = (int)(rng() % N);\n                np.row_mode[x] = (uint8_t)row_modes[(int)(rng() % row_modes.size())];\n            }\n\n            if ((rng() % 100) < 20) {\n                int l = (int)(rng() % N);\n                int len = 1 + (int)(rng() % 6);\n                uint8_t m = (uint8_t)row_modes[(int)(rng() % row_modes.size())];\n                for (int x = l; x < N && x < l + len; ++x) np.row_mode[x] = m;\n            }\n\n            int nk;\n            eval_policy(np, nk);\n            ++it;\n        }\n    }\n\n    if (pool.empty()) {\n        int k;\n        eval_policy(make_safe_policy(false), k);\n    }\n\n    sort_pool();\n\n    vector<Cand> finals = pool;\n    if ((int)finals.size() > 4) finals.resize(4);\n\n    int bestK = (int)1e9;\n    vector<Move> bestOps;\n\n    for (int i = 0; i < (int)finals.size(); ++i) {\n        if (elapsed() > FINAL_T) break;\n\n        EvalRes r = run_policy(init, finals[i].p, true);\n        if (r.E != 0) continue;\n\n        vector<Move> ops = compress_ops(r.ops);\n\n        // prune top candidates\n        if (i < 2 && elapsed() < FINAL_T - 0.02) {\n            prune_ops(init, ops, elapsed, FINAL_T, rng);\n        }\n\n        int e = calcE_after_ops(init, ops);\n        if (e == 0 && (int)ops.size() < bestK) {\n            bestK = (int)ops.size();\n            bestOps = std::move(ops);\n        }\n    }\n\n    // Safe fallback\n    if (bestOps.empty()) {\n        EvalRes a = run_policy(init, make_safe_policy(false), true);\n        EvalRes b = run_policy(init, make_safe_policy(true), true);\n\n        vector<Move> oa = compress_ops(a.ops);\n        vector<Move> ob = compress_ops(b.ops);\n\n        int ea = calcE_after_ops(init, oa);\n        int eb = calcE_after_ops(init, ob);\n\n        if (ea == 0 && (eb != 0 || (int)oa.size() <= (int)ob.size())) bestOps = std::move(oa);\n        else if (eb == 0) bestOps = std::move(ob);\n        else bestOps.clear();\n    }\n\n    // Final guard\n    bestOps = compress_ops(bestOps);\n    if ((int)bestOps.size() > 10000) bestOps.resize(10000);\n\n    // if still invalid, output 0 as last resort\n    if (!bestOps.empty() && calcE_after_ops(init, bestOps) != 0) {\n        bestOps.clear();\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (const auto& m : bestOps) {\n        cout << m.x1 << ' ' << m.y1 << ' ' << m.x2 << ' ' << m.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int r, c; };\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick(int n_ = 0) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int idx) const {\n        if (idx < 0) return 0;\n        int s = 0;\n        for (++idx; idx > 0; idx -= idx & -idx) s += bit[idx];\n        return s;\n    }\n};\n\nstatic inline bool bit_test(uint64_t lo, uint64_t hi, int b) {\n    if (b < 64) return (lo >> b) & 1ULL;\n    return (hi >> (b - 64)) & 1ULL;\n}\nstatic inline void bit_set(uint64_t& lo, uint64_t& hi, int b) {\n    if (b < 64) lo |= (1ULL << b);\n    else hi |= (1ULL << (b - 64));\n}\nstatic inline void bit_clear(uint64_t& lo, uint64_t& hi, int b) {\n    if (b < 64) lo &= ~(1ULL << b);\n    else hi &= ~(1ULL << (b - 64));\n}\nstatic inline int pop_below(uint64_t lo, uint64_t hi, int k) {\n    if (k <= 0) return 0;\n    if (k < 64) {\n        uint64_t m = (1ULL << k) - 1ULL;\n        return __builtin_popcountll(lo & m);\n    }\n    if (k == 64) return __builtin_popcountll(lo);\n    int kk = k - 64;\n    uint64_t m = (1ULL << kk) - 1ULL;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & m);\n}\ntemplate <class F>\nstatic inline void for_each_bit(uint64_t lo, uint64_t hi, F f) {\n    while (lo) {\n        int b = __builtin_ctzll(lo);\n        lo &= lo - 1;\n        f(b);\n    }\n    while (hi) {\n        int b = __builtin_ctzll(hi);\n        hi &= hi - 1;\n        f(b + 64);\n    }\n}\n\nstruct BeamState {\n    uint64_t rlo, rhi; // removed cells\n    uint64_t flo, fhi; // frontier\n    uint64_t llo, lhi; // removed labels\n    int cost;          // inversions in decided prefix\n    int cross;         // unavoidable inv: decided prefix vs remaining\n    int forced;        // unavoidable inv among remaining from mustBefore\n    int parent;\n    int mv;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    if (!(cin >> D >> N)) return 0;\n\n    const int er = 0;\n    const int ec = (D - 1) / 2;\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int i = 0; i < N; i++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    auto inb = [&](int r, int c) -> bool {\n        return (0 <= r && r < D && 0 <= c && c < D);\n    };\n\n    // Build free cells (excluding entrance and obstacles)\n    vector<vector<int>> id(D, vector<int>(D, -1));\n    vector<Pos> cells;\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == er && j == ec) continue;\n        if (obstacle[i][j]) continue;\n        id[i][j] = (int)cells.size();\n        cells.push_back({i, j});\n    }\n\n    const int M = (int)cells.size();\n    const int ENT = M;\n\n    // Graph\n    vector<vector<int>> adj(M + 1);\n    vector<uint64_t> neiLo(M, 0), neiHi(M, 0);\n    vector<char> adjEnt(M, 0);\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = cells[i];\n        for (int d = 0; d < 4; d++) {\n            int nr = r + dr[d], nc = c + dc[d];\n            if (!inb(nr, nc) || obstacle[nr][nc]) continue;\n            if (nr == er && nc == ec) {\n                adj[i].push_back(ENT);\n                adj[ENT].push_back(i);\n                adjEnt[i] = 1;\n            } else {\n                int j = id[nr][nc];\n                if (j >= 0) {\n                    adj[i].push_back(j);\n                    if (j < 64) neiLo[i] |= (1ULL << j);\n                    else neiHi[i] |= (1ULL << (j - 64));\n                }\n            }\n        }\n    }\n\n    uint64_t allLo = 0, allHi = 0;\n    for (int i = 0; i < M; i++) bit_set(allLo, allHi, i);\n\n    uint64_t entLo = 0, entHi = 0;\n    for (int i = 0; i < M; i++) if (adjEnt[i]) bit_set(entLo, entHi, i);\n\n    auto compute_articulation = [&](const vector<char>& active, vector<char>& isArt) {\n        vector<int> disc(M + 1, -1), low(M + 1, 0), par(M + 1, -1);\n        fill(isArt.begin(), isArt.end(), 0);\n        int timer = 0;\n\n        function<void(int)> dfs = [&](int u) {\n            disc[u] = low[u] = ++timer;\n            for (int v : adj[u]) {\n                if (v != ENT && !active[v]) continue;\n                if (disc[v] == -1) {\n                    par[v] = u;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (u != ENT && low[v] >= disc[u]) isArt[u] = 1;\n                } else if (v != par[u]) {\n                    low[u] = min(low[u], disc[v]);\n                }\n            }\n        };\n        dfs(ENT);\n    };\n\n    auto bfs_dist = [&](const vector<char>& active) -> vector<int> {\n        vector<int> dist(M, -1);\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            int du = (u == ENT ? 0 : dist[u]);\n            for (int v : adj[u]) {\n                if (v != ENT && !active[v]) continue;\n                if (vis[v]) continue;\n                vis[v] = 1;\n                if (v != ENT) dist[v] = du + 1;\n                q.push(v);\n            }\n        }\n        return dist;\n    };\n\n    auto reachable_count = [&](const vector<char>& active, int ban) -> int {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n        int cnt = 0;\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                if (v == ENT || v == ban || !active[v] || vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    vector<char> allActive(M, 1);\n    vector<int> distStatic = bfs_dist(allActive);\n\n    // mustBefore[u][v] = removing u disconnects v from entrance in full graph\n    vector<vector<unsigned char>> mustBefore(M, vector<unsigned char>(M, 0));\n    vector<int> domOut(M, 0), domIn(M, 0);\n    long long totalMustPairs = 0;\n\n    for (int ban = 0; ban < M; ban++) {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                if (v == ban || vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n            }\n        }\n        for (int v = 0; v < M; v++) {\n            if (v == ban) continue;\n            if (!vis[v]) {\n                mustBefore[ban][v] = 1;\n                domOut[ban]++;\n                domIn[v]++;\n                totalMustPairs++;\n            }\n        }\n    }\n\n    vector<uint64_t> descLo(M, 0), descHi(M, 0), ancLo(M, 0), ancHi(M, 0);\n    for (int u = 0; u < M; u++) for (int v = 0; v < M; v++) if (mustBefore[u][v]) {\n        bit_set(descLo[u], descHi[u], v);\n        bit_set(ancLo[v], ancHi[v], u);\n    }\n\n    // Reverse-peeling priority\n    vector<char> alive(M, 1), isArt(M + 1, 0);\n    vector<int> peelStep(M, -1);\n\n    for (int step = 0; step < M; step++) {\n        compute_articulation(alive, isArt);\n        vector<int> dist = bfs_dist(alive);\n\n        int best = -1, bestD = -1, bestMan = -1;\n        for (int c = 0; c < M; c++) {\n            if (!alive[c] || isArt[c]) continue;\n            int d = dist[c];\n            int man = abs(cells[c].r - er) + abs(cells[c].c - ec);\n            if (best == -1 ||\n                d > bestD ||\n                (d == bestD && man > bestMan) ||\n                (d == bestD && man == bestMan &&\n                 (cells[c].r > cells[best].r ||\n                  (cells[c].r == cells[best].r && cells[c].c > cells[best].c)))) {\n                best = c;\n                bestD = d;\n                bestMan = man;\n            }\n        }\n        if (best == -1) {\n            for (int c = 0; c < M; c++) if (alive[c]) { best = c; break; }\n        }\n        peelStep[best] = step;\n        alive[best] = 0;\n    }\n\n    vector<int> prio(M);\n    for (int c = 0; c < M; c++) prio[c] = M - 1 - peelStep[c];\n\n    vector<int> orderByPrio(M);\n    iota(orderByPrio.begin(), orderByPrio.end(), 0);\n    sort(orderByPrio.begin(), orderByPrio.end(), [&](int a, int b) {\n        return prio[a] < prio[b];\n    });\n\n    double mustDensity = 0.0;\n    if (M >= 2) mustDensity = (double)totalMustPairs / (double)(M * (M - 1));\n\n    // ---------- Online insertion ----------\n    vector<char> inU(M, 1);\n    uint64_t Ulo = allLo, Uhi = allHi;\n    vector<int> labelAt(M, -1);\n    vector<int> assigned;\n    assigned.reserve(M);\n\n    Fenwick unseen(M);\n    for (int x = 0; x < M; x++) unseen.add(x, 1);\n\n    bool useMandPrimary = (mustDensity > 0.03);\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        if (!(cin >> t)) return 0;\n\n        int rem = M - step;\n        int qrank = unseen.sumPrefix(t - 1);\n\n        compute_articulation(inU, isArt);\n\n        vector<int> safe;\n        safe.reserve(rem);\n        for (int c = 0; c < M; c++) if (inU[c] && !isArt[c]) safe.push_back(c);\n\n        if (safe.empty()) {\n            for (int c = 0; c < M; c++) {\n                if (!inU[c]) continue;\n                if (reachable_count(inU, c) == rem - 1) safe.push_back(c);\n            }\n        }\n\n        vector<int> remRank(M, -1);\n        int ridx = 0;\n        for (int c : orderByPrio) if (inU[c]) remRank[c] = ridx++;\n\n        bool low = (2 * qrank < rem);\n\n        auto better_tie = [&](int a, int b) -> bool {\n            if (b == -1) return true;\n            if (low) {\n                if (prio[a] != prio[b]) return prio[a] < prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] < distStatic[b];\n            } else {\n                if (prio[a] != prio[b]) return prio[a] > prio[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] > distStatic[b];\n            }\n            if (domOut[a] != domOut[b]) return domOut[a] > domOut[b];\n            if (cells[a].r != cells[b].r) return cells[a].r < cells[b].r;\n            return cells[a].c < cells[b].c;\n        };\n\n        int best = -1;\n        long long bestScore = (1LL << 60);\n        int bestMand = INT_MAX;\n        long long bestExpMand = (1LL << 62);\n\n        for (int c : safe) {\n            int r = remRank[c];\n\n            int invPast = 0;\n            int mandPast = 0;\n            for (int a : assigned) {\n                int la = labelAt[a];\n                if (prio[a] < prio[c] && la > t) invPast++;\n                if (prio[a] > prio[c] && la < t) invPast++;\n\n                if (mustBefore[a][c] && la > t) mandPast++;\n                if (mustBefore[c][a] && t > la) mandPast++;\n            }\n\n            long long score = (long long)invPast + llabs((long long)r - qrank);\n            if (useMandPrimary) score += mandPast;\n\n            long long expMand = 0;\n            if (rem > 1) {\n                uint64_t tmpLo = Ulo, tmpHi = Uhi;\n                bit_clear(tmpLo, tmpHi, c);\n                int descCnt = __builtin_popcountll(descLo[c] & tmpLo) + __builtin_popcountll(descHi[c] & tmpHi);\n                int ancCnt  = __builtin_popcountll(ancLo[c]  & tmpLo) + __builtin_popcountll(ancHi[c]  & tmpHi);\n                int smaller = qrank;\n                int larger = rem - 1 - smaller;\n                expMand = 1LL * descCnt * smaller + 1LL * ancCnt * larger; // denominator omitted\n            }\n\n            if (best == -1 ||\n                score < bestScore ||\n                (score == bestScore && mandPast < bestMand) ||\n                (score == bestScore && mandPast == bestMand && expMand < bestExpMand) ||\n                (score == bestScore && mandPast == bestMand && expMand == bestExpMand && better_tie(c, best))) {\n                best = c;\n                bestScore = score;\n                bestMand = mandPast;\n                bestExpMand = expMand;\n            }\n        }\n\n        if (best == -1) {\n            for (int c = 0; c < M; c++) if (inU[c]) { best = c; break; }\n        }\n\n        inU[best] = 0;\n        bit_clear(Ulo, Uhi, best);\n        labelAt[best] = t;\n        assigned.push_back(best);\n        unseen.add(t, -1);\n\n        cout << cells[best].r << ' ' << cells[best].c << '\\n' << flush;\n    }\n\n    // ---------- Offline unloading ----------\n    auto offStart = chrono::steady_clock::now();\n    auto off_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - offStart).count();\n    };\n    const long long TIME_LIMIT = 1910; // offline budget guard\n\n    auto accessible = [&](int c, uint64_t rlo, uint64_t rhi) -> bool {\n        if (adjEnt[c]) return true;\n        if ((neiLo[c] & rlo) != 0ULL) return true;\n        if ((neiHi[c] & rhi) != 0ULL) return true;\n        return false;\n    };\n\n    auto verify_order = [&](const vector<int>& ord) -> bool {\n        if ((int)ord.size() != M) return false;\n        vector<char> used(M, 0);\n        uint64_t rlo = 0, rhi = 0;\n        for (int c : ord) {\n            if (c < 0 || c >= M || used[c]) return false;\n            if (!accessible(c, rlo, rhi)) return false;\n            used[c] = 1;\n            bit_set(rlo, rhi, c);\n        }\n        return true;\n    };\n\n    auto inversion_count = [&](const vector<int>& ord) -> long long {\n        Fenwick fw(M);\n        long long inv = 0;\n        int seen = 0;\n        for (int c : ord) {\n            int x = labelAt[c];\n            int le = fw.sumPrefix(x);\n            inv += (long long)seen - le;\n            fw.add(x, 1);\n            seen++;\n        }\n        return inv;\n    };\n\n    // bad pairs for forced lower bound\n    vector<uint64_t> badOutLo(M, 0), badOutHi(M, 0), badInLo(M, 0), badInHi(M, 0);\n    int forcedAll = 0;\n    for (int u = 0; u < M; u++) for (int v = 0; v < M; v++) {\n        if (mustBefore[u][v] && labelAt[u] > labelAt[v]) {\n            bit_set(badOutLo[u], badOutHi[u], v);\n            bit_set(badInLo[v], badInHi[v], u);\n            forcedAll++;\n        }\n    }\n\n    // mode:\n    // 0: label-first\n    // 1: label - w*domOut\n    // 2: prio-first\n    int domW = (mustDensity > 0.05 ? 2 : 1);\n\n    auto greedy_order = [&](int mode) -> vector<int> {\n        vector<int> ord;\n        ord.reserve(M);\n\n        uint64_t rlo = 0, rhi = 0;\n        uint64_t flo = entLo, fhi = entHi;\n\n        for (int depth = 0; depth < M; depth++) {\n            int best = -1;\n\n            for_each_bit(flo, fhi, [&](int c) {\n                if (best == -1) { best = c; return; }\n\n                if (mode == 0) {\n                    if (labelAt[c] < labelAt[best] ||\n                        (labelAt[c] == labelAt[best] && prio[c] < prio[best]) ||\n                        (labelAt[c] == labelAt[best] && prio[c] == prio[best] && c < best)) {\n                        best = c;\n                    }\n                } else if (mode == 1) {\n                    int ka = labelAt[c] - domW * domOut[c];\n                    int kb = labelAt[best] - domW * domOut[best];\n                    if (ka < kb ||\n                        (ka == kb && labelAt[c] < labelAt[best]) ||\n                        (ka == kb && labelAt[c] == labelAt[best] && prio[c] < prio[best]) ||\n                        (ka == kb && labelAt[c] == labelAt[best] && prio[c] == prio[best] && c < best)) {\n                        best = c;\n                    }\n                } else {\n                    if (prio[c] < prio[best] ||\n                        (prio[c] == prio[best] && labelAt[c] < labelAt[best]) ||\n                        (prio[c] == prio[best] && labelAt[c] == labelAt[best] && c < best)) {\n                        best = c;\n                    }\n                }\n            });\n\n            if (best == -1) {\n                for (int c = 0; c < M; c++) if (!bit_test(rlo, rhi, c)) { best = c; break; }\n            }\n\n            ord.push_back(best);\n            bit_set(rlo, rhi, best);\n\n            bit_clear(flo, fhi, best);\n            flo |= neiLo[best];\n            fhi |= neiHi[best];\n            flo |= entLo;\n            fhi |= entHi;\n            flo &= ~rlo;\n            fhi &= ~rhi;\n        }\n\n        return ord;\n    };\n\n    // Beam eval modes:\n    // 0: cross + forced\n    // 1: cross\n    // 2: cost\n    // 3: cost + cross\n    auto run_beam = [&](int BEAM_WIDTH, int mode) -> vector<int> {\n        auto eval = [&](const BeamState& s) -> long long {\n            if (mode == 0) return (long long)s.cross + s.forced;\n            if (mode == 1) return (long long)s.cross;\n            if (mode == 2) return (long long)s.cost;\n            return (long long)s.cost + s.cross;\n        };\n\n        vector<BeamState> pool;\n        pool.reserve(1 + (size_t)BEAM_WIDTH * (M + 2));\n        pool.push_back({0ULL, 0ULL, entLo, entHi, 0ULL, 0ULL, 0, 0, forcedAll, -1, -1});\n        vector<int> beam = {0};\n\n        for (int depth = 0; depth < M; depth++) {\n            vector<BeamState> nxt;\n            nxt.reserve((size_t)beam.size() * 14);\n\n            for (int sid : beam) {\n                const BeamState& st = pool[sid];\n                uint64_t remLo = allLo & ~st.rlo;\n                uint64_t remHi = allHi & ~st.rhi;\n\n                for_each_bit(st.flo, st.fhi, [&](int c) {\n                    BeamState nx;\n\n                    nx.rlo = st.rlo; nx.rhi = st.rhi;\n                    bit_set(nx.rlo, nx.rhi, c);\n\n                    nx.flo = st.flo; nx.fhi = st.fhi;\n                    bit_clear(nx.flo, nx.fhi, c);\n                    nx.flo |= neiLo[c];\n                    nx.fhi |= neiHi[c];\n                    nx.flo |= entLo;\n                    nx.fhi |= entHi;\n                    nx.flo &= ~nx.rlo;\n                    nx.fhi &= ~nx.rhi;\n\n                    nx.llo = st.llo; nx.lhi = st.lhi;\n                    int lab = labelAt[c];\n                    int removedSmaller = pop_below(st.llo, st.lhi, lab);\n\n                    nx.cost = st.cost + (depth - removedSmaller);\n                    nx.cross = st.cross + (lab - removedSmaller);\n                    bit_set(nx.llo, nx.lhi, lab);\n\n                    int subOut = __builtin_popcountll(badOutLo[c] & remLo) + __builtin_popcountll(badOutHi[c] & remHi);\n                    int subIn  = __builtin_popcountll(badInLo[c]  & remLo) + __builtin_popcountll(badInHi[c]  & remHi);\n                    nx.forced = st.forced - subOut - subIn;\n\n                    nx.parent = sid;\n                    nx.mv = c;\n                    nxt.push_back(nx);\n                });\n            }\n\n            if (nxt.empty()) return {};\n\n            sort(nxt.begin(), nxt.end(), [](const BeamState& a, const BeamState& b) {\n                if (a.rlo != b.rlo) return a.rlo < b.rlo;\n                if (a.rhi != b.rhi) return a.rhi < b.rhi;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.cross != b.cross) return a.cross < b.cross;\n                return a.forced < b.forced;\n            });\n\n            vector<BeamState> uniq;\n            uniq.reserve(nxt.size());\n            for (const auto& s : nxt) {\n                if (uniq.empty() || s.rlo != uniq.back().rlo || s.rhi != uniq.back().rhi) {\n                    uniq.push_back(s);\n                }\n            }\n\n            auto cmpEval = [&](const BeamState& a, const BeamState& b) {\n                long long ea = eval(a), eb = eval(b);\n                if (ea != eb) return ea < eb;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.cross != b.cross) return a.cross < b.cross;\n                if (a.forced != b.forced) return a.forced < b.forced;\n                if (a.rlo != b.rlo) return a.rlo < b.rlo;\n                return a.rhi < b.rhi;\n            };\n\n            if ((int)uniq.size() > BEAM_WIDTH) {\n                nth_element(uniq.begin(), uniq.begin() + BEAM_WIDTH, uniq.end(), cmpEval);\n                uniq.resize(BEAM_WIDTH);\n            }\n            sort(uniq.begin(), uniq.end(), cmpEval);\n\n            beam.clear();\n            beam.reserve(uniq.size());\n            for (const auto& s : uniq) {\n                pool.push_back(s);\n                beam.push_back((int)pool.size() - 1);\n            }\n        }\n\n        if (beam.empty()) return {};\n\n        int bestSid = beam[0];\n        for (int sid : beam) {\n            if (pool[sid].cost < pool[bestSid].cost ||\n                (pool[sid].cost == pool[bestSid].cost && pool[sid].cross < pool[bestSid].cross)) {\n                bestSid = sid;\n            }\n        }\n\n        vector<int> ord;\n        ord.reserve(M);\n        while (bestSid != -1 && pool[bestSid].parent != -1) {\n            ord.push_back(pool[bestSid].mv);\n            bestSid = pool[bestSid].parent;\n        }\n        reverse(ord.begin(), ord.end());\n        if ((int)ord.size() != M) return {};\n        return ord;\n    };\n\n    auto local_adjacent = [&](vector<int>& ord, int maxIter, long long deadline_ms) {\n        if ((int)ord.size() != M) return;\n        if (!verify_order(ord)) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if (off_ms() > deadline_ms) return;\n            bool changed = false;\n\n            uint64_t rlo = 0, rhi = 0;\n            for (int i = 0; i + 1 < M; i++) {\n                int a = ord[i], b = ord[i + 1];\n\n                if (labelAt[a] > labelAt[b]) {\n                    if (accessible(b, rlo, rhi)) {\n                        uint64_t lo2 = rlo, hi2 = rhi;\n                        bit_set(lo2, hi2, b);\n                        if (accessible(a, lo2, hi2)) {\n                            swap(ord[i], ord[i + 1]);\n                            changed = true;\n                            bit_set(rlo, rhi, b);\n                            continue;\n                        }\n                    }\n                }\n\n                bit_set(rlo, rhi, ord[i]);\n            }\n            if (!changed) break;\n        }\n    };\n\n    auto optimize_windows = [&](vector<int>& ord, int L, int passLim, long long deadline_ms) {\n        if ((int)ord.size() != M || L <= 1 || M < L) return;\n        if (!verify_order(ord)) return;\n\n        for (int pass = 0; pass < passLim; pass++) {\n            if (off_ms() > deadline_ms) return;\n            bool changed = false;\n\n            uint64_t preLo = 0, preHi = 0;\n            for (int l = 0; l + L <= M; l++) {\n                if (off_ms() > deadline_ms) return;\n\n                vector<int> w(L), lab(L), lessMask(L, 0);\n                for (int i = 0; i < L; i++) {\n                    w[i] = ord[l + i];\n                    lab[i] = labelAt[w[i]];\n                }\n\n                int curInv = 0;\n                for (int i = 0; i < L; i++) for (int j = i + 1; j < L; j++) {\n                    if (lab[i] > lab[j]) curInv++;\n                }\n\n                for (int i = 0; i < L; i++) {\n                    int m = 0;\n                    for (int j = 0; j < L; j++) if (lab[j] < lab[i]) m |= (1 << j);\n                    lessMask[i] = m;\n                }\n\n                int S = 1 << L;\n                vector<uint64_t> subLo(S, 0), subHi(S, 0);\n                for (int mask = 1; mask < S; mask++) {\n                    int b = __builtin_ctz((unsigned)mask);\n                    int pm = mask & (mask - 1);\n                    subLo[mask] = subLo[pm];\n                    subHi[mask] = subHi[pm];\n                    bit_set(subLo[mask], subHi[mask], w[b]);\n                }\n\n                const int INF = 1e9;\n                vector<int> dp(S, INF), pmask(S, -1), pick(S, -1);\n                dp[0] = 0;\n\n                for (int mask = 0; mask < S; mask++) {\n                    if (dp[mask] >= INF) continue;\n\n                    int k = __builtin_popcount((unsigned)mask);\n                    uint64_t rlo = preLo | subLo[mask];\n                    uint64_t rhi = preHi | subHi[mask];\n\n                    for (int i = 0; i < L; i++) if (((mask >> i) & 1) == 0) {\n                        int v = w[i];\n                        if (!accessible(v, rlo, rhi)) continue;\n\n                        int chosenLess = __builtin_popcount((unsigned)(mask & lessMask[i]));\n                        int add = k - chosenLess;\n                        int nm = mask | (1 << i);\n                        int cand = dp[mask] + add;\n                        if (cand < dp[nm]) {\n                            dp[nm] = cand;\n                            pmask[nm] = mask;\n                            pick[nm] = i;\n                        }\n                    }\n                }\n\n                int full = S - 1;\n                if (dp[full] < curInv) {\n                    vector<int> seq(L);\n                    int mask = full;\n                    for (int pos = L - 1; pos >= 0; pos--) {\n                        int i = pick[mask];\n                        seq[pos] = w[i];\n                        mask = pmask[mask];\n                    }\n                    for (int i = 0; i < L; i++) ord[l + i] = seq[i];\n                    changed = true;\n                }\n\n                bit_set(preLo, preHi, ord[l]);\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto anneal_adjacent = [&](vector<int> ord, int ITER, uint64_t seed, long long deadline_ms) -> vector<int> {\n        if ((int)ord.size() != M || M <= 1 || ITER <= 0) return ord;\n        if (!verify_order(ord)) return ord;\n\n        uint64_t x = (seed ? seed : 88172645463325252ULL);\n        auto rnd = [&]() -> uint64_t {\n            x ^= x << 7;\n            x ^= x >> 9;\n            return x;\n        };\n\n        long long curInv = inversion_count(ord);\n        long long bestInv = curInv;\n        vector<int> bestOrd = ord;\n\n        vector<uint64_t> preLo(M + 1), preHi(M + 1);\n        auto rebuild = [&]() {\n            preLo[0] = 0;\n            preHi[0] = 0;\n            for (int i = 0; i < M; i++) {\n                preLo[i + 1] = preLo[i];\n                preHi[i + 1] = preHi[i];\n                bit_set(preLo[i + 1], preHi[i + 1], ord[i]);\n            }\n        };\n        rebuild();\n\n        for (int it = 0; it < ITER; it++) {\n            if (off_ms() > deadline_ms) break;\n\n            int i = (int)(rnd() % (M - 1));\n            int a = ord[i], b = ord[i + 1];\n\n            uint64_t rlo = preLo[i], rhi = preHi[i];\n            if (!accessible(b, rlo, rhi)) continue;\n            bit_set(rlo, rhi, b);\n            if (!accessible(a, rlo, rhi)) continue;\n\n            int delta = (labelAt[a] > labelAt[b]) ? -1 : +1;\n\n            bool accept = false;\n            if (delta < 0) {\n                accept = true;\n            } else {\n                int p = (int)(70LL * (ITER - it) / ITER); // mild uphill\n                if ((int)(rnd() % 1000) < p) accept = true;\n            }\n\n            if (accept) {\n                swap(ord[i], ord[i + 1]);\n                curInv += delta;\n                rebuild();\n\n                if (curInv < bestInv) {\n                    bestInv = curInv;\n                    bestOrd = ord;\n                }\n            }\n        }\n\n        return bestOrd;\n    };\n\n    auto hash_order = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (int v : ord) {\n            h ^= (uint64_t)(v + 1);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    };\n\n    vector<vector<int>> cands;\n    unordered_set<uint64_t> seenHash;\n    seenHash.reserve(64);\n\n    auto add_candidate = [&](vector<int> ord) {\n        if (ord.empty()) return;\n        if (!verify_order(ord)) return;\n\n        // Light polish\n        local_adjacent(ord, 120, TIME_LIMIT - 240);\n        if (off_ms() < TIME_LIMIT - 260) optimize_windows(ord, 9, 1, TIME_LIMIT - 240);\n        local_adjacent(ord, 60, TIME_LIMIT - 220);\n\n        if (!verify_order(ord)) return;\n        uint64_t h = hash_order(ord);\n        if (seenHash.insert(h).second) cands.push_back(move(ord));\n    };\n\n    // Initial diversified candidates\n    add_candidate(greedy_order(0));\n    if (mustDensity > 0.015) add_candidate(greedy_order(1));\n    if (mustDensity > 0.035) add_candidate(greedy_order(2));\n\n    add_candidate(run_beam(2300, 1)); // main\n    if (off_ms() < TIME_LIMIT - 700) add_candidate(run_beam(1300, 0));\n    if (off_ms() < TIME_LIMIT - 500) add_candidate(run_beam(900, 3));\n    if (off_ms() < TIME_LIMIT - 350) add_candidate(run_beam(700, 2));\n\n    if (cands.empty()) cands.push_back(greedy_order(0));\n\n    vector<pair<long long, int>> ranking;\n    for (int i = 0; i < (int)cands.size(); i++) {\n        if (!verify_order(cands[i])) continue;\n        ranking.push_back({inversion_count(cands[i]), i});\n    }\n    sort(ranking.begin(), ranking.end());\n\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < M; i++) {\n        seed ^= (uint64_t)(labelAt[i] + 1 + 131 * i);\n        seed *= 1099511628211ULL;\n    }\n\n    // Heavy refinement on top candidates\n    int topK = min(2, (int)ranking.size());\n    for (int k = 0; k < topK; k++) {\n        if (off_ms() > TIME_LIMIT - 120) break;\n\n        vector<int> ord = cands[ranking[k].second];\n        if (!verify_order(ord)) continue;\n\n        local_adjacent(ord, 220, TIME_LIMIT - 130);\n        if (off_ms() < TIME_LIMIT - 320) optimize_windows(ord, 12, 1, TIME_LIMIT - 140);\n        if (off_ms() < TIME_LIMIT - 260) optimize_windows(ord, 11, 1, TIME_LIMIT - 120);\n        if (off_ms() < TIME_LIMIT - 200) optimize_windows(ord, 10, 1, TIME_LIMIT - 100);\n        if (off_ms() < TIME_LIMIT - 160) optimize_windows(ord, 9, 1, TIME_LIMIT - 90);\n        local_adjacent(ord, 120, TIME_LIMIT - 80);\n\n        long long rem = TIME_LIMIT - off_ms();\n        if (rem > 130) {\n            int cap = (k == 0 ? 20000 : 12000);\n            int iter = (int)min<long long>(cap, rem * 85);\n            iter = max(iter, 3000);\n            ord = anneal_adjacent(ord, iter, seed + 0x9e3779b97f4a7c15ULL * (k + 1), TIME_LIMIT - 60);\n            local_adjacent(ord, 80, TIME_LIMIT - 40);\n            if (off_ms() < TIME_LIMIT - 30) optimize_windows(ord, 10, 1, TIME_LIMIT - 20);\n        }\n\n        if (verify_order(ord)) {\n            uint64_t h = hash_order(ord);\n            if (seenHash.insert(h).second) cands.push_back(move(ord));\n        }\n    }\n\n    vector<int> finalOrd;\n    long long bestInv = (1LL << 62);\n    for (auto& ord : cands) {\n        if (!verify_order(ord)) continue;\n        long long inv = inversion_count(ord);\n        if (inv < bestInv) {\n            bestInv = inv;\n            finalOrd = ord;\n        }\n    }\n\n    if (finalOrd.empty() || !verify_order(finalOrd)) finalOrd = greedy_order(0);\n\n    for (int c : finalOrd) {\n        cout << cells[c].r << ' ' << cells[c].c << '\\n';\n    }\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nconstexpr int NMAX = 50;\nconstexpr int CMAX = 101;\nconstexpr int INF = 1e9;\n\nstruct Problem {\n    int n = 0, m = 0;\n    array<array<int, NMAX>, NMAX> initGrid{};\n    array<int, CMAX> initCnt{};\n    array<array<int, CMAX>, CMAX> initEdgeCnt{};\n    array<array<bool, CMAX>, CMAX> targetAdj{};\n    array<bool, CMAX> canZero{};\n    array<int, CMAX> depth{};\n    array<int, CMAX> deg{};\n};\n\nstruct State {\n    struct ChangeRec {\n        int i, j;\n        int a, b;\n        int psz;\n        int u[10], v[10], d[10];\n    };\n\n    const Problem* pb = nullptr;\n\n    array<array<int, NMAX>, NMAX> g{};\n    array<int, CMAX> cnt{};\n    array<array<int, CMAX>, CMAX> edgeCnt{};\n    int zeroCount = 0;\n\n    array<array<int, NMAX>, NMAX> vis{};\n    int visToken = 1;\n\n    vector<int> order;\n\n    State() = default;\n    explicit State(const Problem* p) { init(p); }\n\n    void init(const Problem* p) {\n        pb = p;\n        g = pb->initGrid;\n        cnt = pb->initCnt;\n        edgeCnt = pb->initEdgeCnt;\n        zeroCount = cnt[0];\n\n        for (auto& row : vis) row.fill(0);\n        visToken = 1;\n\n        order.resize(pb->n * pb->n);\n        iota(order.begin(), order.end(), 0);\n    }\n\n    inline bool in(int x, int y) const {\n        return (0 <= x && x < pb->n && 0 <= y && y < pb->n);\n    }\n\n    bool connected_after_remove(int ri, int rj, int color, int si, int sj) {\n        int need = cnt[color] - 1;\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        vis[si][sj] = visToken;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        if (reached == need) return true;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != color) continue;\n                if (vis[nx][ny] == visToken) continue;\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n                if (reached == need) return true;\n            }\n        }\n        return reached == need;\n    }\n\n    // For 0-color: all remaining zero cells must be reachable from boundary zero cells.\n    bool zero_connected_after_remove(int ri, int rj) {\n        int need = cnt[0] - 1;\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        int reached = 0;\n\n        for (int i = 0; i < pb->n; i++) {\n            for (int j = 0; j < pb->n; j++) {\n                if (i != 0 && i != pb->n - 1 && j != 0 && j != pb->n - 1) continue;\n                if (i == ri && j == rj) continue;\n                if (g[i][j] != 0) continue;\n                if (vis[i][j] == visToken) continue;\n                vis[i][j] = visToken;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached == 0) return false;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != 0) continue;\n                if (vis[nx][ny] == visToken) continue;\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n\n        return reached == need;\n    }\n\n    bool try_change_rec(int i, int j, int b, ChangeRec& rec) {\n        int a = g[i][j];\n        if (a == b) return false;\n\n        // Keep all non-zero colors non-empty.\n        if (a > 0 && cnt[a] <= 1) return false;\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // New color connectivity local condition.\n        if (b == 0) {\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary) {\n                bool adj0 = false;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj) && g[ni][nj] == 0) {\n                        adj0 = true;\n                        break;\n                    }\n                }\n                if (!adj0) return false;\n            }\n        } else {\n            bool adjb = false;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (in(ni, nj) && g[ni][nj] == b) {\n                    adjb = true;\n                    break;\n                }\n            }\n            if (!adjb) return false;\n        }\n\n        int pu[10], pv[10], pd[10], psz = 0;\n        auto add_delta = [&](int x, int y, int d) {\n            if (x == y) return;\n            if (x > y) swap(x, y);\n            for (int t = 0; t < psz; t++) {\n                if (pu[t] == x && pv[t] == y) {\n                    pd[t] += d;\n                    return;\n                }\n            }\n            pu[psz] = x;\n            pv[psz] = y;\n            pd[psz] = d;\n            ++psz;\n        };\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + dx[d], nj = j + dy[d];\n            int x = in(ni, nj) ? g[ni][nj] : 0;\n            add_delta(a, x, -1);\n            add_delta(b, x, +1);\n        }\n\n        // Adjacency graph exact match.\n        for (int t = 0; t < psz; t++) {\n            int u = pu[t], v = pv[t];\n            int nc = edgeCnt[u][v] + pd[t];\n            if (nc < 0) return false;\n            if ((nc > 0) != pb->targetAdj[u][v]) return false;\n        }\n\n        // Old color connectivity after removal.\n        if (a > 0) {\n            int rem = cnt[a] - 1;\n            if (rem > 0) {\n                int same = 0, si = -1, sj = -1;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj) && g[ni][nj] == a) {\n                        ++same;\n                        if (si == -1) {\n                            si = ni; sj = nj;\n                        }\n                    }\n                }\n                if (same == 0) return false;\n                if (same >= 2 && rem > 1) {\n                    if (!connected_after_remove(i, j, a, si, sj)) return false;\n                }\n            }\n        } else {\n            int rem0 = cnt[0] - 1;\n            if (rem0 > 0) {\n                int adj0 = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj) && g[ni][nj] == 0) ++adj0;\n                }\n                bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n                bool needBFS = true;\n                if (!boundary && adj0 <= 1) needBFS = false;\n                if (boundary && adj0 == 0) needBFS = false;\n                if (needBFS && !zero_connected_after_remove(i, j)) return false;\n            }\n        }\n\n        // Apply + record.\n        rec.i = i; rec.j = j; rec.a = a; rec.b = b;\n        rec.psz = psz;\n        for (int t = 0; t < psz; t++) {\n            rec.u[t] = pu[t];\n            rec.v[t] = pv[t];\n            rec.d[t] = pd[t];\n        }\n\n        g[i][j] = b;\n        --cnt[a];\n        ++cnt[b];\n        if (a == 0) --zeroCount;\n        if (b == 0) ++zeroCount;\n\n        for (int t = 0; t < psz; t++) {\n            edgeCnt[pu[t]][pv[t]] += pd[t];\n        }\n\n        return true;\n    }\n\n    inline void undo_change(const ChangeRec& rec) {\n        g[rec.i][rec.j] = rec.a;\n        ++cnt[rec.a];\n        --cnt[rec.b];\n        if (rec.a == 0) ++zeroCount;\n        if (rec.b == 0) --zeroCount;\n        for (int t = 0; t < rec.psz; t++) {\n            edgeCnt[rec.u[t]][rec.v[t]] -= rec.d[t];\n        }\n    }\n\n    bool try_change(int i, int j, int b) {\n        ChangeRec rec;\n        return try_change_rec(i, j, b, rec);\n    }\n\n    bool try_swap(int i, int j, int ni, int nj) {\n        int a = g[i][j], b = g[ni][nj];\n        if (a <= 0 || b <= 0 || a == b) return false;\n\n        ChangeRec r1, r2;\n        if (try_change_rec(i, j, b, r1)) {\n            if (try_change_rec(ni, nj, a, r2)) return true;\n            undo_change(r1);\n        }\n        if (try_change_rec(ni, nj, a, r1)) {\n            if (try_change_rec(i, j, b, r2)) return true;\n            undo_change(r1);\n        }\n        return false;\n    }\n\n    int improve(const vector<int>& value, mt19937& rng, Clock::time_point deadline,\n                int maxPass, bool allowRecolor, int eqProb = 0, int upProb = 0) {\n        int totalChanges = 0;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (Clock::now() >= deadline) break;\n            bool changed = false;\n\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int t = 0; t < (int)order.size(); t++) {\n                if ((t & 127) == 0 && Clock::now() >= deadline) return totalChanges;\n\n                int idx = order[t];\n                int i = idx / pb->n;\n                int j = idx % pb->n;\n                int a = g[i][j];\n                if (a == 0) continue;\n\n                // Priority 1: delete to 0\n                if (pb->canZero[a]) {\n                    if (try_change(i, j, 0)) {\n                        changed = true;\n                        ++totalChanges;\n                        continue;\n                    }\n                }\n\n                if (!allowRecolor) continue;\n\n                // Priority 2: recolor to neighboring non-zero color\n                int cand[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b <= 0 || b == a) continue;\n\n                    bool ok = false;\n                    if (value[b] < value[a]) ok = true;\n                    else if (value[b] == value[a] && eqProb > 0 && (int)(rng() % eqProb) == 0) ok = true;\n                    else if (value[b] > value[a] && upProb > 0 && (int)(rng() % upProb) == 0) ok = true;\n                    if (!ok) continue;\n\n                    bool dup = false;\n                    for (int q = 0; q < k; q++) {\n                        if (cand[q] == b) { dup = true; break; }\n                    }\n                    if (!dup) cand[k++] = b;\n                }\n                if (k == 0) continue;\n\n                for (int x = 0; x < k; x++) {\n                    int r = x + (int)(rng() % (k - x));\n                    swap(cand[x], cand[r]);\n                }\n                for (int x = 1; x < k; x++) {\n                    int key = cand[x], y = x - 1;\n                    while (y >= 0 && value[cand[y]] > value[key]) {\n                        cand[y + 1] = cand[y];\n                        --y;\n                    }\n                    cand[y + 1] = key;\n                }\n\n                for (int q = 0; q < k; q++) {\n                    if (try_change(i, j, cand[q])) {\n                        changed = true;\n                        ++totalChanges;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return totalChanges;\n    }\n\n    int greedy_delete_queue(mt19937& rng, Clock::time_point deadline, int maxPop) {\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        auto near_zero = [&](int i, int j) {\n            if (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1) return true;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (in(ni, nj) && g[ni][nj] == 0) return true;\n            }\n            return false;\n        };\n\n        int total = pb->n * pb->n;\n        deque<int> dq;\n        vector<unsigned char> inq(total, 0);\n\n        auto push_cell = [&](int i, int j) {\n            int id = i * pb->n + j;\n            if (!inq[id]) {\n                inq[id] = 1;\n                dq.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < pb->n; i++) {\n            for (int j = 0; j < pb->n; j++) {\n                int a = g[i][j];\n                if (a == 0 || !pb->canZero[a]) continue;\n                if (near_zero(i, j)) push_cell(i, j);\n            }\n        }\n\n        int pops = 0, changes = 0;\n        while (!dq.empty() && pops < maxPop) {\n            if ((pops & 255) == 0 && Clock::now() >= deadline) break;\n\n            int id = dq.front();\n            dq.pop_front();\n            inq[id] = 0;\n            ++pops;\n\n            int i = id / pb->n;\n            int j = id % pb->n;\n            int a = g[i][j];\n            if (a == 0 || !pb->canZero[a]) continue;\n            if (!near_zero(i, j)) continue;\n\n            if (try_change(i, j, 0)) {\n                ++changes;\n                push_cell(i, j);\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj)) push_cell(ni, nj);\n                }\n            }\n        }\n        return changes;\n    }\n\n    int random_neutral_moves(mt19937& rng, Clock::time_point deadline, int steps) {\n        int success = 0;\n        int total = pb->n * pb->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 s = 0; s < steps; s++) {\n            if ((s & 63) == 0 && Clock::now() >= deadline) break;\n\n            for (int rep = 0; rep < 8; rep++) {\n                int idx = (int)(rng() % total);\n                int i = idx / pb->n, j = idx % pb->n;\n                int a = g[i][j];\n                if (a <= 0) continue;\n\n                int dirs[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b > 0 && b != a) dirs[k++] = d;\n                }\n                if (k == 0) continue;\n\n                int d = dirs[(int)(rng() % k)];\n                int ni = i + dx[d], nj = j + dy[d];\n                int b = g[ni][nj];\n\n                int op = (int)(rng() % 100);\n                bool ok = false;\n                if (op < 24) ok = try_swap(i, j, ni, nj);\n                else if (op < 66) ok = try_change(i, j, b);\n                else ok = try_change(ni, nj, a);\n\n                if (ok) ++success;\n                break;\n            }\n        }\n        return success;\n    }\n\n    int random_expand_moves(mt19937& rng, Clock::time_point deadline, int attempts) {\n        int success = 0;\n        int total = pb->n * pb->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 t = 0; t < attempts; t++) {\n            if ((t & 63) == 0 && Clock::now() >= deadline) break;\n\n            int idx = (int)(rng() % total);\n            int i = idx / pb->n, j = idx % pb->n;\n            if (g[i][j] != 0) continue;\n\n            int zdeg = 0;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (in(ni, nj) && g[ni][nj] == 0) ++zdeg;\n            }\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary && zdeg >= 2 && (int)(rng() % 3) != 0) continue;\n\n            int cand[4], k = 0;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (!in(ni, nj)) continue;\n                int b = g[ni][nj];\n                if (b <= 0) continue;\n                bool dup = false;\n                for (int q = 0; q < k; q++) {\n                    if (cand[q] == b) { dup = true; break; }\n                }\n                if (!dup) cand[k++] = b;\n            }\n            if (k == 0) continue;\n\n            int key[4];\n            for (int q = 0; q < k; q++) {\n                int b = cand[q];\n                key[q] = (pb->canZero[b] ? 0 : 10000) + pb->depth[b] * 100 + (int)(rng() % 20);\n            }\n            for (int x = 1; x < k; x++) {\n                int bc = cand[x], bk = key[x], y = x - 1;\n                while (y >= 0 && key[y] > bk) {\n                    key[y + 1] = key[y];\n                    cand[y + 1] = cand[y];\n                    --y;\n                }\n                key[y + 1] = bk;\n                cand[y + 1] = bc;\n            }\n\n            for (int q = 0; q < k; q++) {\n                if (try_change(i, j, cand[q])) {\n                    ++success;\n                    break;\n                }\n            }\n        }\n        return success;\n    }\n\n    // score-neutral shift: q:0->a and p:a->0 (or reverse)\n    int random_shift_zero_moves(mt19937& rng, Clock::time_point deadline, int steps) {\n        int success = 0;\n        int total = pb->n * pb->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 s = 0; s < steps; s++) {\n            if ((s & 63) == 0 && Clock::now() >= deadline) break;\n\n            for (int rep = 0; rep < 8; rep++) {\n                int idx = (int)(rng() % total);\n                int i = idx / pb->n, j = idx % pb->n;\n                int a = g[i][j];\n                if (a <= 0 || !pb->canZero[a]) continue;\n\n                int zni[4], znj[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    if (g[ni][nj] == 0) {\n                        zni[k] = ni; znj[k] = nj; ++k;\n                    }\n                }\n                if (k == 0) continue;\n\n                int t = (int)(rng() % k);\n                int qi = zni[t], qj = znj[t];\n\n                ChangeRec r1, r2;\n                bool ok = false;\n\n                if (try_change_rec(qi, qj, a, r1)) {\n                    if (try_change_rec(i, j, 0, r2)) {\n                        ok = true;\n                    } else {\n                        undo_change(r1);\n                    }\n                }\n\n                if (!ok) {\n                    if (try_change_rec(i, j, 0, r1)) {\n                        if (try_change_rec(qi, qj, a, r2)) {\n                            ok = true;\n                        } else {\n                            undo_change(r1);\n                        }\n                    }\n                }\n\n                if (ok) ++success;\n                break;\n            }\n        }\n\n        return success;\n    }\n};\n\nstatic vector<int> build_value(const Problem& pb, const State& st, int mode, mt19937& rng, int maxDepth) {\n    vector<int> value(pb.m + 1, 0);\n    value[0] = -1;\n\n    vector<int> cols(pb.m);\n    for (int i = 0; i < pb.m; i++) cols[i] = i + 1;\n    shuffle(cols.begin(), cols.end(), rng);\n\n    vector<int> prio(pb.m + 1, 0);\n    for (int i = 0; i < pb.m; i++) prio[cols[i]] = i;\n\n    for (int c = 1; c <= pb.m; c++) {\n        switch (mode) {\n            case 0: // depth\n                value[c] = pb.depth[c] * 10000 + prio[c];\n                break;\n            case 1: // random\n                value[c] = prio[c];\n                break;\n            case 2: // reverse depth\n                value[c] = (maxDepth - pb.depth[c]) * 10000 + prio[c];\n                break;\n            case 3: // canZero bias\n                value[c] = (pb.canZero[c] ? 0 : 250000) + pb.depth[c] * 1200 + prio[c];\n                break;\n            case 4: // degree\n                value[c] = (pb.m - pb.deg[c]) * 5000 + pb.depth[c] * 60 + prio[c];\n                break;\n            case 5: // size\n                value[c] = st.cnt[c] * 850 + pb.depth[c] * 35 + prio[c];\n                break;\n            case 6: // mixed\n                value[c] = (pb.canZero[c] ? st.cnt[c] * 220 : 90000 + st.cnt[c] * 220)\n                         + pb.depth[c] * 80 + prio[c];\n                break;\n            default: // strong canZero pressure\n                value[c] = (pb.canZero[c] ? 0 : 450000) + pb.depth[c] * 220 + st.cnt[c] * 45 + prio[c];\n                break;\n        }\n    }\n\n    return value;\n}\n\nbool validate_solution(const State& st) {\n    const Problem& pb = *st.pb;\n    int n = pb.n, m = pb.m;\n\n    array<int, CMAX> realCnt{};\n    realCnt.fill(0);\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (c < 0 || c > m) return false;\n            ++realCnt[c];\n        }\n    }\n\n    for (int c = 1; c <= m; c++) if (realCnt[c] == 0) return false;\n\n    array<array<bool, CMAX>, CMAX> adj{};\n    for (auto& row : adj) row.fill(false);\n\n    auto add_adj = [&](int a, int b) {\n        if (a == b) return;\n        adj[a][b] = adj[b][a] = true;\n    };\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (i + 1 < n) add_adj(c, st.g[i + 1][j]);\n            if (j + 1 < n) add_adj(c, st.g[i][j + 1]);\n            if (i == 0) add_adj(0, c);\n            if (i == n - 1) add_adj(0, c);\n            if (j == 0) add_adj(0, c);\n            if (j == n - 1) add_adj(0, c);\n        }\n    }\n\n    for (int u = 0; u <= m; u++) {\n        for (int v = u + 1; v <= m; v++) {\n            if (adj[u][v] != pb.targetAdj[u][v]) return false;\n        }\n    }\n\n    static const int dx[4] = {-1, 1, 0, 0};\n    static const int dy[4] = {0, 0, -1, 1};\n    auto in = [&](int x, int y) { return (0 <= x && x < n && 0 <= y && y < n); };\n\n    array<array<int, NMAX>, NMAX> vis{};\n    for (auto& row : vis) row.fill(0);\n    int token = 1;\n\n    // non-zero connectivity\n    for (int color = 1; color <= m; color++) {\n        int si = -1, sj = -1;\n        for (int i = 0; i < n && si == -1; i++) {\n            for (int j = 0; j < n; j++) {\n                if (st.g[i][j] == color) {\n                    si = i; sj = j;\n                    break;\n                }\n            }\n        }\n        if (si == -1) return false;\n\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        vis[si][sj] = token;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != color) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[color]) return false;\n    }\n\n    // zero connectivity through outside\n    if (realCnt[0] > 0) {\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                if (i != 0 && i != n - 1 && j != 0 && j != n - 1) continue;\n                if (st.g[i][j] != 0) continue;\n                if (vis[i][j] == token) continue;\n                vis[i][j] = token;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n            }\n        }\n        if (tail == 0) return false;\n\n        int reached = tail;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != 0) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem pb;\n    cin >> pb.n >> pb.m;\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) cin >> pb.initGrid[i][j];\n    }\n\n    pb.initCnt.fill(0);\n    for (auto& row : pb.initEdgeCnt) row.fill(0);\n    for (auto& row : pb.targetAdj) row.fill(false);\n    pb.canZero.fill(false);\n    pb.depth.fill(INF);\n    pb.deg.fill(0);\n\n    auto add_edge_count = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        pb.initEdgeCnt[a][b]++;\n    };\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            int c = pb.initGrid[i][j];\n            ++pb.initCnt[c];\n\n            if (i + 1 < pb.n) add_edge_count(c, pb.initGrid[i + 1][j]);\n            if (j + 1 < pb.n) add_edge_count(c, pb.initGrid[i][j + 1]);\n\n            if (i == 0) add_edge_count(0, c);\n            if (i == pb.n - 1) add_edge_count(0, c);\n            if (j == 0) add_edge_count(0, c);\n            if (j == pb.n - 1) add_edge_count(0, c);\n        }\n    }\n\n    for (int u = 0; u <= pb.m; u++) {\n        for (int v = u + 1; v <= pb.m; v++) {\n            if (pb.initEdgeCnt[u][v] > 0) {\n                pb.targetAdj[u][v] = pb.targetAdj[v][u] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= pb.m; c++) pb.canZero[c] = pb.targetAdj[0][c];\n\n    for (int c = 0; c <= pb.m; c++) {\n        int d = 0;\n        for (int to = 0; to <= pb.m; to++) {\n            if (c != to && pb.targetAdj[c][to]) ++d;\n        }\n        pb.deg[c] = d;\n    }\n\n    // depth from 0 on adjacency graph\n    queue<int> q;\n    pb.depth[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        for (int to = 0; to <= pb.m; to++) {\n            if (!pb.targetAdj[v][to]) continue;\n            if (pb.depth[to] != INF) continue;\n            pb.depth[to] = pb.depth[v] + 1;\n            q.push(to);\n        }\n    }\n    for (int c = 0; c <= pb.m; c++) {\n        if (pb.depth[c] == INF) pb.depth[c] = 50;\n    }\n    int maxDepth = 1;\n    for (int c = 1; c <= pb.m; c++) maxDepth = max(maxDepth, pb.depth[c]);\n\n    // random seed from input hash + time\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < pb.n; i++) for (int j = 0; j < pb.n; j++) {\n        h ^= (uint64_t)(pb.initGrid[i][j] + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));\n    }\n    h ^= (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n    auto start = Clock::now();\n    auto deadline = start + chrono::milliseconds(1920);\n    auto exploreEnd = start + chrono::milliseconds(1560);\n\n    State initState(&pb);\n    State best = initState, second = initState, third = initState;\n    int bestScore = best.zeroCount;\n    int secondScore = -1, thirdScore = -1;\n\n    auto update_elite = [&](const State& s) {\n        int sc = s.zeroCount;\n        auto lucky = [&]() { return ((rng() & 7u) == 0u); }; // 1/8\n        if (sc > bestScore || (sc == bestScore && lucky())) {\n            third = second;\n            thirdScore = secondScore;\n            second = best;\n            secondScore = bestScore;\n            best = s;\n            bestScore = sc;\n        } else if (sc > secondScore || (sc == secondScore && lucky())) {\n            third = second;\n            thirdScore = secondScore;\n            second = s;\n            secondScore = sc;\n        } else if (sc > thirdScore || (sc == thirdScore && lucky())) {\n            third = s;\n            thirdScore = sc;\n        }\n    };\n\n    vector<int> dummy(pb.m + 1, 0);\n\n    auto local_opt = [&](State& st, int rounds, int polish, Clock::time_point phaseDeadline, bool late) {\n        for (int r = 0; r < rounds; r++) {\n            if (Clock::now() >= phaseDeadline) return;\n\n            int mode = 0;\n            int roll = (int)(rng() % 100);\n\n            if (!late) {\n                if (roll < 24) mode = 0;\n                else if (roll < 36) mode = 1;\n                else if (roll < 44) mode = 2;\n                else if (roll < 62) mode = 3;\n                else if (roll < 70) mode = 4;\n                else if (roll < 80) mode = 5;\n                else if (roll < 90) mode = 6;\n                else mode = 7;\n            } else {\n                if (roll < 45) mode = 7;\n                else if (roll < 75) mode = 0;\n                else if (roll < 92) mode = 3;\n                else mode = 5;\n            }\n\n            auto value = build_value(pb, st, mode, rng, maxDepth);\n\n            int passes = 8, eqProb = 6, upProb = 0;\n            switch (mode) {\n                case 0: passes = 11; eqProb = 8; upProb = 0;  break;\n                case 1: passes = 7;  eqProb = 3; upProb = 14; break;\n                case 2: passes = 6;  eqProb = 4; upProb = 10; break;\n                case 3: passes = 10; eqProb = 8; upProb = 0;  break;\n                case 4: passes = 8;  eqProb = 6; upProb = 12; break;\n                case 5: passes = 8;  eqProb = 6; upProb = 8;  break;\n                case 6: passes = 8;  eqProb = 6; upProb = 8;  break;\n                case 7: passes = 9;  eqProb = 7; upProb = 4;  break;\n            }\n\n            st.improve(value, rng, phaseDeadline, passes, true, eqProb, upProb);\n\n            if (!late) {\n                if ((r & 1) == 0) st.random_shift_zero_moves(rng, phaseDeadline, 10 + (int)(rng() % 18));\n                if ((r % 3) == 0) st.random_neutral_moves(rng, phaseDeadline, 8 + (int)(rng() % 14));\n            }\n\n            st.greedy_delete_queue(rng, phaseDeadline, 4200 + polish * 1600);\n        }\n\n        st.random_shift_zero_moves(rng, phaseDeadline, 12 + (int)(rng() % 16));\n        st.greedy_delete_queue(rng, phaseDeadline, 8500 + polish * 2200);\n        st.improve(dummy, rng, phaseDeadline, 3 + polish, false, 0, 0);\n        st.greedy_delete_queue(rng, phaseDeadline, 5600 + polish * 1400);\n    };\n\n    update_elite(initState);\n\n    // Seeds\n    if (Clock::now() < exploreEnd) {\n        State s = initState;\n        local_opt(s, 6, 2, exploreEnd, false);\n        update_elite(s);\n    }\n    if (Clock::now() < exploreEnd) {\n        State s = initState;\n        s.random_neutral_moves(rng, exploreEnd, 70);\n        s.random_shift_zero_moves(rng, exploreEnd, 35);\n        local_opt(s, 5, 1, exploreEnd, false);\n        update_elite(s);\n    }\n    if (Clock::now() < exploreEnd) {\n        State s = initState;\n        s.random_expand_moves(rng, exploreEnd, 80);\n        s.random_shift_zero_moves(rng, exploreEnd, 30);\n        local_opt(s, 5, 1, exploreEnd, false);\n        update_elite(s);\n    }\n\n    int stagnation = 0;\n\n    while (Clock::now() < exploreEnd) {\n        int prevBest = bestScore;\n        State cand;\n\n        int pick = (int)(rng() % 100);\n        if (pick < 58) cand = best;\n        else if (pick < 82 && secondScore >= 0) cand = second;\n        else if (pick < 94 && thirdScore >= 0) cand = third;\n        else cand = initState;\n\n        int kickType = (int)(rng() % 100);\n        if (kickType < 45) {\n            cand.random_shift_zero_moves(rng, exploreEnd, 18 + (int)(rng() % 28));\n            cand.random_neutral_moves(rng, exploreEnd, 10 + (int)(rng() % 22));\n        } else if (kickType < 82) {\n            int ex = 28 + (int)(rng() % 60) + min(70, stagnation * 2);\n            cand.random_expand_moves(rng, exploreEnd, ex);\n            cand.random_shift_zero_moves(rng, exploreEnd, 14 + (int)(rng() % 24));\n            cand.random_neutral_moves(rng, exploreEnd, 10 + (int)(rng() % 18));\n        } else {\n            int ex = 85 + (int)(rng() % 140) + min(120, stagnation * 3);\n            cand.random_expand_moves(rng, exploreEnd, ex);\n            cand.random_shift_zero_moves(rng, exploreEnd, 30 + (int)(rng() % 40));\n            cand.random_neutral_moves(rng, exploreEnd, 24 + (int)(rng() % 34));\n        }\n\n        int rounds = 2 + (int)(rng() % 3);\n        int polish = 1;\n        if (stagnation > 10) { rounds++; polish = 2; }\n        if (stagnation > 18) rounds++;\n\n        local_opt(cand, rounds, polish, exploreEnd, false);\n        update_elite(cand);\n\n        if (bestScore > prevBest) stagnation = 0;\n        else stagnation++;\n\n        if (stagnation >= 20 && Clock::now() < exploreEnd) {\n            State alt = best;\n            alt.random_expand_moves(rng, exploreEnd, 170 + (int)(rng() % 140));\n            alt.random_shift_zero_moves(rng, exploreEnd, 70 + (int)(rng() % 60));\n            alt.random_neutral_moves(rng, exploreEnd, 60 + (int)(rng() % 50));\n            local_opt(alt, 5, 2, exploreEnd, false);\n\n            prevBest = bestScore;\n            update_elite(alt);\n            if (bestScore > prevBest) {\n                stagnation = 0;\n            } else {\n                State rst = initState;\n                local_opt(rst, 4, 1, exploreEnd, false);\n                prevBest = bestScore;\n                update_elite(rst);\n                if (bestScore > prevBest) stagnation = 0;\n                else stagnation = 10;\n            }\n        }\n    }\n\n    // Final polish stage (best only)\n    while (Clock::now() < deadline) {\n        auto v7 = build_value(pb, best, 7, rng, maxDepth);\n        best.improve(v7, rng, deadline, 5, true, 7, 0);\n\n        auto v0 = build_value(pb, best, 0, rng, maxDepth);\n        best.improve(v0, rng, deadline, 6, true, 8, 0);\n\n        best.random_shift_zero_moves(rng, deadline, 8);\n        best.greedy_delete_queue(rng, deadline, 7000);\n        best.improve(dummy, rng, deadline, 2, false, 0, 0);\n\n        bestScore = best.zeroCount;\n    }\n\n    State ans = best;\n    if (!validate_solution(ans)) {\n        if (secondScore >= 0 && validate_solution(second)) ans = second;\n        else if (thirdScore >= 0 && validate_solution(third)) ans = third;\n        else ans = initState;\n    }\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            if (j) cout << ' ';\n            cout << ans.g[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 = 0, D = 0, Q = 0;\n    int used = 0;\n    mt19937 rng;\n\n    // item-item comparison cache:\n    // 2: unknown, -1: a<b, 0: a=b, 1: a>b\n    vector<vector<int8_t>> cmp_cache;\n    vector<int> score_item; // wins-losses from fresh singleton comparisons\n\n    vector<double> harm;    // harmonic numbers\n\n    // current partition state\n    vector<int> assign;              // item -> bin\n    vector<vector<int>> bins;        // bin -> items\n    vector<double> bin_sum_est;      // estimated sum per bin\n\n    // estimated item info\n    vector<double> w_est;\n    vector<int> rank_pos;            // 0 = heaviest\n    double total_est = 0.0;\n\n    struct State {\n        vector<int> assign;\n        vector<vector<int>> bins;\n        vector<double> sum;\n    };\n\n    static int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 1, c = 0;\n        while (p < x) p <<= 1, ++c;\n        return c;\n    }\n\n    static int insertion_cost(int n) {\n        int c = 0;\n        for (int m = 1; m < n; ++m) c += ceil_log2_int(m + 1);\n        return c;\n    }\n\n    char ask_set(const vector<int>& L, const vector<int>& R) {\n        // judge requires both non-empty and disjoint\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n';\n        cout.flush();\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        if (s == \"-1\") exit(0);\n\n        ++used;\n        return s[0];\n    }\n\n    char ask_single_raw(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask_set(L, R);\n    }\n\n    // returns 1 if a>b, -1 if a<b, 0 equal\n    int cmp_item(int a, int b, bool update_score = true) {\n        int8_t v = cmp_cache[a][b];\n        if (v != 2) return (int)v;\n\n        char c = ask_single_raw(a, b);\n        int s = (c == '>') ? 1 : (c == '<' ? -1 : 0);\n\n        cmp_cache[a][b] = (int8_t)s;\n        cmp_cache[b][a] = (int8_t)(-s);\n\n        if (update_score) {\n            if (s > 0) { score_item[a]++; score_item[b]--; }\n            else if (s < 0) { score_item[a]--; score_item[b]++; }\n        }\n        return s;\n    }\n\n    vector<int> full_sort_items() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        shuffle(items.begin(), items.end(), rng);\n\n        vector<int> ord;\n        ord.reserve(N);\n\n        for (int x : items) {\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                int s = cmp_item(x, ord[mid], true); // x ? ord[mid]\n                if (s > 0) hi = mid;          // x heavier\n                else if (s < 0) lo = mid + 1; // x lighter\n                else { lo = mid; hi = mid; break; }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    vector<int> sort_group_exact(const vector<int>& g) {\n        vector<int> ord;\n        ord.reserve(g.size());\n        for (int x : g) {\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                int s = cmp_item(x, ord[mid], true);\n                if (s > 0) hi = mid;\n                else if (s < 0) lo = mid + 1;\n                else { lo = mid; hi = mid; break; }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    // Low-Q ranking: impact-prioritized partitioning + partial polishing.\n    vector<int> partial_rank_focus(int budget_end) {\n        vector<int> all(N);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n\n        vector<vector<int>> groups(1, all);\n        vector<char> exact(1, 0);\n\n        // Stage 1: split groups by pivot where impact is high (heavy-rank + size).\n        while (used < budget_end) {\n            int rem = budget_end - used;\n            int best_idx = -1;\n            double best_key = -1.0;\n\n            int pref = 0; // start rank index of group\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m >= 2 && m - 1 <= rem) {\n                    double rank_weight = harm[N] - harm[pref];\n                    double key = m * (rank_weight + 0.05);\n                    if (key > best_key) {\n                        best_key = key;\n                        best_idx = g;\n                    }\n                }\n                pref += m;\n            }\n            if (best_idx == -1) break;\n\n            vector<int> cur = groups[best_idx];\n            int m = (int)cur.size();\n            int pv = cur[uniform_int_distribution<int>(0, m - 1)(rng)];\n\n            vector<int> heavy, equalv, light;\n            equalv.push_back(pv);\n\n            for (int v : cur) {\n                if (v == pv) continue;\n                int s = cmp_item(v, pv, true);\n                if (s > 0) heavy.push_back(v);\n                else if (s < 0) light.push_back(v);\n                else equalv.push_back(v);\n            }\n\n            vector<vector<int>> repl;\n            vector<char> repl_exact;\n            if (!heavy.empty()) { repl.push_back(move(heavy)); repl_exact.push_back(0); }\n            if (!equalv.empty()) { repl.push_back(move(equalv)); repl_exact.push_back(0); }\n            if (!light.empty()) { repl.push_back(move(light)); repl_exact.push_back(0); }\n\n            groups.erase(groups.begin() + best_idx);\n            exact.erase(exact.begin() + best_idx);\n\n            groups.insert(groups.begin() + best_idx, repl.begin(), repl.end());\n            exact.insert(exact.begin() + best_idx, repl_exact.begin(), repl_exact.end());\n        }\n\n        // Stage 2: fully sort groups when affordable.\n        for (int g = 0; g < (int)groups.size(); ++g) {\n            int m = (int)groups[g].size();\n            if (m <= 1) { exact[g] = 1; continue; }\n            int need = insertion_cost(m);\n            if (used + need <= budget_end) {\n                groups[g] = sort_group_exact(groups[g]);\n                exact[g] = 1;\n            }\n        }\n\n        // Stage 3: leftover budget on unsorted impactful groups.\n        int stale = 0;\n        while (used < budget_end && stale < 3000) {\n            int best_idx = -1;\n            double best_key = -1.0;\n\n            int pref = 0;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (!exact[g] && m >= 2) {\n                    double rank_weight = harm[N] - harm[pref];\n                    double key = m * (rank_weight + 0.05);\n                    if (key > best_key) {\n                        best_key = key;\n                        best_idx = g;\n                    }\n                }\n                pref += m;\n            }\n            if (best_idx == -1) break;\n\n            auto& grp = groups[best_idx];\n            int m = (int)grp.size();\n            int a = grp[uniform_int_distribution<int>(0, m - 1)(rng)];\n            int b = a;\n            for (int t = 0; t < 8 && b == a; ++t) {\n                b = grp[uniform_int_distribution<int>(0, m - 1)(rng)];\n            }\n            if (a == b) { ++stale; continue; }\n\n            int before = used;\n            cmp_item(a, b, true);\n            if (used == before) ++stale;\n            else stale = 0;\n        }\n\n        // Flatten\n        vector<int> ord;\n        ord.reserve(N);\n        for (int g = 0; g < (int)groups.size(); ++g) {\n            if (exact[g]) {\n                for (int x : groups[g]) ord.push_back(x);\n            } else {\n                auto tmp = groups[g];\n                stable_sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n                    if (score_item[a] != score_item[b]) return score_item[a] > score_item[b];\n                    return a < b;\n                });\n                for (int x : tmp) ord.push_back(x);\n            }\n        }\n        return ord;\n    }\n\n    void build_est_from_order(const vector<int>& order) {\n        w_est.assign(N, 1.0);\n        rank_pos.assign(N, N - 1);\n\n        total_est = 0.0;\n        for (int pos = 0; pos < N; ++pos) {\n            int id = order[pos];\n            rank_pos[id] = pos;\n            // Exponential order-stat shape\n            double w = harm[N] - harm[pos];\n            w_est[id] = w;\n            total_est += w;\n        }\n    }\n\n    void init_lpt(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        for (int id : order) {\n            int best = 0;\n            for (int b = 1; b < D; ++b) {\n                if (bin_sum_est[b] < bin_sum_est[best] - 1e-12) best = b;\n                else if (abs(bin_sum_est[b] - bin_sum_est[best]) <= 1e-12 &&\n                         bins[b].size() < bins[best].size()) best = b;\n            }\n            assign[id] = best;\n            bins[best].push_back(id);\n            bin_sum_est[best] += w_est[id];\n        }\n    }\n\n    void init_snake(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        int per = max(1, 2 * D - 2);\n        for (int i = 0; i < N; ++i) {\n            int t = i % per;\n            int b = (t < D ? t : per - t);\n\n            int id = order[i];\n            assign[id] = b;\n            bins[b].push_back(id);\n            bin_sum_est[b] += w_est[id];\n        }\n    }\n\n    void move_item_g(int item, int to) {\n        int from = assign[item];\n        if (from == to) return;\n\n        auto& vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); ++i) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n\n        bins[to].push_back(item);\n        assign[item] = to;\n\n        bin_sum_est[from] -= w_est[item];\n        bin_sum_est[to] += w_est[item];\n    }\n\n    void swap_item_g(int i, int j) {\n        int a = assign[i], b = assign[j];\n        if (a == b) return;\n\n        auto& va = bins[a];\n        auto& vb = bins[b];\n\n        for (int& x : va) if (x == i) { x = j; break; }\n        for (int& x : vb) if (x == j) { x = i; break; }\n\n        assign[i] = b;\n        assign[j] = a;\n\n        double wi = w_est[i], wj = w_est[j];\n        bin_sum_est[a] += wj - wi;\n        bin_sum_est[b] += wi - wj;\n    }\n\n    inline double sq(double x) const { return x * x; }\n\n    double obj_sse() const {\n        double mean = total_est / D;\n        double s = 0.0;\n        for (int b = 0; b < D; ++b) s += sq(bin_sum_est[b] - mean);\n        return s;\n    }\n\n    void local_search_est(int iter_limit, bool allow_swap) {\n        double mean = total_est / D;\n\n        for (int iter = 0; iter < iter_limit; ++iter) {\n            double best_delta = -1e-12;\n            int type = 0;\n            int bi = -1, bj = -1, bt = -1;\n\n            // move\n            for (int i = 0; i < N; ++i) {\n                int a = assign[i];\n                if ((int)bins[a].size() <= 1) continue;\n                double wi = w_est[i];\n\n                for (int b = 0; b < D; ++b) {\n                    if (b == a) continue;\n                    double delta =\n                        sq(bin_sum_est[a] - wi - mean) +\n                        sq(bin_sum_est[b] + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        type = 1;\n                        bi = i;\n                        bt = b;\n                    }\n                }\n            }\n\n            // swap\n            if (allow_swap) {\n                for (int i = 0; i < N; ++i) {\n                    for (int j = i + 1; j < N; ++j) {\n                        int a = assign[i], b = assign[j];\n                        if (a == b) continue;\n\n                        double wi = w_est[i], wj = w_est[j];\n                        double delta =\n                            sq(bin_sum_est[a] - wi + wj - mean) +\n                            sq(bin_sum_est[b] - wj + wi - mean) -\n                            sq(bin_sum_est[a] - mean) -\n                            sq(bin_sum_est[b] - mean);\n\n                        if (delta < best_delta) {\n                            best_delta = delta;\n                            type = 2;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n            }\n\n            if (type == 0) break;\n            if (type == 1) move_item_g(bi, bt);\n            else swap_item_g(bi, bj);\n        }\n    }\n\n    State capture() const {\n        return State{assign, bins, bin_sum_est};\n    }\n\n    void restore(const State& st) {\n        assign = st.assign;\n        bins = st.bins;\n        bin_sum_est = st.sum;\n    }\n\n    char cmp_bins(int a, int b) {\n        return ask_set(bins[a], bins[b]);\n    }\n\n    char cmp_after_move(int h, int l, int x) {\n        vector<int> L;\n        L.reserve((int)bins[h].size() - 1);\n        for (int v : bins[h]) if (v != x) L.push_back(v);\n\n        vector<int> R = bins[l];\n        R.push_back(x);\n\n        return ask_set(L, R);\n    }\n\n    void reinsert_bin(vector<int>& ord, int b) {\n        int lo = 0, hi = (int)ord.size();\n        while (lo < hi && used < Q) {\n            int mid = (lo + hi) / 2;\n            char c = cmp_bins(b, ord[mid]);\n            if (c == '>') hi = mid;   // b heavier\n            else lo = mid + 1;\n        }\n        ord.insert(ord.begin() + lo, b);\n    }\n\n    void refine_high() {\n        int rem = Q - used;\n        int need = insertion_cost(D) + 8;\n        if (rem < need) return;\n\n        vector<int> ord;\n        ord.reserve(D);\n        for (int b = 0; b < D; ++b) {\n            if (used >= Q) return;\n            reinsert_bin(ord, b);\n        }\n\n        int guard = 0;\n        while (used < Q && guard < 10000) {\n            ++guard;\n\n            int h = -1;\n            for (int id : ord) {\n                if ((int)bins[id].size() > 1) {\n                    h = id;\n                    break;\n                }\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int i = (int)ord.size() - 1; i >= 0; --i) {\n                if (ord[i] != h) { l = ord[i]; break; }\n            }\n            if (l == -1) break;\n\n            char base = cmp_bins(h, l);\n            if (base == '=') break;\n            if (base == '<') swap(h, l);\n\n            if ((int)bins[h].size() <= 1) break;\n\n            vector<int> cand = bins[h];\n            // light -> heavy for binary search\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (rank_pos[a] != rank_pos[b]) return rank_pos[a] > rank_pos[b];\n                return a < b;\n            });\n\n            int m = (int)cand.size();\n            int lo = -1, hi = m; // lo: too light ('>'), hi: heavy enough ('<'/'=')\n\n            while (hi - lo > 1 && used < Q) {\n                int mid = (lo + hi) / 2;\n                int x = cand[mid];\n                char c = cmp_after_move(h, l, x);\n                if (c == '>') lo = mid;\n                else hi = mid;\n            }\n\n            if (lo == -1 && hi == m) break;\n\n            int chosen;\n            if (lo == -1) chosen = cand[hi];\n            else if (hi == m) chosen = cand[lo];\n            else {\n                double diff = bin_sum_est[h] - bin_sum_est[l];\n                double e1 = fabs(diff - 2.0 * w_est[cand[lo]]);\n                double e2 = fabs(diff - 2.0 * w_est[cand[hi]]);\n                chosen = (e1 <= e2 ? cand[lo] : cand[hi]);\n            }\n\n            move_item_g(chosen, l);\n\n            auto it = find(ord.begin(), ord.end(), h);\n            if (it != ord.end()) ord.erase(it);\n            it = find(ord.begin(), ord.end(), l);\n            if (it != ord.end()) ord.erase(it);\n\n            if (used >= Q) break;\n            reinsert_bin(ord, h);\n            if (used >= Q) break;\n            reinsert_bin(ord, l);\n        }\n    }\n\n    void refine_simple(int max_steps) {\n        int stall = 0;\n        int last_item = -1, last_from = -1, last_to = -1;\n\n        for (int step = 0; step < max_steps && used < Q && stall < 2 * D + 6; ++step) {\n            int h = -1;\n            for (int b = 0; b < D; ++b) {\n                if ((int)bins[b].size() <= 1) continue;\n                if (h == -1 || bin_sum_est[b] > bin_sum_est[h]) h = b;\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int b = 0; b < D; ++b) {\n                if (b == h) continue;\n                if (l == -1 || bin_sum_est[b] < bin_sum_est[l]) l = b;\n            }\n            if (l == -1) break;\n\n            char c = cmp_bins(h, l);\n            if (c == '=') {\n                double avg = 0.5 * (bin_sum_est[h] + bin_sum_est[l]);\n                bin_sum_est[h] = avg;\n                bin_sum_est[l] = avg;\n                ++stall;\n                continue;\n            }\n            if (c == '<') {\n                swap(h, l);\n                if (bin_sum_est[h] < bin_sum_est[l]) {\n                    swap(bin_sum_est[h], bin_sum_est[l]);\n                }\n            }\n\n            if ((int)bins[h].size() <= 1) {\n                ++stall;\n                continue;\n            }\n\n            double diff = max(0.0, bin_sum_est[h] - bin_sum_est[l]);\n            int chosen = -1;\n            double best = 1e100;\n\n            for (int x : bins[h]) {\n                if (x == last_item && h == last_to && l == last_from) continue;\n                double v = fabs(diff - 2.0 * w_est[x]);\n                if (v < best) {\n                    best = v;\n                    chosen = x;\n                }\n            }\n            if (chosen == -1) {\n                for (int x : bins[h]) {\n                    if (chosen == -1 || w_est[x] < w_est[chosen]) chosen = x;\n                }\n            }\n            if (chosen == -1) {\n                ++stall;\n                continue;\n            }\n\n            move_item_g(chosen, l);\n            last_item = chosen;\n            last_from = h;\n            last_to = l;\n            stall = 0;\n        }\n    }\n\n    void fill_dummy() {\n        while (used < Q) {\n            ask_single_raw(0, 1);\n        }\n    }\n\n    void solve() {\n        if (!(cin >> N >> D >> Q)) return;\n\n        uint64_t seed = 0x9e3779b97f4a7c15ULL;\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)D * 9176ULL;\n        seed ^= (uint64_t)Q * 1315423911ULL;\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n\n        cmp_cache.assign(N, vector<int8_t>(N, 2));\n        for (int i = 0; i < N; ++i) cmp_cache[i][i] = 0;\n        score_item.assign(N, 0);\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        int full_cost = insertion_cost(N);\n        int rank_start = used;\n\n        vector<int> order;\n        if (Q >= full_cost) {\n            order = full_sort_items();\n        } else {\n            int reserve = min(max(4, D / 2), max(0, Q - (int)(1.7 * N)));\n            reserve = min(reserve, Q / 6);\n            int budget_end = Q - reserve;\n            if (budget_end < used) budget_end = used;\n\n            order = partial_rank_focus(budget_end);\n        }\n\n        int rank_used = used - rank_start;\n\n        // sanitize permutation\n        {\n            vector<int> seen(N, 0), clean;\n            clean.reserve(N);\n            for (int x : order) {\n                if (0 <= x && x < N && !seen[x]) {\n                    seen[x] = 1;\n                    clean.push_back(x);\n                }\n            }\n            for (int i = 0; i < N; ++i) if (!seen[i]) clean.push_back(i);\n            order.swap(clean);\n        }\n\n        build_est_from_order(order);\n        double conf = min(1.0, (double)rank_used / max(1, full_cost));\n\n        // Multi-start init: LPT vs snake\n        int iter = 170 + (int)(90.0 * conf);\n        bool allow_swap = true;\n\n        State best_state;\n        double best_obj = 1e100;\n\n        init_lpt(order);\n        local_search_est(iter, allow_swap);\n        best_state = capture();\n        best_obj = obj_sse();\n\n        init_snake(order);\n        local_search_est(iter, allow_swap);\n        double obj2 = obj_sse();\n        if (obj2 < best_obj) {\n            best_obj = obj2;\n            best_state = capture();\n        }\n\n        restore(best_state);\n\n        int rem = Q - used;\n        if (rem > 0) {\n            if (rem >= insertion_cost(D) + 10 && conf > 0.82) {\n                refine_high();\n                if (used < Q) refine_simple(min(D, Q - used));\n            } else {\n                refine_simple(min(Q - used, 3 * D + 10));\n            }\n        }\n\n        fill_dummy();\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << assign[i];\n        }\n        cout << '\\n';\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 200;\nconstexpr int MAXM = 10;\nconstexpr long long INF64 = (1LL << 60);\n\nint N, M;\n\nstruct Params {\n    int w_cross;\n    int w_near;\n    int near_th;\n    int w_height;\n    int w_top;\n    int w_empty;\n    int w_boundary;\n\n    bool operator==(const Params& o) const {\n        return w_cross == o.w_cross &&\n               w_near == o.w_near &&\n               near_th == o.near_th &&\n               w_height == o.w_height &&\n               w_top == o.w_top &&\n               w_empty == o.w_empty &&\n               w_boundary == o.w_boundary;\n    }\n};\n\nstruct State {\n    int len[MAXM];\n    int box[MAXM][MAXN]; // bottom -> top\n    int stk[MAXN + 1];   // box value -> stack id, -1 if removed\n    int pos[MAXN + 1];   // index in stack\n};\n\nstruct SegInfo {\n    int total;\n    int bottom;\n    int pref[MAXN + 1]; // # in segment <= v\n};\n\nstruct Result {\n    long long energy = INF64;\n    vector<pair<int, int>> ops;\n    Params param{};\n};\n\nstruct Trial {\n    long long e;\n    Params p;\n};\n\ninline void move_suffix(State& st, int src, int start, int dst) {\n    int k = st.len[src] - start;\n    int base = st.len[dst];\n    for (int i = 0; i < k; ++i) {\n        int v = st.box[src][start + i];\n        st.box[dst][base + i] = v;\n        st.stk[v] = dst;\n        st.pos[v] = base + i;\n    }\n    st.len[dst] += k;\n    st.len[src] = start;\n}\n\ninline void remove_target(State& st, int x) {\n    int s = st.stk[x];\n    st.len[s]--;\n    st.stk[x] = -1;\n    st.pos[x] = -1;\n}\n\ninline SegInfo build_seg_info(const State& st, int src, int start) {\n    SegInfo sg{};\n    sg.total = st.len[src] - start;\n    sg.bottom = st.box[src][start];\n\n    int freq[MAXN + 1];\n    memset(freq, 0, sizeof(freq));\n    for (int i = start; i < st.len[src]; ++i) {\n        ++freq[st.box[src][i]];\n    }\n\n    sg.pref[0] = 0;\n    for (int v = 1; v <= N; ++v) {\n        sg.pref[v] = sg.pref[v - 1] + freq[v];\n    }\n    return sg;\n}\n\ninline long long score_dest(\n    const State& st, int dst, int x, const Params& p, const SegInfo& sg\n) {\n    long long cross = 0;\n    long long nearv = 0;\n\n    for (int j = 0; j < st.len[dst]; ++j) {\n        int z = st.box[dst][j];\n        int cnt = sg.total - sg.pref[z]; // # moved boxes > z\n        if (cnt <= 0) continue;\n        cross += cnt;\n\n        int dz = z - x;\n        if (dz <= p.near_th) {\n            nearv += 1LL * cnt * (p.near_th + 1 - dz);\n        }\n    }\n\n    long long sc = 0;\n    sc += 1LL * p.w_cross * cross;\n    sc += 1LL * p.w_near * nearv;\n    sc += 1LL * p.w_height * st.len[dst];\n\n    if (st.len[dst] == 0) {\n        sc -= p.w_empty;\n    } else {\n        int top = st.box[dst][st.len[dst] - 1];\n        sc -= 1LL * p.w_top * top;\n        if (sg.bottom > top) {\n            sc += 1LL * p.w_boundary * (sg.bottom - top);\n        }\n    }\n    return sc;\n}\n\ninline int choose_best_dest(\n    const State& st, int src, int start, int x, const Params& p\n) {\n    SegInfo sg = build_seg_info(st, src, start);\n\n    long long bestSc = INF64;\n    int bestD = -1;\n\n    for (int d = 0; d < M; ++d) {\n        if (d == src) continue;\n        long long sc = score_dest(st, d, x, p, sg);\n\n        if (sc < bestSc ||\n            (sc == bestSc && (bestD == -1 ||\n                              st.len[d] < st.len[bestD] ||\n                              (st.len[d] == st.len[bestD] && d < bestD)))) {\n            bestSc = sc;\n            bestD = d;\n        }\n    }\n    return bestD;\n}\n\ninline int rank_destinations(\n    const State& st, int src, int start, int x, const Params& p,\n    array<pair<long long, int>, MAXM>& cand\n) {\n    SegInfo sg = build_seg_info(st, src, start);\n    int cnt = 0;\n    for (int d = 0; d < M; ++d) {\n        if (d == src) continue;\n        cand[cnt++] = {score_dest(st, d, x, p, sg), d};\n    }\n\n    sort(cand.begin(), cand.begin() + cnt,\n         [&](const auto& a, const auto& b) {\n             if (a.first != b.first) return a.first < b.first;\n             if (st.len[a.second] != st.len[b.second]) {\n                 return st.len[a.second] < st.len[b.second];\n             }\n             return a.second < b.second;\n         });\n    return cnt;\n}\n\nlong long simulate_base(State& st, int nextX, const Params& p, long long cutoff) {\n    long long energy = 0;\n    for (int x = nextX; x <= N; ++x) {\n        int s = st.stk[x];\n        int pos = st.pos[x];\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int d = choose_best_dest(st, s, start, x, p);\n            move_suffix(st, s, start, d);\n            energy += k + 1;\n            if (energy > cutoff) return energy;\n        }\n        remove_target(st, x);\n    }\n    return energy;\n}\n\nlong long solve_run(\n    const State& init, const Params& p, int candK,\n    vector<pair<int, int>>* outOps\n) {\n    State st = init;\n    long long energy = 0;\n\n    if (outOps) {\n        outOps->clear();\n        outOps->reserve(700);\n    }\n\n    array<pair<long long, int>, MAXM> cand{};\n\n    for (int x = 1; x <= N; ++x) {\n        int s = st.stk[x];\n        int pos = st.pos[x];\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int chosenD = -1;\n\n            if (candK <= 1) {\n                chosenD = choose_best_dest(st, s, start, x, p);\n            } else {\n                int cnt = rank_destinations(st, s, start, x, p, cand);\n                int K = min(candK, cnt);\n\n                long long bestEst = INF64;\n                long long bestCheap = INF64;\n                int bestD = cand[0].second;\n\n                for (int ci = 0; ci < K; ++ci) {\n                    int d = cand[ci].second;\n                    long long cheap = cand[ci].first;\n\n                    State tmp = st;\n                    move_suffix(tmp, s, start, d);\n                    remove_target(tmp, x);\n\n                    long long cutoff = (bestEst >= INF64 / 4) ? INF64 : (bestEst - (k + 1));\n                    if (cutoff < 0) cutoff = 0;\n\n                    long long fut = simulate_base(tmp, x + 1, p, cutoff);\n                    long long est = (k + 1) + fut;\n\n                    if (est < bestEst ||\n                        (est == bestEst && cheap < bestCheap) ||\n                        (est == bestEst && cheap == bestCheap && d < bestD)) {\n                        bestEst = est;\n                        bestCheap = cheap;\n                        bestD = d;\n                    }\n                }\n                chosenD = bestD;\n            }\n\n            int vmove = st.box[s][start];\n            move_suffix(st, s, start, chosenD);\n            energy += k + 1;\n            if (outOps) outOps->push_back({vmove, chosenD + 1});\n        }\n\n        remove_target(st, x);\n        if (outOps) outOps->push_back({x, 0});\n    }\n\n    return energy;\n}\n\nvoid add_pool(vector<Trial>& pool, long long e, const Params& p, int lim) {\n    bool found = false;\n    for (auto& t : pool) {\n        if (t.p == p) {\n            if (e < t.e) t.e = e;\n            found = true;\n            break;\n        }\n    }\n    if (!found) pool.push_back({e, p});\n\n    sort(pool.begin(), pool.end(),\n         [](const Trial& a, const Trial& b) { return a.e < b.e; });\n\n    if ((int)pool.size() > lim) pool.resize(lim);\n}\n\nParams random_param(mt19937& rng) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n    Params p{};\n    p.w_cross = rnd(600, 1800);\n    p.w_near = rnd(0, 100);\n    p.near_th = rnd(8, 65);\n    p.w_height = rnd(-5, 12);\n    p.w_top = rnd(0, 12);\n    p.w_empty = rnd(0, 3800);\n    p.w_boundary = rnd(0, 80);\n    return p;\n}\n\nParams mutate_param(const Params& base, mt19937& rng, int strength) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    if (rnd(0, 99) < 10) return random_param(rng);\n\n    int s = max(1, strength);\n    Params p = base;\n    p.w_cross = clamp(base.w_cross + rnd(-130 * s, 130 * s), 450, 2200);\n    p.w_near = clamp(base.w_near + rnd(-10 * s, 10 * s), 0, 130);\n    p.near_th = clamp(base.near_th + rnd(-4 * s, 4 * s), 5, 75);\n    p.w_height = clamp(base.w_height + rnd(-2 * s, 2 * s), -8, 16);\n    p.w_top = clamp(base.w_top + rnd(-2 * s, 2 * s), 0, 16);\n    p.w_empty = clamp(base.w_empty + rnd(-220 * s, 220 * s), 0, 5000);\n    p.w_boundary = clamp(base.w_boundary + rnd(-6 * s, 6 * s), 0, 100);\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    State init{};\n\n    for (int i = 0; i < MAXM; ++i) init.len[i] = 0;\n    for (int v = 1; v <= MAXN; ++v) {\n        init.stk[v] = -1;\n        init.pos[v] = -1;\n    }\n\n    int h = N / M;\n    uint64_t seed = 1469598103934665603ULL;\n\n    for (int i = 0; i < M; ++i) {\n        init.len[i] = h;\n        for (int j = 0; j < h; ++j) {\n            int v;\n            cin >> v;\n            init.box[i][j] = v;\n            init.stk[v] = i;\n            init.pos[v] = j;\n\n            seed ^= (uint64_t)v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    uint64_t clk = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32) ^ clk));\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    vector<Params> presets = {\n        {1000, 10, 20, 1, 1,  800, 10},\n        {1000, 20, 24, 2, 1, 1200, 15},\n        {1050, 30, 28, 2, 2, 1500, 20},\n        {1100, 35, 32, 3, 2, 1700, 25},\n        { 900, 45, 20, 1, 3, 1300, 15},\n        {1200, 25, 40, 4, 1, 2000, 30},\n        { 950, 15, 18, 1, 2,  900,  8},\n        {1300, 20, 45, 5, 1, 2200, 35},\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    // Time plan\n    const double HARD = 1.80;\n    const double T1 = 0.55;\n    const double T2 = 1.35;\n\n    const int K_FAST = 1;\n    const int K_MID = 4;\n    const int K_FINAL = 7;\n    const int POOL_SZ = 24;\n\n    vector<Trial> pool;\n    Params bestFastP = presets[0];\n    long long bestFastE = INF64;\n\n    // Stage 1: fast coarse search (greedy base)\n    for (const auto& p : presets) {\n        if (elapsed() + 0.01 > T1) break;\n        long long e = solve_run(init, p, K_FAST, nullptr);\n        if (e < bestFastE) {\n            bestFastE = e;\n            bestFastP = p;\n        }\n        add_pool(pool, e, p, POOL_SZ);\n    }\n\n    if (pool.empty()) {\n        long long e = solve_run(init, bestFastP, K_FAST, nullptr);\n        add_pool(pool, e, bestFastP, POOL_SZ);\n    }\n\n    while (elapsed() + 0.01 < T1) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 55) {\n            base = bestFastP;\n        } else if (r < 90 && !pool.empty()) {\n            int idx = rnd(0, min((int)pool.size() - 1, 7));\n            base = pool[idx].p;\n        } else {\n            base = presets[rnd(0, (int)presets.size() - 1)];\n        }\n\n        Params cand = mutate_param(base, rng, 2);\n        long long e = solve_run(init, cand, K_FAST, nullptr);\n        if (e < bestFastE) {\n            bestFastE = e;\n            bestFastP = cand;\n        }\n        add_pool(pool, e, cand, POOL_SZ);\n    }\n\n    Result bestRes;\n    bestRes.energy = INF64;\n\n    auto run_record = [&](const Params& p, int k) {\n        vector<pair<int, int>> ops;\n        long long e = solve_run(init, p, k, &ops);\n        if (e < bestRes.energy ||\n            (e == bestRes.energy && (bestRes.ops.empty() || ops.size() < bestRes.ops.size()))) {\n            bestRes.energy = e;\n            bestRes.ops = move(ops);\n            bestRes.param = p;\n        }\n    };\n\n    // Stage 2 init: evaluate top coarse candidates with medium rollout\n    int initTry = min((int)pool.size(), 8);\n    for (int i = 0; i < initTry && elapsed() + 0.06 < T2; ++i) {\n        run_record(pool[i].p, K_MID);\n    }\n    for (const auto& p : presets) {\n        if (elapsed() + 0.06 > T2) break;\n        run_record(p, K_MID);\n    }\n\n    if (bestRes.energy >= INF64 / 2) {\n        run_record(bestFastP, K_FAST);\n    }\n\n    auto eval_and_update = [&](const Params& p, int k, double est, bool addToPool) {\n        if (elapsed() + est * 1.5 > HARD) return;\n        long long e = solve_run(init, p, k, nullptr);\n        if (addToPool) add_pool(pool, e, p, POOL_SZ);\n        if (e < bestRes.energy && elapsed() + est < HARD) {\n            run_record(p, k);\n        }\n    };\n\n    // Stage 2: medium refinement\n    while (elapsed() + 0.06 * 1.5 < T2) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 60) {\n            base = bestRes.param;\n        } else if (r < 90 && !pool.empty()) {\n            int idx = rnd(0, min((int)pool.size() - 1, 9));\n            base = pool[idx].p;\n        } else {\n            base = presets[rnd(0, (int)presets.size() - 1)];\n        }\n\n        Params cand = mutate_param(base, rng, 1);\n        eval_and_update(cand, K_MID, 0.06, true);\n    }\n\n    // Stage 3: stronger rollout polish\n    eval_and_update(bestRes.param, K_FINAL, 0.10, false);\n    eval_and_update(bestRes.param, 9, 0.13, false);\n\n    for (int i = 0; i < min((int)pool.size(), 6) && elapsed() + 0.10 * 1.5 < HARD; ++i) {\n        eval_and_update(pool[i].p, K_FINAL, 0.10, false);\n    }\n\n    while (elapsed() + 0.10 * 1.5 < HARD) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 75 || pool.empty()) {\n            base = bestRes.param;\n        } else {\n            int idx = rnd(0, min((int)pool.size() - 1, 9));\n            base = pool[idx].p;\n        }\n        Params cand = mutate_param(base, rng, 1);\n        eval_and_update(cand, K_FINAL, 0.10, false);\n    }\n\n    if (bestRes.ops.empty()) {\n        run_record(bestFastP, K_FAST);\n    }\n\n    for (auto [v, i] : bestRes.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Metric {\n    long long total = 0;\n    int L = 0;\n    bool valid = false;\n};\n\nclass Solver {\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void read_input() {\n        cin >> N;\n        hWall.resize(N - 1);\n        for (int i = 0; i < N - 1; i++) cin >> hWall[i];\n        vWall.resize(N);\n        for (int i = 0; i < N; i++) cin >> vWall[i];\n\n        V = N * N;\n        dirt.resize(V);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                cin >> dirt[i * N + j];\n            }\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        build_graph();\n        precompute_apsp();\n\n        logd.resize(V);\n        for (int i = 0; i < V; i++) logd[i] = log(1.0 + (double)dirt[i]);\n\n        firstVisit.assign(V, -1);\n        prevVisit.assign(V, -1);\n        tri.assign(V, 0LL);\n\n        string dfsRoute = build_dfs_route();\n        Metric dfsM = evaluate(dfsRoute);\n\n        string bestRoute = dfsRoute;\n        Metric bestM = dfsM;\n\n        const double T_INIT = 0.30;\n        const double T_GAP  = 1.00;\n        const double T_RAND = 1.75;\n        const double T_END  = 1.88;\n\n        // Initial multi-start\n        int trial = 0;\n        while (elapsed() < T_INIT) {\n            string r;\n            if (trial % 3 == 0) {\n                double a = 0.2 + rnd01() * 1.8;\n                double b = 0.4 + rnd01() * 1.8;\n                double g = rnd01() * 0.6;\n                r = build_random_route(a, b, g);\n            } else {\n                double wD = rnd01() * 2.0;\n                double wR = rnd01() * 1.0;\n                double nz = 0.2 + rnd01() * 1.2;\n                r = build_weighted_dfs(wD, wR, nz);\n            }\n\n            if (!r.empty()) {\n                Metric m = evaluate(r);\n                if (better(m, bestM)) {\n                    bestM = m;\n                    bestRoute = std::move(r);\n                }\n            }\n            trial++;\n        }\n\n        string curRoute = bestRoute;\n        Metric curM = bestM;\n\n        long long sumd = 0;\n        int maxd = 0;\n        for (int x : dirt) {\n            sumd += x;\n            maxd = max(maxd, x);\n        }\n        double avgd = (double)sumd / max(1, V);\n        double skew = maxd / max(1.0, avgd);\n\n        int maxLen = 32000;\n        if (skew > 4.0) maxLen = 42000;\n        if (skew > 7.0) maxLen = 52000;\n        if (V < 900) maxLen += 6000;\n        maxLen = min(maxLen, 90000);\n\n        // Deterministic improve\n        while (elapsed() < T_GAP) {\n            bool improved = false;\n            if (improve_gap_best(curRoute, curM, T_GAP, maxLen)) improved = true;\n            if (elapsed() < T_GAP && improve_shorten_batch(curRoute, curM, T_GAP)) improved = true;\n\n            if (improved && better(curM, bestM)) {\n                bestM = curM;\n                bestRoute = curRoute;\n            }\n            if (!improved) break;\n        }\n\n        // High-d candidates and near lists\n        vector<int> highIds(V);\n        iota(highIds.begin(), highIds.end(), 0);\n        sort(highIds.begin(), highIds.end(), [&](int a, int b) {\n            if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n            return a < b;\n        });\n        if ((int)highIds.size() > 500) highIds.resize(500);\n\n        vector<vector<int>> nearTargets(V);\n        const int NEAR_DIST = 10;\n        for (int a = 0; a < V; a++) {\n            for (int x : highIds) {\n                int dd = (int)distMat[a][x];\n                if (dd > 0 && dd <= NEAR_DIST) nearTargets[a].push_back(x);\n            }\n        }\n\n        vector<int> pos = decode_positions(curRoute);\n        if (pos.empty()) {\n            curRoute = bestRoute;\n            curM = bestM;\n            pos = decode_positions(curRoute);\n        }\n        if (pos.empty()) {\n            curRoute = dfsRoute;\n            curM = dfsM;\n            pos = decode_positions(curRoute);\n        }\n        vector<int> cnt = build_counts(pos);\n\n        // Random hill-climb (improvement only)\n        int fail = 0;\n        while (elapsed() < T_RAND) {\n            string cand;\n            bool ok = false;\n\n            int op = (int)(rng() % 100);\n            if (op < 45) {\n                ok = make_random_loop_insert(curRoute, pos, nearTargets, highIds, cand, maxLen);\n            } else if (op < 65) {\n                ok = make_random_edge_insert(curRoute, pos, highIds, cand, maxLen);\n            } else if (op < 83) {\n                ok = make_random_shortcut(curRoute, pos, cnt, cand);\n            } else {\n                ok = make_random_loop_remove(curRoute, pos, cnt, cand);\n            }\n\n            if (!ok) {\n                fail++;\n                continue;\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, curM)) {\n                curRoute.swap(cand);\n                curM = m;\n                if (better(curM, bestM)) {\n                    bestM = curM;\n                    bestRoute = curRoute;\n                }\n                pos = decode_positions(curRoute);\n                if (pos.empty()) break;\n                cnt = build_counts(pos);\n                fail = 0;\n            } else {\n                fail++;\n            }\n\n            if (fail > 220 && elapsed() < T_RAND) {\n                bool improved = false;\n                if (improve_gap_best(curRoute, curM, T_RAND, maxLen)) improved = true;\n                if (elapsed() < T_RAND && improve_shorten_batch(curRoute, curM, T_RAND)) improved = true;\n\n                if (improved) {\n                    if (better(curM, bestM)) {\n                        bestM = curM;\n                        bestRoute = curRoute;\n                    }\n                    pos = decode_positions(curRoute);\n                    if (pos.empty()) break;\n                    cnt = build_counts(pos);\n                }\n                fail = 0;\n            }\n        }\n\n        // Final polish\n        curRoute = bestRoute;\n        curM = bestM;\n        while (elapsed() < T_END) {\n            bool improved = false;\n            if (improve_shorten_batch(curRoute, curM, T_END)) improved = true;\n            if (elapsed() < T_END && improve_gap_best(curRoute, curM, T_END, maxLen)) improved = true;\n\n            if (improved) {\n                if (better(curM, bestM)) {\n                    bestM = curM;\n                    bestRoute = curRoute;\n                }\n            } else {\n                break;\n            }\n        }\n\n        Metric fin = evaluate(bestRoute);\n        if (!fin.valid || (int)bestRoute.size() > 100000) {\n            bestRoute = dfsRoute;\n        }\n        cout << bestRoute << '\\n';\n    }\n\nprivate:\n    int N = 0, V = 0;\n    vector<string> hWall, vWall;\n    vector<int> dirt;\n    vector<double> logd;\n\n    vector<int> row, col;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> nxtMove; // U D L R\n\n    vector<vector<int16_t>> distMat, nextHop;\n    vector<int> dist0;\n\n    vector<int> firstVisit, prevVisit;\n    vector<long long> tri;\n\n    int dirMap[256]{};\n\n    mt19937_64 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    double rnd01() {\n        return (rng() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    void build_graph() {\n        fill(begin(dirMap), end(dirMap), -1);\n        dirMap[(unsigned char)'U'] = 0;\n        dirMap[(unsigned char)'D'] = 1;\n        dirMap[(unsigned char)'L'] = 2;\n        dirMap[(unsigned char)'R'] = 3;\n\n        row.resize(V);\n        col.resize(V);\n        adj.assign(V, {});\n        nxtMove.assign(V, array<int, 4>{-1, -1, -1, -1});\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                row[id] = i;\n                col[id] = j;\n\n                if (i > 0 && hWall[i - 1][j] == '0') {\n                    int to = (i - 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][0] = to;\n                }\n                if (i + 1 < N && hWall[i][j] == '0') {\n                    int to = (i + 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][1] = to;\n                }\n                if (j > 0 && vWall[i][j - 1] == '0') {\n                    int to = i * N + (j - 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][2] = to;\n                }\n                if (j + 1 < N && vWall[i][j] == '0') {\n                    int to = i * N + (j + 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][3] = to;\n                }\n            }\n        }\n    }\n\n    void precompute_apsp() {\n        const int16_t INF = 30000;\n        distMat.assign(V, vector<int16_t>(V, INF));\n        nextHop.assign(V, vector<int16_t>(V, -1));\n\n        vector<int> q(V);\n\n        for (int s = 0; s < V; s++) {\n            auto &ds = distMat[s];\n            auto &ns = nextHop[s];\n\n            fill(ds.begin(), ds.end(), INF);\n            fill(ns.begin(), ns.end(), -1);\n\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            ds[s] = 0;\n            ns[s] = s;\n\n            while (head < tail) {\n                int u = q[head++];\n                for (int v : adj[u]) {\n                    if (ds[v] != INF) continue;\n                    ds[v] = ds[u] + 1;\n                    ns[v] = (u == s ? v : ns[u]);\n                    q[tail++] = v;\n                }\n            }\n        }\n\n        dist0.resize(V);\n        for (int i = 0; i < V; i++) dist0[i] = (int)distMat[0][i];\n    }\n\n    char dir_between(int u, int v) const {\n        if (row[v] == row[u] - 1) return 'U';\n        if (row[v] == row[u] + 1) return 'D';\n        if (col[v] == col[u] - 1) return 'L';\n        return 'R';\n    }\n\n    char opposite(char c) const {\n        if (c == 'U') return 'D';\n        if (c == 'D') return 'U';\n        if (c == 'L') return 'R';\n        return 'L';\n    }\n\n    Metric evaluate(const string &route) {\n        int L = (int)route.size();\n        if (L <= 0 || L > 100000) return Metric{0, L, false};\n\n        fill(firstVisit.begin(), firstVisit.end(), -1);\n        fill(prevVisit.begin(), prevVisit.end(), -1);\n        fill(tri.begin(), tri.end(), 0LL);\n\n        int cur = 0;\n        for (int t = 1; t <= L; t++) {\n            int d = dirMap[(unsigned char)route[t - 1]];\n            if (d < 0) return Metric{0, L, false};\n\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return Metric{0, L, false};\n\n            cur = nx;\n            if (prevVisit[cur] != -1) {\n                long long delta = t - prevVisit[cur];\n                tri[cur] += delta * (delta - 1) / 2;\n            } else {\n                firstVisit[cur] = t;\n            }\n            prevVisit[cur] = t;\n        }\n\n        if (cur != 0) return Metric{0, L, false};\n\n        long long total = 0;\n        for (int v = 0; v < V; v++) {\n            if (prevVisit[v] == -1) return Metric{0, L, false};\n            long long delta = (long long)firstVisit[v] + L - prevVisit[v];\n            tri[v] += delta * (delta - 1) / 2;\n            total += tri[v] * (long long)dirt[v];\n        }\n\n        return Metric{total, L, true};\n    }\n\n    bool better(const Metric &a, const Metric &b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        __int128 lhs = (__int128)a.total * b.L;\n        __int128 rhs = (__int128)b.total * a.L;\n        if (lhs != rhs) return lhs < rhs;\n        return a.L < b.L;\n    }\n\n    vector<int> decode_positions(const string &route) const {\n        int L = (int)route.size();\n        vector<int> pos(L + 1);\n        int cur = 0;\n        pos[0] = 0;\n\n        for (int i = 0; i < L; i++) {\n            int d = dirMap[(unsigned char)route[i]];\n            if (d < 0) return {};\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return {};\n            cur = nx;\n            pos[i + 1] = cur;\n        }\n        return pos;\n    }\n\n    vector<int> build_counts(const vector<int> &pos) const {\n        vector<int> cnt(V, 0);\n        for (int i = 1; i < (int)pos.size(); i++) cnt[pos[i]]++;\n        return cnt;\n    }\n\n    string path_between(int a, int b) const {\n        if (a == b) return \"\";\n        string p;\n        int u = a;\n        int guard = 0;\n        while (u != b) {\n            int v = (int)nextHop[u][b];\n            if (v < 0 || v == u) return \"\";\n            p.push_back(dir_between(u, v));\n            u = v;\n            if (++guard > 500000) return \"\";\n        }\n        return p;\n    }\n\n    string roundtrip_detour(int a, int target) const {\n        if (a == target) return \"\";\n        string fwd = path_between(a, target);\n        if (fwd.empty()) return \"\";\n        string det = fwd;\n        for (int i = (int)fwd.size() - 1; i >= 0; i--) det.push_back(opposite(fwd[i]));\n        return det;\n    }\n\n    string insert_detour(const string &route, int t, const string &det) const {\n        string out;\n        out.reserve(route.size() + det.size());\n        out.append(route, 0, t);\n        out += det;\n        out.append(route, t, route.size() - t);\n        return out;\n    }\n\n    string remove_segment(const string &route, int l, int len) const {\n        string out;\n        out.reserve(route.size() - len);\n        out.append(route, 0, l);\n        out.append(route, l + len, route.size() - (l + len));\n        return out;\n    }\n\n    string replace_segment(const string &route, int l, int r, const string &rep) const {\n        string out;\n        out.reserve(route.size() - (r - l) + rep.size());\n        out.append(route, 0, l);\n        out += rep;\n        out.append(route, r, route.size() - r);\n        return out;\n    }\n\n    string build_dfs_route() {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            vector<int> nbs = adj[u];\n            sort(nbs.begin(), nbs.end(), [&](int a, int b) {\n                if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n                return a < b;\n            });\n\n            for (int v : nbs) {\n                if (vis[v]) continue;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_weighted_dfs(double wD, double wR, double noise) {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(adj[u].size());\n            for (int v : adj[u]) {\n                if (vis[v]) continue;\n                double s = wD * logd[v] - wR * dist0[v] + noise * rnd01();\n                cand.push_back({s, v});\n            }\n\n            sort(cand.begin(), cand.end(), [](const auto &x, const auto &y) {\n                return x.first > y.first;\n            });\n\n            for (auto &kv : cand) {\n                int v = kv.second;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_random_route(double alpha, double beta, double gamma) {\n        vector<char> vis(V, 0);\n        vis[0] = 1;\n        int rem = V - 1;\n\n        int cur = 0;\n        string route;\n        route.reserve(V * 3);\n\n        while (rem > 0) {\n            if ((int)route.size() > 90000) return \"\";\n\n            int bestN = -1;\n            double bestS = -1e100;\n\n            for (int nb : adj[cur]) {\n                if (vis[nb]) continue;\n                int onward = 0;\n                for (int z : adj[nb]) if (!vis[z]) onward++;\n                double s = alpha * logd[nb] - beta * onward + rnd01() * 0.02;\n                if (s > bestS) {\n                    bestS = s;\n                    bestN = nb;\n                }\n            }\n\n            if (bestN != -1) {\n                route.push_back(dir_between(cur, bestN));\n                cur = bestN;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                continue;\n            }\n\n            int target = -1;\n            double bestV = 1e100;\n            for (int v = 0; v < V; v++) {\n                if (vis[v]) continue;\n                int dd = (int)distMat[cur][v];\n                double val = (double)dd - gamma * logd[v] + rnd01() * 0.02;\n                if (val < bestV) {\n                    bestV = val;\n                    target = v;\n                }\n            }\n            if (target < 0) return \"\";\n\n            while (cur != target) {\n                int nx = (int)nextHop[cur][target];\n                if (nx < 0 || nx == cur) return \"\";\n                route.push_back(dir_between(cur, nx));\n                cur = nx;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                if ((int)route.size() > 90000) return \"\";\n            }\n        }\n\n        while (cur != 0) {\n            int nx = (int)nextHop[cur][0];\n            if (nx < 0 || nx == cur) return \"\";\n            route.push_back(dir_between(cur, nx));\n            cur = nx;\n            if ((int)route.size() > 90000) return \"\";\n        }\n\n        return route;\n    }\n\n    struct InsCand {\n        double est;\n        int type; // 0: loop insert, 1: edge replacement via target\n        int t;\n        int v;\n    };\n\n    bool improve_gap_best(string &route, Metric &curM, double timeLimit, int maxLen) {\n        int L = (int)route.size();\n        if (L <= 0 || L >= maxLen) return false;\n\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n\n        vector<int> first(V, -1), last(V, -1), maxGap(V, 0), gapStart(V, 0);\n\n        for (int t = 1; t <= L; t++) {\n            int v = pos[t];\n            if (first[v] == -1) {\n                first[v] = last[v] = t;\n            } else {\n                int g = t - last[v];\n                if (g > maxGap[v]) {\n                    maxGap[v] = g;\n                    gapStart[v] = last[v];\n                }\n                last[v] = t;\n            }\n        }\n        for (int v = 0; v < V; v++) {\n            int g = first[v] + L - last[v];\n            if (g > maxGap[v]) {\n                maxGap[v] = g;\n                gapStart[v] = last[v];\n            }\n        }\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(V);\n        for (int v = 0; v < V; v++) {\n            if (maxGap[v] <= 2) continue;\n            long long g = maxGap[v];\n            long long pot = 1LL * dirt[v] * g * g;\n            ord.push_back({pot, v});\n        }\n        if (ord.empty()) return false;\n\n        sort(ord.begin(), ord.end(), greater<pair<long long, int>>());\n        int M = min((int)ord.size(), 220);\n\n        vector<InsCand> cands;\n        cands.reserve(M * 16);\n\n        auto push_off = [&](vector<int> &offs, int g, int x) {\n            if (x > 0 && x < g) offs.push_back(x);\n        };\n\n        for (int i = 0; i < M; i++) {\n            if (elapsed() >= timeLimit) break;\n\n            int v = ord[i].second;\n            int g = maxGap[v];\n            int s = gapStart[v];\n            if (g <= 2) continue;\n\n            vector<int> offs;\n            offs.reserve(12);\n\n            push_off(offs, g, g / 4);\n            push_off(offs, g, g / 3);\n            push_off(offs, g, g / 2);\n            push_off(offs, g, (2 * g) / 3);\n            push_off(offs, g, (3 * g) / 4);\n\n            int step = max(1, g / 16);\n            int bestOff = -1;\n            int bestScore = INT_MAX;\n\n            for (int off = 1; off < g; off += step) {\n                int t = (s + off) % L;\n                int a = pos[t];\n                int dd = (int)distMat[a][v];\n                int bal = abs(2 * off - g);\n                int score = dd * 4 + bal / 8;\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestOff = off;\n                }\n            }\n            push_off(offs, g, bestOff);\n            push_off(offs, g, g / 2 - step);\n            push_off(offs, g, g / 2 + step);\n\n            sort(offs.begin(), offs.end());\n            offs.erase(unique(offs.begin(), offs.end()), offs.end());\n\n            long long oldTerm = 1LL * g * (g - 1) / 2;\n\n            for (int off : offs) {\n                int t = (s + off) % L;\n                int a = pos[t];\n\n                // Type 0: roundtrip loop insertion\n                int dd = (int)distMat[a][v];\n                if (dd > 0) {\n                    int add = 2 * dd;\n                    if (L + add <= maxLen) {\n                        long long g1 = (long long)off + dd;\n                        long long g2 = (long long)g - off + dd;\n                        long long newTerm = g1 * (g1 - 1) / 2 + g2 * (g2 - 1) / 2;\n                        long long gain = 1LL * dirt[v] * (oldTerm - newTerm);\n                        if (gain > 0) {\n                            double est = (double)gain / (add + 1.0);\n                            cands.push_back({est, 0, t, v});\n                        }\n                    }\n                }\n\n                // Type 1: replace edge (t->t+1) by path through v\n                int u = pos[t];\n                int w = pos[t + 1];\n                int d1 = (int)distMat[u][v];\n                int d2 = (int)distMat[v][w];\n                int via = d1 + d2;\n                int add = via - 1;\n\n                if (add > 0 && via <= 90 && L + add <= maxLen) {\n                    long long g1 = (long long)off + d1;\n                    long long g2 = (long long)g - off + d2 - 1;\n                    if (g1 > 0 && g2 > 0) {\n                        long long newTerm = g1 * (g1 - 1) / 2 + g2 * (g2 - 1) / 2;\n                        long long gain = 1LL * dirt[v] * (oldTerm - newTerm);\n                        if (gain > 0) {\n                            double est = 1.08 * (double)gain / (add + 1.0);\n                            cands.push_back({est, 1, t, v});\n                        }\n                    }\n                }\n            }\n        }\n\n        if (cands.empty()) return false;\n\n        sort(cands.begin(), cands.end(), [](const InsCand &a, const InsCand &b) {\n            return a.est > b.est;\n        });\n\n        int evalLim = (L < 8000 ? 100 : (L < 20000 ? 70 : 45));\n        if ((int)cands.size() > evalLim) cands.resize(evalLim);\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (const auto &c : cands) {\n            if (elapsed() >= timeLimit) break;\n\n            string cand;\n            if (c.type == 0) {\n                string det = roundtrip_detour(pos[c.t], c.v);\n                if (det.empty()) continue;\n                cand = insert_detour(route, c.t, det);\n            } else {\n                int u = pos[c.t];\n                int w = pos[c.t + 1];\n                string p1 = path_between(u, c.v);\n                string p2 = path_between(c.v, w);\n                if ((int)distMat[u][c.v] > 0 && p1.empty()) continue;\n                if ((int)distMat[c.v][w] > 0 && p2.empty()) continue;\n                string rep = p1 + p2;\n                if ((int)rep.size() <= 1) continue;\n                cand = replace_segment(route, c.t, c.t + 1, rep);\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\n    }\n\n    static void add_delta_small(vector<int> &ids, vector<int> &delta, int v, int add) {\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (ids[i] == v) {\n                delta[i] += add;\n                return;\n            }\n        }\n        ids.push_back(v);\n        delta.push_back(add);\n    }\n\n    bool can_remove_closed(const vector<int> &pos, const vector<int> &cnt, int l, int r) const {\n        vector<int> ids, delta;\n        ids.reserve(r - l + 2);\n        delta.reserve(r - l + 2);\n\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool can_replace_segment(const vector<int> &pos, const vector<int> &cnt, int l, int r, const string &rep) const {\n        vector<int> ids, delta;\n        ids.reserve((r - l) + (int)rep.size() + 4);\n        delta.reserve((r - l) + (int)rep.size() + 4);\n\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n\n        int cur = pos[l];\n        for (char c : rep) {\n            int d = dirMap[(unsigned char)c];\n            if (d < 0) return false;\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return false;\n            cur = nx;\n            add_delta_small(ids, delta, cur, +1);\n        }\n        if (cur != pos[r]) return false;\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool make_random_loop_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<vector<int>> &nearTargets,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L >= maxLen) return false;\n\n        int t = (int)(rng() % (L + 1));\n        int a = pos[t];\n\n        int chosen = -1;\n        double bestVal = -1e100;\n\n        const auto &lst = nearTargets[a];\n        if (!lst.empty()) {\n            int sample = min(12, (int)lst.size());\n            for (int i = 0; i < sample; i++) {\n                int x = lst[(int)(rng() % lst.size())];\n                int dd = (int)distMat[a][x];\n                if (dd <= 0) continue;\n                int add = 2 * dd;\n                if (L + add > maxLen) continue;\n                double val = (double)dirt[x] / add + rnd01() * 0.02;\n                if (val > bestVal) {\n                    bestVal = val;\n                    chosen = x;\n                }\n            }\n        }\n\n        if (chosen < 0 && !highIds.empty()) {\n            int H = (int)highIds.size();\n            for (int it = 0; it < 24; it++) {\n                int idx = (int)(pow(rnd01(), 1.7) * H);\n                if (idx >= H) idx = H - 1;\n                int x = highIds[idx];\n                int dd = (int)distMat[a][x];\n                if (dd <= 0 || dd > 20) continue;\n                int add = 2 * dd;\n                if (L + add > maxLen) continue;\n                double val = (double)dirt[x] / add + rnd01() * 0.02;\n                if (val > bestVal) {\n                    bestVal = val;\n                    chosen = x;\n                }\n            }\n        }\n\n        if (chosen < 0) return false;\n\n        string det = roundtrip_detour(a, chosen);\n        if (det.empty()) return false;\n        cand = insert_detour(route, t, det);\n        return true;\n    }\n\n    bool make_random_edge_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L <= 0 || L >= maxLen || highIds.empty()) return false;\n\n        int t = (int)(rng() % L);\n        int u = pos[t];\n        int w = pos[t + 1];\n\n        int chosen = -1;\n        double bestVal = -1e100;\n\n        int H = (int)highIds.size();\n        for (int it = 0; it < 30; it++) {\n            int idx = (int)(pow(rnd01(), 1.8) * H);\n            if (idx >= H) idx = H - 1;\n            int x = highIds[idx];\n\n            int d1 = (int)distMat[u][x];\n            int d2 = (int)distMat[x][w];\n            int add = d1 + d2 - 1;\n            if (add <= 0 || add > 35) continue;\n            if (L + add > maxLen) continue;\n\n            double val = (double)dirt[x] / add + rnd01() * 0.02;\n            if (val > bestVal) {\n                bestVal = val;\n                chosen = x;\n            }\n        }\n\n        if (chosen < 0) return false;\n\n        string p1 = path_between(u, chosen);\n        string p2 = path_between(chosen, w);\n        if ((int)distMat[u][chosen] > 0 && p1.empty()) return false;\n        if ((int)distMat[chosen][w] > 0 && p2.empty()) return false;\n\n        string rep = p1 + p2;\n        if ((int)rep.size() <= 1) return false;\n\n        cand = replace_segment(route, t, t + 1, rep);\n        return true;\n    }\n\n    bool make_random_loop_remove(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        if (L < 4) return false;\n\n        int maxLen = min(80, L);\n        int len = 2 + (int)(rng() % (maxLen - 1)); // [2, maxLen]\n        int l = (int)(rng() % (L - len + 1));\n        int r = l + len;\n\n        if (pos[l] != pos[r]) return false;\n        if (!can_remove_closed(pos, cnt, l, r)) return false;\n\n        cand = remove_segment(route, l, len);\n        return true;\n    }\n\n    bool make_random_shortcut(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        if (L < 6) return false;\n\n        int maxSpan = min(90, L);\n        int span = 3 + (int)(rng() % (maxSpan - 2)); // [3, maxSpan]\n        int l = (int)(rng() % (L - span + 1));\n        int r = l + span;\n\n        int u = pos[l];\n        int v = pos[r];\n        int p = (int)distMat[u][v];\n        if (p <= 0 || p >= span) return false;\n\n        string rep = path_between(u, v);\n        if ((int)rep.size() != p) return false;\n        if (!can_replace_segment(pos, cnt, l, r, rep)) return false;\n\n        cand = replace_segment(route, l, r, rep);\n        return true;\n    }\n\n    bool improve_shorten_batch(string &route, Metric &curM, double timeLimit) {\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n        vector<int> cnt = build_counts(pos);\n\n        int L = (int)route.size();\n        int attempts = (L < 8000 ? 120 : (L < 20000 ? 80 : 55));\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (int it = 0; it < attempts && elapsed() < timeLimit; it++) {\n            string cand;\n            bool ok;\n            if ((rng() % 100) < 58) {\n                ok = make_random_shortcut(route, pos, cnt, cand);\n            } else {\n                ok = make_random_loop_remove(route, pos, cnt, cand);\n            }\n            if (!ok) continue;\n\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\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}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % (uint64_t)n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct Solver {\n    static constexpr int INF = 1e9;\n\n    int N{}, M{}, V{};\n    int si{}, sj{}, startId{};\n    vector<string> board;\n    vector<string> words;\n\n    array<vector<int>, 26> occ{};\n    int distMat[225][225]{};\n\n    vector<vector<int>> ov; // overlap [0..4]\n\n    vector<int> lastChar, nEnd;\n\n    // Exact evaluator precompute\n    vector<vector<uint16_t>> firstEndCost; // first word from start -> each end-state\n    vector<size_t> transOffset;            // (a,b) -> flattened matrix offset\n    vector<uint16_t> transData;            // transition matrix [nEnd[a] x nEnd[b]]\n\n    // row-wise minima for fast exact-greedy scoring\n    vector<size_t> rowMinOffset;           // (a,b) -> row minima offset\n    vector<uint16_t> rowMinData;           // size nEnd[a] for each pair\n\n    // Approx objective\n    vector<int> startApprox;\n    vector<vector<int>> edgeApprox;\n\n    // Candidate lists\n    vector<vector<int>> candNext, candPrev;\n\n    chrono::steady_clock::time_point t0;\n    XorShift64 rng{};\n\n    struct MoveInfo {\n        uint8_t type; // 0 swap, 1 relocate\n        int i, j;\n        long long dA;\n    };\n\n    struct CandMove {\n        uint8_t type;\n        uint16_t i, j;\n        int dA;\n    };\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n        words.resize(M);\n        for (int i = 0; i < M; i++) cin >> words[i];\n\n        V = N * N;\n        startId = si * N + sj;\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t h = 1469598103934665603ull;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        mix((uint64_t)si);\n        mix((uint64_t)sj);\n        for (const auto& r : board) for (char c : r) mix((uint64_t)c);\n        for (const auto& w : words) for (char c : w) mix((uint64_t)c);\n        return h;\n    }\n\n    void computeOccAndDist() {\n        for (auto& v : occ) v.clear();\n\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\n        for (int a = 0; a < V; a++) {\n            int ra = a / N, ca = a % N;\n            for (int b = 0; b < V; b++) {\n                int rb = b / N, cb = b % N;\n                distMat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n    }\n\n    void computeOverlap() {\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int best = 0;\n                for (int k = 4; k >= 0; k--) {\n                    bool ok = true;\n                    for (int x = 0; x < k; x++) {\n                        if (words[i][5 - k + x] != words[j][x]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (ok) {\n                        best = k;\n                        break;\n                    }\n                }\n                ov[i][j] = best;\n            }\n        }\n    }\n\n    // Type words[w][begin..4] from one startCell.\n    // out size = nEnd[w], order = occ[lastChar[w]]\n    void endCostsSingleStartRaw(int startCell, int w, int begin, uint16_t* out) const {\n        int prevId[225], nextId[225];\n        int prevCost[225], nextCost[225];\n\n        int ps = 1;\n        prevId[0] = startCell;\n        prevCost[0] = 0;\n\n        for (int pos = begin; pos < 5; pos++) {\n            const vector<int>& cells = occ[words[w][pos] - 'A'];\n            int ns = (int)cells.size();\n\n            for (int ni = 0; ni < ns; ni++) {\n                int q = cells[ni];\n                int best = INF;\n                for (int pi = 0; pi < ps; pi++) {\n                    int p = prevId[pi];\n                    int cand = prevCost[pi] + distMat[p][q] + 1;\n                    if (cand < best) best = cand;\n                }\n                nextId[ni] = q;\n                nextCost[ni] = best;\n            }\n\n            ps = ns;\n            for (int i = 0; i < ps; i++) {\n                prevId[i] = nextId[i];\n                prevCost[i] = nextCost[i];\n            }\n        }\n\n        for (int i = 0; i < ps; i++) out[i] = (uint16_t)prevCost[i];\n    }\n\n    void preprocessTransitionsAndApprox() {\n        lastChar.resize(M);\n        nEnd.resize(M);\n        for (int w = 0; w < M; w++) {\n            lastChar[w] = words[w][4] - 'A';\n            nEnd[w] = (int)occ[lastChar[w]].size();\n        }\n\n        firstEndCost.assign(M, {});\n        startApprox.assign(M, INF);\n        edgeApprox.assign(M, vector<int>(M, INF));\n\n        // first word from initial finger\n        for (int w = 0; w < M; w++) {\n            firstEndCost[w].resize(nEnd[w]);\n            endCostsSingleStartRaw(startId, w, 0, firstEndCost[w].data());\n            int mn = INF;\n            for (uint16_t v : firstEndCost[w]) mn = min(mn, (int)v);\n            startApprox[w] = mn;\n        }\n\n        transOffset.assign((size_t)M * M + 1, 0);\n        rowMinOffset.assign((size_t)M * M + 1, 0);\n\n        size_t totalTrans = 0, totalRow = 0;\n        for (int a = 0; a < M; a++) {\n            for (int b = 0; b < M; b++) {\n                size_t id = (size_t)a * M + b;\n                totalTrans += (size_t)nEnd[a] * nEnd[b];\n                transOffset[id + 1] = totalTrans;\n\n                totalRow += (size_t)nEnd[a];\n                rowMinOffset[id + 1] = totalRow;\n            }\n        }\n\n        transData.assign(totalTrans, 0);\n        rowMinData.assign(totalRow, 0);\n\n        uint16_t row[225];\n\n        for (int a = 0; a < M; a++) {\n            const vector<int>& starts = occ[lastChar[a]];\n            int na = nEnd[a];\n\n            for (int b = 0; b < M; b++) {\n                int nb = nEnd[b];\n                size_t id = (size_t)a * M + b;\n                size_t off = transOffset[id];\n                size_t roff = rowMinOffset[id];\n                int begin = ov[a][b];\n\n                int mn = INF;\n                for (int si = 0; si < na; si++) {\n                    endCostsSingleStartRaw(starts[si], b, begin, row);\n                    size_t base = off + (size_t)si * nb;\n\n                    int rmin = INF;\n                    for (int tj = 0; tj < nb; tj++) {\n                        int v = (int)row[tj];\n                        transData[base + tj] = row[tj];\n                        if (v < rmin) rmin = v;\n                    }\n                    rowMinData[roff + si] = (uint16_t)rmin;\n                    if (rmin < mn) mn = rmin;\n                }\n                edgeApprox[a][b] = mn;\n            }\n        }\n    }\n\n    void buildCandidateLists(int C = 12) {\n        candNext.assign(M, {});\n        candPrev.assign(M, {});\n\n        for (int a = 0; a < M; a++) {\n            vector<pair<int, int>> v;\n            v.reserve(M - 1);\n            for (int b = 0; b < M; b++) if (b != a) v.emplace_back(edgeApprox[a][b], b);\n            sort(v.begin(), v.end());\n            int take = min(C, (int)v.size());\n            candNext[a].reserve(take);\n            for (int i = 0; i < take; i++) candNext[a].push_back(v[i].second);\n        }\n\n        for (int b = 0; b < M; b++) {\n            vector<pair<int, int>> v;\n            v.reserve(M - 1);\n            for (int a = 0; a < M; a++) if (a != b) v.emplace_back(edgeApprox[a][b], a);\n            sort(v.begin(), v.end());\n            int take = min(C, (int)v.size());\n            candPrev[b].reserve(take);\n            for (int i = 0; i < take; i++) candPrev[b].push_back(v[i].second);\n        }\n    }\n\n    void preprocess() {\n        computeOccAndDist();\n        computeOverlap();\n        preprocessTransitionsAndApprox();\n        buildCandidateLists(12);\n    }\n\n    inline long long edgeContrib(int from, int to) const {\n        if (to < 0) return 0;\n        if (from < 0) return startApprox[to];\n        return edgeApprox[from][to];\n    }\n\n    long long approxCost(const vector<int>& perm) const {\n        long long c = startApprox[perm[0]];\n        for (int i = 1; i < M; i++) c += edgeApprox[perm[i - 1]][perm[i]];\n        return c;\n    }\n\n    long long deltaSwapApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int cand[4] = {i, i + 1, j, j + 1};\n        int pos[4], npos = 0;\n        for (int z = 0; z < 4; z++) {\n            int t = cand[z];\n            if (t < 0 || t >= M) continue;\n            bool ex = false;\n            for (int k = 0; k < npos; k++) if (pos[k] == t) { ex = true; break; }\n            if (!ex) pos[npos++] = t;\n        }\n\n        auto getNew = [&](int idx) -> int {\n            if (idx == i) return p[j];\n            if (idx == j) return p[i];\n            return p[idx];\n        };\n\n        long long oldc = 0, newc = 0;\n        for (int z = 0; z < npos; z++) {\n            int t = pos[z];\n            int toOld = p[t];\n            int fromOld = (t == 0 ? -1 : p[t - 1]);\n            oldc += edgeContrib(fromOld, toOld);\n\n            int toNew = getNew(t);\n            int fromNew = (t == 0 ? -1 : getNew(t - 1));\n            newc += edgeContrib(fromNew, toNew);\n        }\n        return newc - oldc;\n    }\n\n    long long deltaRelocateApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        int x = p[i];\n\n        if (i < j) {\n            int a = (i > 0 ? p[i - 1] : -1);\n            int b = p[i + 1];\n            int c = p[j];\n            int d = (j + 1 < M ? p[j + 1] : -1);\n\n            long long oldc = edgeContrib(a, x) + edgeContrib(x, b) + edgeContrib(c, d);\n            long long newc = edgeContrib(a, b) + edgeContrib(c, x) + edgeContrib(x, d);\n            return newc - oldc;\n        } else {\n            int a = p[i - 1];\n            int b = (i + 1 < M ? p[i + 1] : -1);\n            int c = (j > 0 ? p[j - 1] : -1);\n            int d = p[j];\n\n            long long oldc = edgeContrib(c, d) + edgeContrib(a, x) + edgeContrib(x, b);\n            long long newc = edgeContrib(c, x) + edgeContrib(x, d) + edgeContrib(a, b);\n            return newc - oldc;\n        }\n    }\n\n    static void relocateMove(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) p[k] = p[k + 1];\n            p[j] = v;\n        } else {\n            for (int k = i; k > j; k--) p[k] = p[k - 1];\n            p[j] = v;\n        }\n    }\n\n    static void swapWithPos(vector<int>& p, vector<int>& pos, int i, int j) {\n        int a = p[i], b = p[j];\n        swap(p[i], p[j]);\n        pos[a] = j;\n        pos[b] = i;\n    }\n\n    static void relocateWithPos(vector<int>& p, vector<int>& pos, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) {\n                p[k] = p[k + 1];\n                pos[p[k]] = k;\n            }\n            p[j] = v;\n            pos[v] = j;\n        } else {\n            for (int k = i; k > j; k--) {\n                p[k] = p[k - 1];\n                pos[p[k]] = k;\n            }\n            p[j] = v;\n            pos[v] = j;\n        }\n    }\n\n    MoveInfo proposeMove(const vector<int>& cur, const vector<int>& pos) {\n        MoveInfo mv{1, 0, 0, 0};\n\n        int mode = rng.nextInt(100);\n\n        if (mode < 34) {\n            mv.type = 0;\n            mv.i = rng.nextInt(M);\n            mv.j = rng.nextInt(M - 1);\n            if (mv.j >= mv.i) mv.j++;\n        } else if (mode < 68) {\n            mv.type = 1;\n            mv.i = rng.nextInt(M);\n            mv.j = rng.nextInt(M - 1);\n            if (mv.j >= mv.i) mv.j++;\n        } else if (mode < 84) {\n            bool found = false;\n            for (int tr = 0; tr < 5 && !found; tr++) {\n                int pa = rng.nextInt(M);\n                int a = cur[pa];\n                const auto& cn = candNext[a];\n                if (cn.empty()) continue;\n\n                int take = min((int)cn.size(), 6);\n                int b = cn[rng.nextInt(take)];\n                int pb = pos[b];\n                if (pb == pa + 1) continue;\n\n                mv.type = 1;\n                mv.i = pb;\n                mv.j = (pb < pa ? pa : pa + 1);\n                if (mv.j >= M) mv.j = M - 1;\n                if (mv.i == mv.j) continue;\n                found = true;\n            }\n            if (!found) {\n                mv.type = 1;\n                mv.i = rng.nextInt(M);\n                mv.j = rng.nextInt(M - 1);\n                if (mv.j >= mv.i) mv.j++;\n            }\n        } else {\n            bool found = false;\n            for (int tr = 0; tr < 5 && !found; tr++) {\n                int pa = rng.nextInt(M);\n                int a = cur[pa];\n                const auto& cp = candPrev[a];\n                if (cp.empty()) continue;\n\n                int take = min((int)cp.size(), 6);\n                int b = cp[rng.nextInt(take)];\n                int pb = pos[b];\n                if (pb == pa - 1) continue;\n\n                mv.type = 1;\n                mv.i = pb;\n                mv.j = (pb < pa ? pa - 1 : pa);\n                if (mv.j < 0) mv.j = 0;\n                if (mv.i == mv.j) continue;\n                found = true;\n            }\n            if (!found) {\n                mv.type = 1;\n                mv.i = rng.nextInt(M);\n                mv.j = rng.nextInt(M - 1);\n                if (mv.j >= mv.i) mv.j++;\n            }\n        }\n\n        mv.dA = (mv.type == 0) ? deltaSwapApprox(cur, mv.i, mv.j)\n                               : deltaRelocateApprox(cur, mv.i, mv.j);\n        return mv;\n    }\n\n    vector<int> nearestAllStarts() const {\n        vector<int> bestPerm;\n        long long best = (1LL << 60);\n\n        vector<char> used(M);\n        vector<int> perm(M);\n\n        for (int s = 0; s < M; s++) {\n            fill(used.begin(), used.end(), 0);\n            perm[0] = s;\n            used[s] = 1;\n            long long c = startApprox[s];\n\n            for (int pos = 1; pos < M; pos++) {\n                int cur = perm[pos - 1];\n                int bj = -1, bv = INF;\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeApprox[cur][j];\n                    if (v < bv) {\n                        bv = v;\n                        bj = j;\n                    }\n                }\n                perm[pos] = bj;\n                used[bj] = 1;\n                c += bv;\n            }\n\n            if (c < best) {\n                best = c;\n                bestPerm = perm;\n            }\n        }\n        return bestPerm;\n    }\n\n    vector<int> cheapestInsertion(int seed) const {\n        vector<int> path;\n        path.reserve(M);\n        vector<char> used(M, 0);\n\n        path.push_back(seed);\n        used[seed] = 1;\n\n        for (int step = 1; step < M; step++) {\n            long long bestDelta = (1LL << 60);\n            int bestWord = -1, bestPos = -1;\n            int len = (int)path.size();\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                long long dFront = (long long)startApprox[x] + edgeApprox[x][path[0]] - startApprox[path[0]];\n                if (dFront < bestDelta) {\n                    bestDelta = dFront;\n                    bestWord = x;\n                    bestPos = 0;\n                }\n\n                for (int pos = 1; pos < len; pos++) {\n                    int u = path[pos - 1], v = path[pos];\n                    long long d = (long long)edgeApprox[u][x] + edgeApprox[x][v] - edgeApprox[u][v];\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestWord = x;\n                        bestPos = pos;\n                    }\n                }\n\n                long long dEnd = edgeApprox[path[len - 1]][x];\n                if (dEnd < bestDelta) {\n                    bestDelta = dEnd;\n                    bestWord = x;\n                    bestPos = len;\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestWord);\n            used[bestWord] = 1;\n        }\n        return path;\n    }\n\n    vector<int> randomGreedy(int seed, int rcl) {\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> used(M, 0);\n\n        perm.push_back(seed);\n        used[seed] = 1;\n\n        while ((int)perm.size() < M) {\n            int cur = perm.back();\n            vector<pair<int, int>> cands;\n            cands.reserve(M);\n\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                cands.emplace_back(edgeApprox[cur][j], j);\n            }\n\n            sort(cands.begin(), cands.end());\n            int take = min(rcl, (int)cands.size());\n            int pick = cands[rng.nextInt(take)].second;\n            perm.push_back(pick);\n            used[pick] = 1;\n        }\n\n        return perm;\n    }\n\n    int appendMinFromVec(const vector<int>& vec, int a, int b) const {\n        size_t id = (size_t)a * M + b;\n        const uint16_t* rm = rowMinData.data() + rowMinOffset[id];\n        int na = nEnd[a];\n        int best = INF;\n        for (int i = 0; i < na; i++) {\n            int cand = vec[i] + (int)rm[i];\n            if (cand < best) best = cand;\n        }\n        return best;\n    }\n\n    void appendTransform(const vector<int>& vec, int a, int b, vector<int>& out) const {\n        int na = nEnd[a];\n        int nb = nEnd[b];\n        out.assign(nb, INF);\n\n        size_t id = (size_t)a * M + b;\n        const uint16_t* mat = transData.data() + transOffset[id];\n\n        for (int i = 0; i < na; i++) {\n            int base = vec[i];\n            const uint16_t* row = mat + (size_t)i * nb;\n            for (int j = 0; j < nb; j++) {\n                int cand = base + (int)row[j];\n                if (cand < out[j]) out[j] = cand;\n            }\n        }\n    }\n\n    // Exact-aware greedy construction\n    vector<int> exactGreedy(int start, int rcl) {\n        vector<char> used(M, 0);\n        vector<int> perm;\n        perm.reserve(M);\n\n        int cur = start;\n        used[cur] = 1;\n        perm.push_back(cur);\n\n        vector<int> vec(nEnd[cur]);\n        for (int i = 0; i < nEnd[cur]; i++) vec[i] = (int)firstEndCost[cur][i];\n        vector<int> nvec;\n        nvec.reserve(225);\n\n        for (int step = 1; step < M; step++) {\n            vector<pair<int, int>> top;\n            top.reserve(rcl);\n\n            for (int b = 0; b < M; b++) if (!used[b]) {\n                int v = appendMinFromVec(vec, cur, b);\n\n                int p = 0;\n                while (p < (int)top.size() && top[p].first <= v) p++;\n                if (p < rcl) {\n                    top.insert(top.begin() + p, {v, b});\n                    if ((int)top.size() > rcl) top.pop_back();\n                }\n            }\n\n            int pick = top[(rcl <= 1 ? 0 : rng.nextInt((int)top.size()))].second;\n            appendTransform(vec, cur, pick, nvec);\n            vec.swap(nvec);\n\n            cur = pick;\n            used[cur] = 1;\n            perm.push_back(cur);\n        }\n\n        return perm;\n    }\n\n    vector<int> pathRelinkCandidate(vector<int> cur, const vector<int>& target) const {\n        vector<int> pos(M);\n        for (int i = 0; i < M; i++) pos[cur[i]] = i;\n\n        long long c = approxCost(cur);\n        long long best = c;\n        vector<int> bestP = cur;\n\n        for (int i = 0; i < M; i++) {\n            int want = target[i];\n            int j = pos[want];\n            if (j == i) continue;\n\n            long long d = deltaSwapApprox(cur, i, j);\n            int a = cur[i], b = cur[j];\n            swap(cur[i], cur[j]);\n            pos[a] = j;\n            pos[b] = i;\n            c += d;\n\n            if (c < best) {\n                best = c;\n                bestP = cur;\n            }\n        }\n        return bestP;\n    }\n\n    uint64_t hashPerm(const vector<int>& p) const {\n        uint64_t h = 1469598103934665603ull;\n        for (int x : p) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ull;\n        }\n        return h;\n    }\n\n    void SAApprox(vector<int>& perm, long long& curCost, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm, best = perm;\n        vector<int> pos(M);\n        for (int i = 0; i < M; i++) pos[cur[i]] = i;\n\n        long long cC = curCost, bC = cC;\n\n        const double T0 = 22.0, T1 = 0.05;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        const int SAMPLE = 3;\n        array<MoveInfo, SAMPLE> sample{};\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            for (int s = 0; s < SAMPLE; s++) sample[s] = proposeMove(cur, pos);\n\n            int bestIdx = 0;\n            for (int s = 1; s < SAMPLE; s++) if (sample[s].dA < sample[bestIdx].dA) bestIdx = s;\n\n            int pick = (rng.nextInt(100) < 80 ? bestIdx : rng.nextInt(SAMPLE));\n            MoveInfo mv = sample[pick];\n\n            bool accept = (mv.dA <= 0) || (rng.nextDouble() < exp(-double(mv.dA) / temp));\n            if (!accept) continue;\n\n            if (mv.type == 0) swapWithPos(cur, pos, mv.i, mv.j);\n            else relocateWithPos(cur, pos, mv.i, mv.j);\n\n            cC += mv.dA;\n            if (cC < bC) {\n                bC = cC;\n                best = cur;\n            }\n        }\n\n        perm = best;\n        curCost = bC;\n    }\n\n    int exactCost(const vector<int>& perm) const {\n        int dpA[225], dpB[225];\n\n        int w0 = perm[0];\n        int sz = nEnd[w0];\n        for (int i = 0; i < sz; i++) dpA[i] = (int)firstEndCost[w0][i];\n\n        for (int idx = 1; idx < M; idx++) {\n            int a = perm[idx - 1], b = perm[idx];\n            int na = nEnd[a], nb = nEnd[b];\n\n            for (int j = 0; j < nb; j++) dpB[j] = INF;\n\n            size_t id = (size_t)a * M + b;\n            const uint16_t* mat = transData.data() + transOffset[id];\n\n            for (int i = 0; i < na; i++) {\n                int base = dpA[i];\n                const uint16_t* row = mat + (size_t)i * nb;\n                for (int j = 0; j < nb; j++) {\n                    int cand = base + (int)row[j];\n                    if (cand < dpB[j]) dpB[j] = cand;\n                }\n            }\n\n            for (int j = 0; j < nb; j++) dpA[j] = dpB[j];\n            sz = nb;\n        }\n\n        int ans = INF;\n        for (int i = 0; i < sz; i++) ans = min(ans, dpA[i]);\n        return ans;\n    }\n\n    void perturb(vector<int>& p, int moves) {\n        for (int t = 0; t < moves; t++) {\n            if (rng.nextInt(100) < 50) {\n                int i = rng.nextInt(M);\n                int j = rng.nextInt(M - 1);\n                if (j >= i) j++;\n                swap(p[i], p[j]);\n            } else {\n                int i = rng.nextInt(M);\n                int j = rng.nextInt(M - 1);\n                if (j >= i) j++;\n                relocateMove(p, i, j);\n            }\n        }\n    }\n\n    void SAExact(vector<int>& perm, long long& curA, int& curE, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm, best = perm;\n        vector<int> pos(M);\n        for (int i = 0; i < M; i++) pos[cur[i]] = i;\n\n        long long cA = curA, bA = curA;\n        int cE = curE, bE = curE;\n\n        const double T0 = 10.8, T1 = 0.02;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        int stagn = 0;\n        const int SAMPLE = 4;\n        array<MoveInfo, SAMPLE> sample{};\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            for (int s = 0; s < SAMPLE; s++) sample[s] = proposeMove(cur, pos);\n\n            int bestIdx = 0;\n            for (int s = 1; s < SAMPLE; s++) if (sample[s].dA < sample[bestIdx].dA) bestIdx = s;\n            int pick = (rng.nextInt(100) < 82 ? bestIdx : rng.nextInt(SAMPLE));\n            MoveInfo mv = sample[pick];\n\n            if (mv.dA > 240 && rng.nextInt(100) < 96) continue;\n            if (mv.dA > 130 && rng.nextInt(100) < 65) continue;\n\n            if (mv.type == 0) swapWithPos(cur, pos, mv.i, mv.j);\n            else relocateWithPos(cur, pos, mv.i, mv.j);\n\n            int ne = exactCost(cur);\n            int dE = ne - cE;\n\n            bool accept = false;\n            if (dE < 0) {\n                accept = true;\n            } else if (dE == 0) {\n                if (mv.dA < 0) accept = true;\n                else accept = (rng.nextInt(100) < 8);\n            } else {\n                accept = (rng.nextDouble() < exp(-double(dE) / temp));\n            }\n\n            if (accept) {\n                cE = ne;\n                cA += mv.dA;\n                if (cE < bE || (cE == bE && cA < bA)) {\n                    bE = cE;\n                    bA = cA;\n                    best = cur;\n                    stagn = 0;\n                } else {\n                    stagn++;\n                }\n            } else {\n                if (mv.type == 0) swapWithPos(cur, pos, mv.i, mv.j);\n                else relocateWithPos(cur, pos, mv.j, mv.i); // inverse\n                stagn++;\n            }\n\n            if (stagn > 6000 && elapsed() < endTime - 0.02) {\n                cur = best;\n                for (int t = 0; t < 2; t++) {\n                    if (rng.nextInt(100) < 50) {\n                        int a = rng.nextInt(M);\n                        int b = rng.nextInt(M - 1);\n                        if (b >= a) b++;\n                        swap(cur[a], cur[b]);\n                    } else {\n                        int a = rng.nextInt(M);\n                        int b = rng.nextInt(M - 1);\n                        if (b >= a) b++;\n                        relocateMove(cur, a, b);\n                    }\n                }\n                for (int k = 0; k < M; k++) pos[cur[k]] = k;\n                cA = approxCost(cur);\n                cE = exactCost(cur);\n                stagn = 0;\n            }\n        }\n\n        perm = best;\n        curA = approxCost(best);\n        curE = bE;\n    }\n\n    void exactCandidateDescent(vector<int>& perm, long long& curA, int& curE, double endTime) {\n        vector<int> pos(M), tmp;\n        tmp.reserve(M);\n\n        vector<CandMove> moves;\n        moves.reserve(M * 16 + 180);\n\n        auto cmpMove = [](const CandMove& a, const CandMove& b) {\n            return a.dA < b.dA;\n        };\n\n        while (elapsed() < endTime) {\n            for (int i = 0; i < M; i++) pos[perm[i]] = i;\n\n            moves.clear();\n\n            for (int pa = 0; pa < M; pa++) {\n                int a = perm[pa];\n\n                const auto& cn = candNext[a];\n                int limN = min((int)cn.size(), 5);\n                for (int z = 0; z < limN; z++) {\n                    int b = cn[z];\n                    int pb = pos[b];\n                    if (pb == pa + 1) continue;\n                    int j = (pb < pa ? pa : pa + 1);\n                    if (j >= M) j = M - 1;\n                    if (pb == j) continue;\n                    int dA = (int)deltaRelocateApprox(perm, pb, j);\n                    moves.push_back(CandMove{1, (uint16_t)pb, (uint16_t)j, dA});\n                }\n\n                const auto& cp = candPrev[a];\n                int limP = min((int)cp.size(), 5);\n                for (int z = 0; z < limP; z++) {\n                    int b = cp[z];\n                    int pb = pos[b];\n                    if (pb == pa - 1) continue;\n                    int j = (pb < pa ? pa - 1 : pa);\n                    if (j < 0) j = 0;\n                    if (pb == j) continue;\n                    int dA = (int)deltaRelocateApprox(perm, pb, j);\n                    moves.push_back(CandMove{1, (uint16_t)pb, (uint16_t)j, dA});\n                }\n            }\n\n            for (int t = 0; t < 100; t++) {\n                if (rng.nextInt(100) < 55) {\n                    int i = rng.nextInt(M);\n                    int j = rng.nextInt(M - 1);\n                    if (j >= i) j++;\n                    int dA = (int)deltaSwapApprox(perm, i, j);\n                    moves.push_back(CandMove{0, (uint16_t)i, (uint16_t)j, dA});\n                } else {\n                    int i = rng.nextInt(M);\n                    int j = rng.nextInt(M - 1);\n                    if (j >= i) j++;\n                    int dA = (int)deltaRelocateApprox(perm, i, j);\n                    moves.push_back(CandMove{1, (uint16_t)i, (uint16_t)j, dA});\n                }\n            }\n\n            if (moves.empty()) break;\n            sort(moves.begin(), moves.end(), cmpMove);\n\n            int K = min((int)moves.size(), 180);\n\n            int bestIdx = -1;\n            int bestE = curE;\n            int bestDA = 0;\n\n            for (int idx = 0; idx < K; idx++) {\n                if ((idx & 15) == 0 && elapsed() >= endTime) break;\n\n                const CandMove& mv = moves[idx];\n                tmp = perm;\n                if (mv.type == 0) swap(tmp[mv.i], tmp[mv.j]);\n                else relocateMove(tmp, mv.i, mv.j);\n\n                int ne = exactCost(tmp);\n                if (ne < bestE || (ne == bestE && mv.dA < bestDA)) {\n                    bestE = ne;\n                    bestDA = mv.dA;\n                    bestIdx = idx;\n                }\n            }\n\n            if (bestIdx < 0) break;\n\n            const CandMove& bm = moves[bestIdx];\n            if (bm.type == 0) swap(perm[bm.i], perm[bm.j]);\n            else relocateMove(perm, bm.i, bm.j);\n\n            curE = bestE;\n            curA += bestDA;\n        }\n    }\n\n    void buildString(const vector<int>& perm, string& out) const {\n        out.clear();\n        out.reserve(5 * M);\n\n        out += words[perm[0]];\n        for (int i = 1; i < M; i++) {\n            int a = perm[i - 1], b = perm[i];\n            int k = ov[a][b];\n            for (int p = k; p < 5; p++) out.push_back(words[b][p]);\n        }\n    }\n\n    vector<int> bestPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<short>> parent(L, vector<short>(V, -1));\n\n        vector<int> prev(V, INF), cur(V, INF);\n        vector<int> prevCells = occ[s[0] - 'A'];\n\n        for (int q : prevCells) prev[q] = distMat[startId][q] + 1;\n\n        for (int idx = 1; idx < L; idx++) {\n            const vector<int>& nextCells = occ[s[idx] - 'A'];\n\n            for (int q : nextCells) {\n                int best = INF;\n                short bp = -1;\n                for (int p : prevCells) {\n                    int cand = prev[p] + distMat[p][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bp = (short)p;\n                    }\n                }\n                cur[q] = best;\n                parent[idx][q] = bp;\n            }\n\n            for (int p : prevCells) prev[p] = INF;\n            prevCells = nextCells;\n            for (int q : prevCells) {\n                prev[q] = cur[q];\n                cur[q] = INF;\n            }\n        }\n\n        int endCell = -1, best = INF;\n        for (int p : prevCells) {\n            if (prev[p] < best) {\n                best = prev[p];\n                endCell = p;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = endCell;\n        for (int i = L - 1; i >= 1; i--) {\n            path[i - 1] = parent[i][path[i]];\n        }\n        return path;\n    }\n\n    void solve() {\n        readInput();\n        rng = XorShift64(makeSeed());\n        t0 = chrono::steady_clock::now();\n\n        preprocess();\n\n        const double APPROX_END = 0.52;\n        const double MAIN_END   = 1.83;\n        const double DESC_END   = 1.90;\n        const double FINAL_END  = 1.94;\n\n        vector<vector<int>> cands;\n        vector<long long> aCost;\n        unordered_set<uint64_t> seen;\n        seen.reserve(256);\n\n        auto addCand = [&](vector<int> p) {\n            uint64_t h = hashPerm(p);\n            if (seen.insert(h).second) {\n                aCost.push_back(approxCost(p));\n                cands.push_back(move(p));\n            }\n        };\n\n        // Baseline seeds\n        addCand(nearestAllStarts());\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 (startApprox[a] != startApprox[b]) return startApprox[a] < startApprox[b];\n            return a < b;\n        });\n\n        for (int i = 0; i < min(M, 6); i++) addCand(cheapestInsertion(ord[i]));\n        for (int t = 0; t < 3; t++) addCand(cheapestInsertion(rng.nextInt(M)));\n\n        for (int i = 0; i < min(M, 4); i++) addCand(randomGreedy(ord[i], 4));\n        for (int t = 0; t < 6; t++) addCand(randomGreedy(rng.nextInt(M), 3 + rng.nextInt(4)));\n\n        // Exact-aware greedy seeds\n        for (int i = 0; i < min(M, 8); i++) addCand(exactGreedy(ord[i], 1));\n        for (int i = 0; i < min(M, 5); i++) addCand(exactGreedy(ord[i], 3));\n        for (int t = 0; t < 6; t++) addCand(exactGreedy(rng.nextInt(M), 3 + rng.nextInt(3)));\n\n        // Path relinking among top approx seeds\n        {\n            vector<int> idx((int)cands.size());\n            iota(idx.begin(), idx.end(), 0);\n            sort(idx.begin(), idx.end(), [&](int x, int y) { return aCost[x] < aCost[y]; });\n\n            int K = min(5, (int)idx.size());\n            for (int i = 0; i < K; i++) {\n                for (int j = i + 1; j < K; j++) {\n                    addCand(pathRelinkCandidate(cands[idx[i]], cands[idx[j]]));\n                    addCand(pathRelinkCandidate(cands[idx[j]], cands[idx[i]]));\n                }\n            }\n        }\n\n        // Short approx SA on top seeds\n        if (elapsed() < APPROX_END) {\n            vector<int> idx((int)cands.size());\n            iota(idx.begin(), idx.end(), 0);\n            sort(idx.begin(), idx.end(), [&](int x, int y) { return aCost[x] < aCost[y]; });\n\n            int use = min(2, (int)idx.size());\n            for (int z = 0; z < use && elapsed() < APPROX_END; z++) {\n                int id = idx[z];\n                double rem = APPROX_END - elapsed();\n                double slice = rem / (use - z);\n                SAApprox(cands[id], aCost[id], elapsed() + slice);\n            }\n        }\n\n        int C = (int)cands.size();\n        vector<int> eCost(C, INF);\n\n        int bestIdx = 0;\n        int bestE = INF;\n        long long bestA = (1LL << 60);\n\n        for (int i = 0; i < C; i++) {\n            eCost[i] = exactCost(cands[i]);\n            if (eCost[i] < bestE || (eCost[i] == bestE && aCost[i] < bestA)) {\n                bestE = eCost[i];\n                bestA = aCost[i];\n                bestIdx = i;\n            }\n        }\n\n        vector<int> bestPerm = cands[bestIdx];\n\n        vector<int> seedOrder(C);\n        iota(seedOrder.begin(), seedOrder.end(), 0);\n        sort(seedOrder.begin(), seedOrder.end(), [&](int x, int y) {\n            if (eCost[x] != eCost[y]) return eCost[x] < eCost[y];\n            return aCost[x] < aCost[y];\n        });\n\n        int round = 0;\n        int seedUse = min(C, 12);\n\n        while (elapsed() < MAIN_END) {\n            vector<int> cur;\n            long long curA;\n            int curE;\n\n            if (round < seedUse) {\n                int id = seedOrder[round];\n                cur = cands[id];\n                curA = aCost[id];\n                curE = eCost[id];\n            } else {\n                if ((round & 3) == 0 && seedUse > 0) {\n                    int id = seedOrder[rng.nextInt(seedUse)];\n                    cur = cands[id];\n                } else {\n                    cur = bestPerm;\n                }\n                perturb(cur, 1 + (round % 6));\n                curA = approxCost(cur);\n                curE = exactCost(cur);\n            }\n\n            double rem = MAIN_END - elapsed();\n            if (rem <= 0.03) break;\n            double slice = min(0.18, max(0.05, rem * 0.33));\n\n            SAExact(cur, curA, curE, elapsed() + slice);\n\n            if (curE < bestE || (curE == bestE && curA < bestA)) {\n                bestE = curE;\n                bestA = curA;\n                bestPerm = cur;\n            }\n            round++;\n        }\n\n        if (elapsed() < DESC_END) {\n            exactCandidateDescent(bestPerm, bestA, bestE, DESC_END);\n        }\n\n        if (elapsed() < FINAL_END) {\n            SAExact(bestPerm, bestA, bestE, FINAL_END);\n        }\n\n        string finalS;\n        buildString(bestPerm, finalS);\n\n        vector<int> path = bestPathForString(finalS);\n\n        for (int id : path) {\n            cout << (id / N) << ' ' << (id % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Mask {\n    static constexpr int W = 7; // 448 bits >= 400 cells\n    array<uint64_t, W> w{};\n    Mask() { w.fill(0ULL); }\n    inline void set(int idx) { w[idx >> 6] |= (1ULL << (idx & 63)); }\n    inline bool test(int idx) const { return (w[idx >> 6] >> (idx & 63)) & 1ULL; }\n};\n\nstruct Placement {\n    vector<int> cells;      // covered cell indices\n    Mask mask;\n    vector<uint8_t> qcov;   // for each drilled query id: 0/1 cover\n};\n\nclass OilSolver {\n    struct ArrHash {\n        size_t operator()(array<uint64_t, Mask::W> const& a) const noexcept {\n            uint64_t h = 0x9e3779b97f4a7c15ULL;\n            for (uint64_t x : a) {\n                x ^= (x >> 30);\n                x *= 0xbf58476d1ce4e5b9ULL;\n                x ^= (x >> 27);\n                x *= 0x94d049bb133111ebULL;\n                x ^= (x >> 31);\n                h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n            }\n            return (size_t)h;\n        }\n    };\n\n    struct UnionCand {\n        array<uint64_t, Mask::W> m{};\n        int cnt = 0;\n    };\n\n    int N = 0, M = 0, n2 = 0;\n    double eps = 0.0;\n\n    vector<vector<pair<int,int>>> shapes;\n    vector<vector<Placement>> fieldPls; // [field][placement]\n\n    vector<int> drilledVal;   // -1 unknown, else exact v(cell)\n    vector<int> qidOfCell;    // cell -> query id if drilled\n    vector<int> queryVals;    // drilled exact values\n    vector<int> queryCells;\n    vector<int> positiveDrilled;\n\n    vector<int> priorOrder;\n    int priorPtr = 0;\n\n    vector<array<uint64_t, Mask::W>> forbiddenMasks;\n\n    mt19937 rng;\n    int ops = 0;\n    int wrongGuesses = 0;\n\n    chrono::steady_clock::time_point startTime;\n\n    static constexpr double HARD_LIMIT_MS = 2850.0;\n    static constexpr double EMERGENCY_MS  = 2620.0;\n    static constexpr int MAX_WRONG_GUESSES = 18;\n\npublic:\n    OilSolver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        n2 = N * N;\n        shapes.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            shapes[k].resize(d);\n            for (int i = 0; i < d; i++) {\n                int r, c;\n                cin >> r >> c;\n                shapes[k][i] = {r, c};\n            }\n        }\n        drilledVal.assign(n2, -1);\n        qidOfCell.assign(n2, -1);\n    }\n\n    void build_placements() {\n        fieldPls.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int maxr = 0, maxc = 0;\n            for (auto [r, c] : shapes[k]) {\n                maxr = max(maxr, r);\n                maxc = max(maxc, c);\n            }\n\n            for (int di = 0; di + maxr < N; di++) {\n                for (int dj = 0; dj + maxc < N; dj++) {\n                    Placement pl;\n                    pl.cells.reserve(shapes[k].size());\n                    pl.qcov.reserve(n2);\n                    for (auto [r, c] : shapes[k]) {\n                        int idx = (di + r) * N + (dj + c);\n                        pl.cells.push_back(idx);\n                        pl.mask.set(idx);\n                    }\n                    fieldPls[k].push_back(move(pl));\n                }\n            }\n        }\n    }\n\n    void build_prior_order() {\n        vector<vector<int>> coverCnt(M, vector<int>(n2, 0));\n        for (int k = 0; k < M; k++) {\n            for (auto const& pl : fieldPls[k]) {\n                for (int idx : pl.cells) coverCnt[k][idx]++;\n            }\n        }\n\n        vector<double> score(n2, 0.0);\n        for (int idx = 0; idx < n2; idx++) {\n            double p0 = 1.0;\n            for (int k = 0; k < M; k++) {\n                double pk = (double)coverCnt[k][idx] / (double)fieldPls[k].size();\n                p0 *= (1.0 - pk);\n            }\n            double p = 1.0 - p0;\n            score[idx] = p * (1.0 - p);\n        }\n\n        priorOrder.resize(n2);\n        iota(priorOrder.begin(), priorOrder.end(), 0);\n        sort(priorOrder.begin(), priorOrder.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return a < b;\n        });\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << \" \" << (idx % N) << '\\n' << flush;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    int ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int idx : cells) cout << \" \" << (idx / N) << \" \" << (idx % N);\n        cout << '\\n' << flush;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    void add_drill(int idx, int val) {\n        if (drilledVal[idx] != -1) return;\n\n        drilledVal[idx] = val;\n        int qid = (int)queryVals.size();\n        qidOfCell[idx] = qid;\n        queryVals.push_back(val);\n        queryCells.push_back(idx);\n        if (val > 0) positiveDrilled.push_back(idx);\n\n        // append one qcov bit for every placement\n        for (int k = 0; k < M; k++) {\n            for (auto& pl : fieldPls[k]) {\n                pl.qcov.push_back(pl.mask.test(idx) ? 1 : 0);\n            }\n        }\n    }\n\n    int pick_prior_cell() {\n        while (priorPtr < (int)priorOrder.size() && drilledVal[priorOrder[priorPtr]] != -1) priorPtr++;\n        if (priorPtr < (int)priorOrder.size()) return priorOrder[priorPtr++];\n        return -1;\n    }\n\n    int first_unknown_cell() const {\n        for (int idx = 0; idx < n2; idx++) if (drilledVal[idx] == -1) return idx;\n        return -1;\n    }\n\n    int pick_frontier_cell() const {\n        static const int di[4] = {-1, 1, 0, 0};\n        static const int dj[4] = {0, 0, -1, 1};\n\n        int best = -1, bestScore = -1;\n        for (int idx : positiveDrilled) {\n            int i = idx / N, j = idx % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nid = ni * N + nj;\n                if (drilledVal[nid] != -1) continue;\n\n                int sc = 0;\n                for (int d2 = 0; d2 < 4; d2++) {\n                    int xi = ni + di[d2], xj = nj + dj[d2];\n                    if (xi < 0 || xi >= N || xj < 0 || xj >= N) continue;\n                    int xid = xi * N + xj;\n                    if (drilledVal[xid] > 0) sc++;\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = nid;\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<int> exact_from_drilled() const {\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int idx = 0; idx < n2; idx++) if (drilledVal[idx] > 0) ans.push_back(idx);\n        return ans;\n    }\n\n    static inline void set_bit(array<uint64_t, Mask::W>& m, int idx) {\n        m[idx >> 6] |= (1ULL << (idx & 63));\n    }\n\n    bool is_forbidden(const array<uint64_t, Mask::W>& m) const {\n        for (auto const& x : forbiddenMasks) if (x == m) return true;\n        return false;\n    }\n\n    void add_forbidden(const array<uint64_t, Mask::W>& m) {\n        if (!is_forbidden(m)) forbiddenMasks.push_back(m);\n    }\n\n    void normalize_mask(array<uint64_t, Mask::W>& m) const {\n        for (int idx : positiveDrilled) set_bit(m, idx);\n    }\n\n    array<uint64_t, Mask::W> build_union_mask(const vector<int>& asg) const {\n        array<uint64_t, Mask::W> m{};\n        m.fill(0ULL);\n        for (int k = 0; k < M; k++) {\n            int p = asg[k];\n            if (p < 0) continue;\n            for (int wi = 0; wi < Mask::W; wi++) m[wi] |= fieldPls[k][p].mask.w[wi];\n        }\n        return m;\n    }\n\n    vector<int> mask_to_cells(const array<uint64_t, Mask::W>& m) const {\n        vector<int> cells;\n        cells.reserve(n2);\n        for (int wi = 0; wi < Mask::W; wi++) {\n            uint64_t bits = m[wi];\n            while (bits) {\n                int b = __builtin_ctzll(bits);\n                int idx = wi * 64 + b;\n                if (idx < n2) cells.push_back(idx);\n                bits &= bits - 1;\n            }\n        }\n        return cells;\n    }\n\n    bool can_afford_guess(int safety = 2) const {\n        int maxOps = 2 * n2;\n        int unknown = n2 - (int)queryVals.size();\n        return (maxOps - ops) > (unknown + safety);\n    }\n\n    int submit_guess_mask(array<uint64_t, Mask::W> m) {\n        normalize_mask(m);\n        if (is_forbidden(m)) return -1;\n\n        vector<int> cells = mask_to_cells(m);\n        int res = ask_answer(cells);\n        ops++;\n\n        if (res == 1) return 1;\n        wrongGuesses++;\n        add_forbidden(m);\n        return 0;\n    }\n\n    void fill_all_domains(vector<vector<int>>& domains) const {\n        domains.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            domains[k].resize(fieldPls[k].size());\n            iota(domains[k].begin(), domains[k].end(), 0);\n        }\n    }\n\n    bool verify_assignment_full(const vector<int>& asg) const {\n        vector<int> rem = queryVals;\n        for (int k = 0; k < M; k++) {\n            int p = asg[k];\n            if (p < 0) return false;\n            for (int idx : fieldPls[k][p].cells) {\n                int qid = qidOfCell[idx];\n                if (qid != -1) rem[qid]--;\n            }\n        }\n        for (int v : rem) if (v != 0) return false;\n        return true;\n    }\n\n    bool propagate_domains(vector<vector<int>>& domains) {\n        domains.assign(M, {});\n        int q = (int)queryVals.size();\n\n        if (q == 0) {\n            fill_all_domains(domains);\n            return true;\n        }\n\n        vector<vector<uint8_t>> active(M);\n        for (int k = 0; k < M; k++) active[k].assign(fieldPls[k].size(), 1);\n\n        int maxIt = 10;\n        if (q > 80)  maxIt = 7;\n        if (q > 160) maxIt = 5;\n        if (q > 260) maxIt = 3;\n        if (elapsed_ms() > 2300.0) maxIt = min(maxIt, 2);\n\n        for (int it = 0; it < maxIt; it++) {\n            if (elapsed_ms() > HARD_LIMIT_MS - 140.0) break;\n\n            vector<int> domSize(M, 0);\n            vector<vector<int>> cnt1(M, vector<int>(q, 0));\n\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    domSize[k]++;\n                    const auto& qc = pls[p].qcov;\n                    for (int r = 0; r < q; r++) cnt1[k][r] += qc[r];\n                }\n            }\n\n            for (int k = 0; k < M; k++) if (domSize[k] == 0) return false;\n\n            vector<vector<int8_t>> minv(M, vector<int8_t>(q, 0));\n            vector<vector<int8_t>> maxv(M, vector<int8_t>(q, 0));\n            vector<int> totalMin(q, 0), totalMax(q, 0);\n\n            for (int r = 0; r < q; r++) {\n                int tmin = 0, tmax = 0;\n                for (int k = 0; k < M; k++) {\n                    bool has1 = cnt1[k][r] > 0;\n                    bool has0 = (domSize[k] - cnt1[k][r]) > 0;\n                    int mn = has0 ? 0 : 1;\n                    int mx = has1 ? 1 : 0;\n                    minv[k][r] = (int8_t)mn;\n                    maxv[k][r] = (int8_t)mx;\n                    tmin += mn;\n                    tmax += mx;\n                }\n                totalMin[r] = tmin;\n                totalMax[r] = tmax;\n                int y = queryVals[r];\n                if (y < tmin || y > tmax) return false;\n            }\n\n            bool changed = false;\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    const auto& qc = pls[p].qcov;\n                    bool ok = true;\n                    for (int r = 0; r < q; r++) {\n                        int need = queryVals[r] - (int)qc[r];\n                        int lo = totalMin[r] - (int)minv[k][r];\n                        int hi = totalMax[r] - (int)maxv[k][r];\n                        if (need < lo || need > hi) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) {\n                        active[k][p] = 0;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        for (int k = 0; k < M; k++) {\n            for (int p = 0; p < (int)fieldPls[k].size(); p++) if (active[k][p]) domains[k].push_back(p);\n            if (domains[k].empty()) return false;\n        }\n        return true;\n    }\n\n    vector<int> choose_used_constraints(int maxUsed) {\n        int q = (int)queryVals.size();\n        vector<int> used;\n        if (q <= maxUsed) {\n            used.resize(q);\n            iota(used.begin(), used.end(), 0);\n            return used;\n        }\n\n        vector<int> pos, zero;\n        pos.reserve(q);\n        zero.reserve(q);\n\n        for (int r = 0; r < q; r++) {\n            if (queryVals[r] > 0) pos.push_back(r);\n            else zero.push_back(r);\n        }\n\n        shuffle(pos.begin(), pos.end(), rng);\n        shuffle(zero.begin(), zero.end(), rng);\n\n        // prioritize positive cells (usually informative)\n        int keepPos = min((int)pos.size(), maxUsed * 3 / 4);\n        for (int i = 0; i < keepPos; i++) used.push_back(pos[i]);\n\n        int rem = maxUsed - (int)used.size();\n        int takeZero = min(rem, (int)zero.size());\n        for (int i = 0; i < takeZero; i++) used.push_back(zero[i]);\n        rem = maxUsed - (int)used.size();\n\n        int pidx = keepPos;\n        while (rem > 0 && pidx < (int)pos.size()) {\n            used.push_back(pos[pidx++]);\n            rem--;\n        }\n\n        int zidx = takeZero;\n        while (rem > 0 && zidx < (int)zero.size()) {\n            used.push_back(zero[zidx++]);\n            rem--;\n        }\n\n        return used;\n    }\n\n    vector<vector<int>> sample_solutions(const vector<vector<int>>& domains, int maxSol, long long nodeLimit, int baseTimeMs) {\n        vector<vector<int>> sols;\n        if (maxSol <= 0) return sols;\n\n        int qFull = (int)queryVals.size();\n        if (elapsed_ms() > HARD_LIMIT_MS - 120.0) return sols;\n\n        double remGlobal = HARD_LIMIT_MS - elapsed_ms();\n        if (remGlobal < 18.0) return sols;\n        int timeMs = min(baseTimeMs, (int)max(6.0, remGlobal - 10.0));\n        auto deadline = chrono::steady_clock::now() + chrono::milliseconds(timeMs);\n\n        if (qFull == 0) {\n            int trials = maxSol * 5;\n            for (int t = 0; t < trials && (int)sols.size() < maxSol; t++) {\n                vector<int> asg(M, -1);\n                for (int k = 0; k < M; k++) {\n                    const auto& d = domains[k];\n                    asg[k] = d[rng() % d.size()];\n                }\n                auto m = build_union_mask(asg);\n                normalize_mask(m);\n                if (is_forbidden(m)) continue;\n                sols.push_back(move(asg));\n            }\n            return sols;\n        }\n\n        const int Q_USED_MAX = 140;\n        vector<int> used = choose_used_constraints(min(qFull, Q_USED_MAX));\n        int q = (int)used.size();\n\n        vector<vector<int8_t>> varMin(M, vector<int8_t>(q, 0));\n        vector<vector<int8_t>> varMax(M, vector<int8_t>(q, 0));\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            vector<int> c1(q, 0);\n\n            for (int p : domains[k]) {\n                const auto& qc = fieldPls[k][p].qcov;\n                for (int r = 0; r < q; r++) c1[r] += qc[used[r]];\n            }\n\n            for (int r = 0; r < q; r++) {\n                bool has1 = c1[r] > 0;\n                bool has0 = (ds - c1[r]) > 0;\n                varMin[k][r] = has0 ? 0 : 1;\n                varMax[k][r] = has1 ? 1 : 0;\n            }\n        }\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (domains[a].size() != domains[b].size()) return domains[a].size() < domains[b].size();\n            return a < b;\n        });\n\n        vector<vector<int>> sufMin(M + 1, vector<int>(q, 0));\n        vector<vector<int>> sufMax(M + 1, vector<int>(q, 0));\n        for (int d = M - 1; d >= 0; d--) {\n            int k = order[d];\n            for (int r = 0; r < q; r++) {\n                sufMin[d][r] = sufMin[d + 1][r] + (int)varMin[k][r];\n                sufMax[d][r] = sufMax[d + 1][r] + (int)varMax[k][r];\n            }\n        }\n\n        vector<int> target(q, 0);\n        for (int r = 0; r < q; r++) target[r] = queryVals[used[r]];\n\n        for (int r = 0; r < q; r++) {\n            if (target[r] < sufMin[0][r] || target[r] > sufMax[0][r]) return sols;\n        }\n\n        vector<vector<int>> domOrd = domains;\n        vector<int> assign(M, -1);\n\n        long long nodes = 0;\n        bool stop = false;\n\n        auto over = [&]() -> bool {\n            if (nodes > nodeLimit) return true;\n            if (chrono::steady_clock::now() >= deadline) return true;\n            if (elapsed_ms() > HARD_LIMIT_MS - 35.0) return true;\n            return false;\n        };\n\n        function<void(int)> dfs = [&](int depth) {\n            if (stop || (int)sols.size() >= maxSol) return;\n\n            if (depth == M) {\n                for (int r = 0; r < q; r++) if (target[r] != 0) return;\n                if (!verify_assignment_full(assign)) return;\n                auto m = build_union_mask(assign);\n                normalize_mask(m);\n                if (!is_forbidden(m)) sols.push_back(assign);\n                return;\n            }\n\n            int k = order[depth];\n            auto& plist = domOrd[k];\n\n            for (int p : plist) {\n                nodes++;\n                if ((nodes & 1023LL) == 0 && over()) {\n                    stop = true;\n                    return;\n                }\n\n                const auto& qc = fieldPls[k][p].qcov;\n                bool ok = true;\n                for (int r = 0; r < q; r++) {\n                    int nt = target[r] - (int)qc[used[r]];\n                    if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (!ok) continue;\n\n                assign[k] = p;\n                for (int r = 0; r < q; r++) target[r] -= (int)qc[used[r]];\n                dfs(depth + 1);\n                for (int r = 0; r < q; r++) target[r] += (int)qc[used[r]];\n\n                if (stop || (int)sols.size() >= maxSol) return;\n            }\n\n            assign[k] = -1;\n        };\n\n        int restarts = 0;\n        while (!stop && (int)sols.size() < maxSol && restarts < 4) {\n            for (int k = 0; k < M; k++) {\n                if (domOrd[k].size() > 1) shuffle(domOrd[k].begin(), domOrd[k].end(), rng);\n            }\n            fill(assign.begin(), assign.end(), -1);\n            for (int r = 0; r < q; r++) target[r] = queryVals[used[r]];\n            dfs(0);\n            restarts++;\n        }\n\n        // randomized constructive fallback\n        if ((int)sols.size() < max(4, maxSol / 4) && chrono::steady_clock::now() < deadline) {\n            int attempts = 100;\n            for (int at = 0; at < attempts && (int)sols.size() < maxSol; at++) {\n                if (chrono::steady_clock::now() >= deadline) break;\n\n                vector<int> t(q, 0);\n                for (int r = 0; r < q; r++) t[r] = queryVals[used[r]];\n                vector<int> asg(M, -1);\n                bool fail = false;\n\n                for (int depth = 0; depth < M; depth++) {\n                    int k = order[depth];\n                    int chosen = -1;\n                    int feasCnt = 0;\n\n                    for (int p : domOrd[k]) {\n                        const auto& qc = fieldPls[k][p].qcov;\n                        bool ok = true;\n                        for (int r = 0; r < q; r++) {\n                            int nt = t[r] - (int)qc[used[r]];\n                            if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                                ok = false;\n                                break;\n                            }\n                        }\n                        if (!ok) continue;\n                        feasCnt++;\n                        if ((int)(rng() % feasCnt) == 0) chosen = p;\n                    }\n\n                    if (chosen == -1) {\n                        fail = true;\n                        break;\n                    }\n\n                    asg[k] = chosen;\n                    const auto& qc = fieldPls[k][chosen].qcov;\n                    for (int r = 0; r < q; r++) t[r] -= (int)qc[used[r]];\n                }\n\n                if (fail) continue;\n                bool exactSub = true;\n                for (int r = 0; r < q; r++) if (t[r] != 0) { exactSub = false; break; }\n                if (!exactSub) continue;\n\n                if (!verify_assignment_full(asg)) continue;\n\n                auto m = build_union_mask(asg);\n                normalize_mask(m);\n                if (is_forbidden(m)) continue;\n                sols.push_back(move(asg));\n            }\n        }\n\n        return sols;\n    }\n\n    vector<UnionCand> build_union_candidates(const vector<vector<int>>& sols, vector<int>& freq, int& totalCnt) {\n        unordered_map<array<uint64_t, Mask::W>, int, ArrHash> mp;\n        mp.reserve(sols.size() * 2 + 1);\n\n        vector<UnionCand> cands;\n        for (auto const& asg : sols) {\n            auto m = build_union_mask(asg);\n            normalize_mask(m);\n            if (is_forbidden(m)) continue;\n\n            auto it = mp.find(m);\n            if (it == mp.end()) {\n                int id = (int)cands.size();\n                mp.emplace(m, id);\n                UnionCand uc;\n                uc.m = m;\n                uc.cnt = 1;\n                cands.push_back(move(uc));\n            } else {\n                cands[it->second].cnt++;\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [&](const UnionCand& a, const UnionCand& b) {\n            return a.cnt > b.cnt;\n        });\n\n        totalCnt = 0;\n        for (auto& c : cands) totalCnt += c.cnt;\n\n        freq.assign(n2, 0);\n        if (totalCnt == 0) return cands;\n\n        for (auto const& c : cands) {\n            int add = c.cnt;\n            for (int wi = 0; wi < Mask::W; wi++) {\n                uint64_t bits = c.m[wi];\n                while (bits) {\n                    int b = __builtin_ctzll(bits);\n                    int idx = wi * 64 + b;\n                    if (idx < n2) freq[idx] += add;\n                    bits &= bits - 1;\n                }\n            }\n        }\n\n        return cands;\n    }\n\n    int choose_uncertain_cell(const vector<int>& freq, int total) const {\n        if (total <= 0) return -1;\n        int best = -1;\n        double bestScore = -1.0;\n\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            int f = freq[idx];\n            if (f == 0 || f == total) continue;\n            double p = (double)f / (double)total;\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    int choose_entropy_cell(const vector<vector<int>>& domains) const {\n        vector<double> p0(n2, 1.0);\n        vector<int> cnt(n2, 0);\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            if (ds <= 0) continue;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            for (int p : domains[k]) {\n                for (int idx : fieldPls[k][p].cells) cnt[idx]++;\n            }\n\n            double inv = 1.0 / (double)ds;\n            for (int idx = 0; idx < n2; idx++) {\n                if (drilledVal[idx] != -1) continue;\n                if (cnt[idx] == 0) continue;\n                double pk = cnt[idx] * inv;\n                p0[idx] *= (1.0 - pk);\n            }\n        }\n\n        int best = -1;\n        double bestScore = -1.0;\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            double p = 1.0 - p0[idx];\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    int infer_interval(int drilled) const {\n        if (drilled < 60)  return 1;\n        if (drilled < 140) return 2;\n        if (drilled < 220) return 4;\n        if (drilled < 300) return 6;\n        return 9;\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        const int maxOps = 2 * n2;\n        int turn = 0;\n\n        while (ops < maxOps) {\n            turn++;\n            int drilledCnt = (int)queryVals.size();\n            int unknown = n2 - drilledCnt;\n\n            if (unknown == 0) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    (void)res;\n                }\n                return;\n            }\n\n            double now = elapsed_ms();\n            bool emergency = (now > EMERGENCY_MS || now > HARD_LIMIT_MS - 70.0);\n\n            int next = -1;\n\n            if (!emergency) {\n                int interval = infer_interval(drilledCnt);\n                bool doInference = (drilledCnt < 20) || (turn % interval == 0);\n\n                if (doInference) {\n                    vector<vector<int>> domains;\n                    bool feasible = propagate_domains(domains);\n\n                    if (!feasible) {\n                        next = first_unknown_cell();\n                    } else {\n                        // unique placement per field => direct guess candidate\n                        bool unique = true;\n                        vector<int> uniqAsg(M, -1);\n                        for (int k = 0; k < M; k++) {\n                            if (domains[k].size() != 1) {\n                                unique = false;\n                                break;\n                            }\n                            uniqAsg[k] = domains[k][0];\n                        }\n                        if (unique && can_afford_guess(2) && wrongGuesses < MAX_WRONG_GUESSES) {\n                            int r = submit_guess_mask(build_union_mask(uniqAsg));\n                            if (r == 1) return;\n                            if (r == 0) continue;\n                        }\n\n                        next = choose_entropy_cell(domains);\n\n                        // sampling\n                        if (drilledCnt >= 4 && elapsed_ms() < 2500.0) {\n                            double rem = HARD_LIMIT_MS - elapsed_ms();\n                            if (rem > 18.0) {\n                                int maxSol = 40, tMs = 12;\n                                long long nodeLim = 240000;\n\n                                if (drilledCnt < 40) {\n                                    maxSol = 40; nodeLim = 250000; tMs = 14;\n                                } else if (drilledCnt < 120) {\n                                    maxSol = 60; nodeLim = 500000; tMs = 20;\n                                } else if (drilledCnt < 220) {\n                                    maxSol = 55; nodeLim = 450000; tMs = 16;\n                                } else {\n                                    maxSol = 40; nodeLim = 260000; tMs = 10;\n                                }\n\n                                tMs = min(tMs, (int)max(6.0, rem * 0.18));\n\n                                auto sols = sample_solutions(domains, maxSol, nodeLim, tMs);\n\n                                if (!sols.empty()) {\n                                    vector<int> freq;\n                                    int total = 0;\n                                    auto cands = build_union_candidates(sols, freq, total);\n\n                                    if (total > 0) {\n                                        double p0 = (double)cands[0].cnt / (double)total;\n                                        bool madeGuess = false;\n\n                                        if (can_afford_guess(2) && wrongGuesses < MAX_WRONG_GUESSES) {\n                                            bool g1 = false;\n                                            if ((int)cands.size() == 1 && total >= 3) g1 = true;\n                                            else if (p0 >= 0.88 && total >= 8) g1 = true;\n                                            else if (p0 >= 0.78 && total >= 12 && drilledCnt >= 10) g1 = true;\n                                            else if (p0 >= 0.66 && total >= 20 && drilledCnt >= 24) g1 = true;\n\n                                            if (g1) {\n                                                int r = submit_guess_mask(cands[0].m);\n                                                if (r == 1) return;\n                                                if (r == 0) madeGuess = true;\n                                            }\n\n                                            // late aggressive burst: try top-2 if candidate set small\n                                            if (!madeGuess && drilledCnt >= 140 && unknown >= 80 && (int)cands.size() <= 3) {\n                                                int tries = min(2, (int)cands.size());\n                                                for (int ci = 0; ci < tries; ci++) {\n                                                    double pp = (double)cands[ci].cnt / (double)total;\n                                                    if (pp < 0.20) break;\n                                                    if (!can_afford_guess(2) || wrongGuesses >= MAX_WRONG_GUESSES) break;\n                                                    int r = submit_guess_mask(cands[ci].m);\n                                                    if (r == 1) return;\n                                                    if (r == 0) madeGuess = true;\n                                                }\n                                            }\n                                        }\n\n                                        if (madeGuess) continue;\n\n                                        int u = choose_uncertain_cell(freq, total);\n                                        if (u != -1) next = u;\n                                        else if (next == -1) next = choose_entropy_cell(domains);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (next == -1) {\n                int f = pick_frontier_cell();\n                if (f != -1) next = f;\n            }\n\n            if (next == -1) {\n                if (drilledCnt < min(8, N)) next = pick_prior_cell();\n                if (next == -1) next = pick_prior_cell();\n            }\n\n            if (next == -1) next = first_unknown_cell();\n\n            if (next == -1) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    if (res == 1) return;\n                }\n                return;\n            }\n\n            int v = ask_drill(next);\n            ops++;\n            add_drill(next, v);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    OilSolver solver;\n    solver.read_input();\n    solver.build_placements();\n    solver.build_prior_order();\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\nusing ll = long long;\n\nstruct Iseg {\n    int c, l, r; // coordinate c, interval [l,r)\n    bool operator==(const Iseg& o) const { return c == o.c && l == o.l && r == o.r; }\n};\n\nstruct Candidate {\n    vector<array<int, 4>> rects; // by request rank k\n    vector<Iseg> hsegs;          // y=c, x in [l,r)\n    vector<Iseg> vsegs;          // x=c, y in [l,r)\n    vector<int> areas;           // sorted cell areas\n    ll shortage = 0;             // day-dependent\n    int boundaryLen = 0;         // shape-dependent\n    uint64_t hash = 0;           // shape hash\n    unsigned char src = 0;       // 1: local, 2: global proto, 4: path proto\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 shape_hash(const vector<Iseg>& H, const vector<Iseg>& V) {\n    uint64_t h = 0x123456789abcdefULL;\n    auto add = [&](uint64_t v) {\n        h ^= splitmix64(v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));\n    };\n    add((uint64_t)H.size() + 0x11111111ULL);\n    for (auto& s : H) {\n        uint64_t p = ((uint64_t)s.c << 22) ^ ((uint64_t)s.l << 11) ^ (uint64_t)s.r;\n        add((p << 1) | 1ULL);\n    }\n    add(0xfedcba987654321ULL);\n    add((uint64_t)V.size() + 0x22222222ULL);\n    for (auto& s : V) {\n        uint64_t p = ((uint64_t)s.c << 22) ^ ((uint64_t)s.l << 11) ^ (uint64_t)s.r;\n        add((p << 1) | 0ULL);\n    }\n    return h;\n}\n\nstatic vector<Iseg> merge_segments(vector<Iseg> segs) {\n    sort(segs.begin(), segs.end(), [](const Iseg& a, const Iseg& b) {\n        if (a.c != b.c) return a.c < b.c;\n        if (a.l != b.l) return a.l < b.l;\n        return a.r < b.r;\n    });\n    vector<Iseg> out;\n    out.reserve(segs.size());\n    for (auto& s : segs) {\n        if (s.l >= s.r) continue;\n        if (out.empty() || out.back().c != s.c || s.l > out.back().r) {\n            out.push_back(s);\n        } else {\n            out.back().r = max(out.back().r, s.r);\n        }\n    }\n    return out;\n}\n\nstatic inline ll rect_area(const array<int, 4>& r) {\n    return 1LL * (r[2] - r[0]) * (r[3] - r[1]);\n}\n\nstatic ll calc_shortage(const vector<int>& dayA, const vector<int>& areasSorted) {\n    ll sh = 0;\n    int N = (int)dayA.size();\n    for (int k = 0; k < N; k++) {\n        if (areasSorted[k] < dayA[k]) sh += 100LL * (dayA[k] - areasSorted[k]);\n    }\n    return sh;\n}\n\n// Build candidate from arbitrary cells (size N), assigning by area order -> request rank.\nstatic Candidate build_candidate_from_cells(\n    int W,\n    const vector<int>& dayA,\n    const vector<array<int, 4>>& cells,\n    unsigned char src = 1\n) {\n    int N = (int)dayA.size();\n    Candidate c;\n    c.src = src;\n    c.rects.resize(N);\n    c.areas.resize(N);\n\n    vector<pair<ll, int>> ord;\n    ord.reserve(N);\n    for (int i = 0; i < N; i++) ord.push_back({rect_area(cells[i]), i});\n    sort(ord.begin(), ord.end(), [](auto& a, auto& b) {\n        if (a.first != b.first) return a.first < b.first;\n        return a.second < b.second;\n    });\n\n    for (int k = 0; k < N; k++) {\n        c.rects[k] = cells[ord[k].second];\n        c.areas[k] = (int)ord[k].first;\n    }\n    c.shortage = calc_shortage(dayA, c.areas);\n\n    vector<Iseg> rawH, rawV;\n    rawH.reserve(2 * N);\n    rawV.reserve(2 * N);\n\n    for (auto& rc : cells) {\n        int y0 = rc[0], x0 = rc[1], y1 = rc[2], x1 = rc[3];\n        if (y0 > 0) rawH.push_back({y0, x0, x1});\n        if (y1 < W) rawH.push_back({y1, x0, x1});\n        if (x0 > 0) rawV.push_back({x0, y0, y1});\n        if (x1 < W) rawV.push_back({x1, y0, y1});\n    }\n\n    c.hsegs = merge_segments(move(rawH));\n    c.vsegs = merge_segments(move(rawV));\n\n    ll bl = 0;\n    for (auto& s : c.hsegs) bl += (s.r - s.l);\n    for (auto& s : c.vsegs) bl += (s.r - s.l);\n    c.boundaryLen = (int)bl;\n\n    c.hash = shape_hash(c.hsegs, c.vsegs);\n    return c;\n}\n\nstatic Candidate clone_for_day(const Candidate& proto, const vector<int>& dayA, unsigned char srcOverride = 0) {\n    Candidate c = proto;\n    c.shortage = calc_shortage(dayA, c.areas);\n    if (srcOverride) c.src = srcOverride;\n    return c;\n}\n\nstatic Candidate transpose_candidate(const Candidate& base, int W, const vector<int>& dayA, unsigned char srcOverride = 0) {\n    (void)W;\n    vector<array<int, 4>> cells = base.rects;\n    for (auto& r : cells) {\n        swap(r[0], r[1]);\n        swap(r[2], r[3]);\n    }\n    return build_candidate_from_cells(W, dayA, cells, srcOverride ? srcOverride : base.src);\n}\n\nstatic bool same_shape(const Candidate& a, const Candidate& b) {\n    if (a.hash != b.hash) return false;\n    return a.hsegs == b.hsegs && a.vsegs == b.vsegs;\n}\n\nstatic ll symdiff_len(const vector<Iseg>& A, const vector<Iseg>& B) {\n    ll cost = 0;\n    int i = 0, j = 0;\n    while (i < (int)A.size() || j < (int)B.size()) {\n        int c;\n        if (j == (int)B.size() || (i < (int)A.size() && A[i].c < B[j].c)) c = A[i].c;\n        else c = B[j].c;\n\n        int i0 = i, j0 = j;\n        while (i < (int)A.size() && A[i].c == c) i++;\n        while (j < (int)B.size() && B[j].c == c) j++;\n\n        ll lenA = 0, lenB = 0;\n        for (int p = i0; p < i; p++) lenA += (A[p].r - A[p].l);\n        for (int q = j0; q < j; q++) lenB += (B[q].r - B[q].l);\n\n        ll inter = 0;\n        int p = i0, q = j0;\n        while (p < i && q < j) {\n            int L = max(A[p].l, B[q].l);\n            int R = min(A[p].r, B[q].r);\n            if (R > L) inter += (R - L);\n            if (A[p].r < B[q].r) p++;\n            else q++;\n        }\n        cost += lenA + lenB - 2LL * inter;\n    }\n    return cost;\n}\n\nstatic inline ll transition_cost(const Candidate& A, const Candidate& B) {\n    return symdiff_len(A.hsegs, B.hsegs) + symdiff_len(A.vsegs, B.vsegs);\n}\n\nstatic int min_height_segment(const vector<int>& arr, int l, int r, int W) {\n    auto ok = [&](int h) -> bool {\n        ll sw = 0;\n        for (int i = l; i < r; i++) {\n            sw += (arr[i] + h - 1) / h;\n            if (sw > W) return false;\n        }\n        return true;\n    };\n    if (!ok(W)) return W + 1;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (ok(mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nstatic int closest_feasible(const vector<int>& feasible, int t) {\n    auto it = lower_bound(feasible.begin(), feasible.end(), t);\n    if (it == feasible.begin()) return *it;\n    if (it == feasible.end()) return feasible.back();\n    int a = *it, b = *prev(it);\n    return (abs(a - t) < abs(b - t)) ? a : b;\n}\n\nstatic vector<int> sample_rows(const vector<int>& feasible, int cap) {\n    if (feasible.empty()) return {};\n    if ((int)feasible.size() <= cap) return feasible;\n    cap = max(cap, 1);\n\n    set<int> S;\n    auto add_target = [&](int t) { S.insert(closest_feasible(feasible, t)); };\n\n    add_target(1); add_target(2); add_target(3); add_target(4); add_target(5); add_target(8);\n    add_target(feasible.back());\n\n    int m = (int)feasible.size();\n    for (int i = 0; i < cap; i++) {\n        int idx = (int)(1LL * i * (m - 1) / max(1, cap - 1));\n        S.insert(feasible[idx]);\n    }\n\n    vector<int> ret(S.begin(), S.end());\n    if ((int)ret.size() > cap) {\n        vector<int> tmp;\n        for (int i = 0; i < cap; i++) {\n            int idx = (int)(1LL * i * ((int)ret.size() - 1) / max(1, cap - 1));\n            tmp.push_back(ret[idx]);\n        }\n        sort(tmp.begin(), tmp.end());\n        tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());\n        ret.swap(tmp);\n    }\n    return ret;\n}\n\nstatic vector<int> snapped_variant(const vector<int>& hmin, int slack, int W, int Q, int mode) {\n    int rr = (int)hmin.size();\n    vector<int> pref(rr + 1, 0);\n    for (int i = 0; i < rr; i++) pref[i + 1] = pref[i] + hmin[i];\n\n    vector<int> inc(rr + 1, 0);\n    inc[0] = 0;\n    inc[rr] = slack;\n\n    int prev = 0;\n    for (int t = 1; t < rr; t++) {\n        int p = pref[t];\n        int targetY;\n        if (mode == 0) {\n            targetY = ((p + Q - 1) / Q) * Q;\n        } else {\n            int ideal = (int)llround((double)W * t / rr);\n            int dn = (ideal / Q) * Q;\n            int up = ((ideal + Q - 1) / Q) * Q;\n            targetY = (abs(ideal - dn) <= abs(up - ideal) ? dn : up);\n            if (targetY < p) targetY = ((p + Q - 1) / Q) * Q;\n        }\n        int des = targetY - p;\n        des = max(des, prev);\n        des = min(des, slack);\n        inc[t] = des;\n        prev = des;\n    }\n\n    for (int t = rr - 1; t >= 1; t--) inc[t] = min(inc[t], inc[t + 1]);\n    for (int t = 1; t <= rr; t++) inc[t] = max(inc[t], inc[t - 1]);\n    inc[rr] = slack;\n\n    vector<int> h(rr);\n    for (int g = 0; g < rr; g++) h[g] = hmin[g] + (inc[g + 1] - inc[g]);\n    return h;\n}\n\nstatic vector<int> random_variant(const vector<int>& hmin, int slack, uint64_t seed) {\n    int rr = (int)hmin.size();\n    mt19937_64 rng(seed);\n\n    vector<int> cuts(rr + 1, 0);\n    cuts[0] = 0;\n    cuts[rr] = slack;\n    uniform_int_distribution<int> dist(0, slack);\n    for (int i = 1; i < rr; i++) cuts[i] = dist(rng);\n    sort(cuts.begin(), cuts.end());\n\n    vector<int> h(rr);\n    for (int g = 0; g < rr; g++) h[g] = hmin[g] + (cuts[g + 1] - cuts[g]);\n    return h;\n}\n\nstatic void add_var_unique(vector<vector<int>>& vars, const vector<int>& v) {\n    if (v.empty()) return;\n    for (auto& u : vars) if (u == v) return;\n    vars.push_back(v);\n}\n\nstatic void add_split_unique(vector<vector<int>>& splits, const vector<int>& sp) {\n    for (auto& u : splits) if (u == sp) return;\n    splits.push_back(sp);\n}\n\nstatic void apply_width_mode(vector<int>& w, int slack, int mode) {\n    int m = (int)w.size();\n    if (m == 0 || slack <= 0) return;\n    if (m == 1) {\n        w[0] += slack;\n        return;\n    }\n\n    if (mode == 0) {\n        w[m - 1] += slack; // all to last\n    } else if (mode == 1) {\n        w[0] += slack; // all to first\n    } else if (mode == 2) {\n        int q = slack / m, rem = slack % m;\n        for (int i = 0; i < m; i++) w[i] += q + (i < rem ? 1 : 0);\n    } else { // proportional\n        ll sumw = 0;\n        for (int x : w) sumw += x;\n        if (sumw <= 0) {\n            w[m - 1] += slack;\n            return;\n        }\n        vector<pair<ll, int>> frac;\n        frac.reserve(m);\n        int used = 0;\n        for (int i = 0; i < m; i++) {\n            ll num = 1LL * slack * w[i];\n            int add = (int)(num / sumw);\n            ll fr = num % sumw;\n            w[i] += add;\n            used += add;\n            frac.push_back({fr, i});\n        }\n        int rem = slack - used;\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        for (int t = 0; t < rem; t++) w[frac[t % m].second]++;\n    }\n}\n\n// Build shelf cells from split+heights+global width mode.\nstatic bool build_cells_from_split_heights(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    const vector<int>& split,\n    const vector<int>& heights,\n    int widthMode,\n    vector<array<int, 4>>& cells\n) {\n    int rr = (int)heights.size();\n    int N = (int)dayA.size();\n    if ((int)split.size() != rr + 1 || split[0] != 0 || split[rr] != N) return false;\n\n    int sumH = 0;\n    for (int h : heights) {\n        if (h <= 0) return false;\n        sumH += h;\n    }\n    if (sumH != W) return false;\n\n    cells.clear();\n    cells.reserve(N);\n\n    int y = 0;\n    for (int g = 0; g < rr; g++) {\n        int l = split[g], r = split[g + 1];\n        if (!(l < r)) return false;\n        int h = heights[g];\n\n        vector<int> minw;\n        minw.reserve(r - l);\n        int sumMin = 0;\n        for (int t = l; t < r; t++) {\n            int req = dayA[ord[t]];\n            int mw = (req + h - 1) / h;\n            if (mw <= 0) return false;\n            minw.push_back(mw);\n            sumMin += mw;\n            if (sumMin > W) return false;\n        }\n\n        int slack = W - sumMin;\n        vector<int> widths = minw;\n        apply_width_mode(widths, slack, widthMode);\n\n        int x = 0;\n        for (int i = 0; i < (int)widths.size(); i++) {\n            int ww = widths[i];\n            if (ww <= 0) return false;\n            cells.push_back({y, x, y + h, x + ww});\n            x += ww;\n        }\n        if (x != W) return false;\n        y += h;\n    }\n    if (y != W) return false;\n    return (int)cells.size() == N;\n}\n\nstatic vector<Candidate> generate_shelf_one_order(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    int capRows,\n    const vector<int>& widthModes\n) {\n    int N = (int)dayA.size();\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    vector<vector<int>> htab(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            htab[l][r] = min_height_segment(arr, l, r, W);\n        }\n    }\n\n    const int INF = 1e9;\n    vector<vector<int>> dp(N + 1, vector<int>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int rr = 1; rr <= N; rr++) {\n        for (int i = 1; i <= N; i++) {\n            int best = INF, bestj = -1;\n            for (int j = 0; j < i; j++) {\n                if (dp[rr - 1][j] == INF) continue;\n                int h = htab[j][i];\n                if (h > W) continue;\n                int v = dp[rr - 1][j] + h;\n                if (v < best || (v == best && j > bestj)) {\n                    best = v;\n                    bestj = j;\n                }\n            }\n            dp[rr][i] = best;\n            par[rr][i] = bestj;\n        }\n    }\n\n    vector<int> feasibleRows;\n    for (int rr = 1; rr <= N; rr++) if (dp[rr][N] <= W) feasibleRows.push_back(rr);\n    vector<int> selRows = sample_rows(feasibleRows, capRows);\n\n    vector<Candidate> out;\n    out.reserve(selRows.size() * 24);\n\n    for (int rr : selRows) {\n        vector<int> split(rr + 1, 0);\n        split[rr] = N;\n        int cur = N;\n        bool ok = true;\n        for (int r = rr; r >= 1; r--) {\n            int j = par[r][cur];\n            if (j < 0) { ok = false; break; }\n            split[r - 1] = j;\n            cur = j;\n        }\n        if (!ok || split[0] != 0) continue;\n\n        vector<int> hmin(rr);\n        int sumMin = 0;\n        for (int g = 0; g < rr; g++) {\n            int l = split[g], r = split[g + 1];\n            hmin[g] = htab[l][r];\n            sumMin += hmin[g];\n        }\n        if (sumMin > W) continue;\n        int slack = W - sumMin;\n\n        vector<vector<int>> hvars;\n        {\n            vector<int> v = hmin;\n            v.back() += slack;\n            add_var_unique(hvars, v);\n        }\n        if (rr >= 2) {\n            vector<int> v = hmin;\n            v[0] += slack;\n            add_var_unique(hvars, v);\n        }\n        if (rr >= 2) {\n            vector<int> v = hmin;\n            int q = slack / rr, rem = slack % rr;\n            for (int g = 0; g < rr; g++) v[g] += q + (g < rem ? 1 : 0);\n            add_var_unique(hvars, v);\n        }\n        if (rr >= 3) {\n            vector<int> v = hmin;\n            v[rr / 2] += slack;\n            add_var_unique(hvars, v);\n        }\n\n        add_var_unique(hvars, snapped_variant(hmin, slack, W, 50, 0));\n        add_var_unique(hvars, snapped_variant(hmin, slack, W, 50, 1));\n        add_var_unique(hvars, snapped_variant(hmin, slack, W, 100, 1));\n\n        if (slack > 0 && rr >= 2) {\n            uint64_t seed = 1469598103934665603ULL ^ (uint64_t)rr;\n            for (int x : split) seed = splitmix64(seed ^ (uint64_t)(x + 0x9e37));\n            add_var_unique(hvars, random_variant(hmin, slack, seed ^ 1ULL));\n        }\n\n        vector<array<int, 4>> cells;\n        for (auto& hv : hvars) {\n            for (int wm : widthModes) {\n                if (build_cells_from_split_heights(W, dayA, ord, split, hv, wm, cells)) {\n                    out.push_back(build_candidate_from_cells(W, dayA, cells, 1));\n                }\n            }\n        }\n    }\n\n    return out;\n}\n\n// fixed row-height templates shared across days\nstatic vector<Candidate> generate_fixed_height_templates(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    const vector<vector<int>>& templates,\n    const vector<int>& widthModes,\n    unsigned char src = 1\n) {\n    int N = (int)dayA.size();\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    const int INFINT = 1e9;\n    const ll INF64 = (1LL << 60);\n\n    vector<Candidate> out;\n    vector<array<int, 4>> cells;\n\n    for (auto& hvec : templates) {\n        int rr = (int)hvec.size();\n        if (rr <= 0 || rr > N) continue;\n\n        int sumH = 0;\n        bool bad = false;\n        for (int h : hvec) {\n            if (h <= 0) bad = true;\n            sumH += h;\n        }\n        if (bad || sumH != W) continue;\n\n        // slack[g][l][i] for row g using segment [l,i)\n        vector<vector<vector<int>>> slack(rr, vector<vector<int>>(N + 1, vector<int>(N + 1, INFINT)));\n\n        for (int g = 0; g < rr; g++) {\n            int h = hvec[g];\n            for (int l = 0; l < N; l++) {\n                int sumw = 0;\n                for (int i = l + 1; i <= N; i++) {\n                    sumw += (arr[i - 1] + h - 1) / h;\n                    if (sumw > W) break;\n                    slack[g][l][i] = W - sumw;\n                }\n            }\n        }\n\n        // Reconstruct up to 2 splits: objective sum(slack^2), and sum(slack)\n        vector<vector<int>> splits;\n        for (int obj = 0; obj < 2; obj++) {\n            vector<vector<ll>> dp(rr + 1, vector<ll>(N + 1, INF64));\n            vector<vector<int>> par(rr + 1, vector<int>(N + 1, -1));\n            dp[0][0] = 0;\n\n            for (int g = 1; g <= rr; g++) {\n                for (int i = 1; i <= N; i++) {\n                    ll best = INF64;\n                    int bestj = -1;\n                    for (int j = 0; j < i; j++) {\n                        if (dp[g - 1][j] >= INF64 / 4) continue;\n                        int sl = slack[g - 1][j][i];\n                        if (sl >= INFINT) continue;\n                        ll add = (obj == 0 ? 1LL * sl * sl : 1LL * sl);\n                        ll val = dp[g - 1][j] + add;\n                        if (val < best || (val == best && j > bestj)) {\n                            best = val;\n                            bestj = j;\n                        }\n                    }\n                    dp[g][i] = best;\n                    par[g][i] = bestj;\n                }\n            }\n\n            if (dp[rr][N] >= INF64 / 4) continue;\n            vector<int> split(rr + 1, 0);\n            split[rr] = N;\n            int cur = N;\n            bool ok = true;\n            for (int g = rr; g >= 1; g--) {\n                int j = par[g][cur];\n                if (j < 0) { ok = false; break; }\n                split[g - 1] = j;\n                cur = j;\n            }\n            if (ok && split[0] == 0) add_split_unique(splits, split);\n        }\n\n        for (auto& split : splits) {\n            for (int wm : widthModes) {\n                if (build_cells_from_split_heights(W, dayA, ord, split, hvec, wm, cells)) {\n                    out.push_back(build_candidate_from_cells(W, dayA, cells, src));\n                }\n            }\n        }\n    }\n\n    return out;\n}\n\nstatic Candidate fallback_horizontal(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int y0 = (int)(1LL * W * k / N);\n        int y1 = (int)(1LL * W * (k + 1) / N);\n        cells.push_back({y0, 0, y1, W});\n    }\n    return build_candidate_from_cells(W, dayA, cells, 1);\n}\n\nstatic Candidate fallback_vertical(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int x0 = (int)(1LL * W * k / N);\n        int x1 = (int)(1LL * W * (k + 1) / N);\n        cells.push_back({0, x0, W, x1});\n    }\n    return build_candidate_from_cells(W, dayA, cells, 1);\n}\n\n// mode: 0 deterministic, 1 mild random, 2 stronger random\nstatic bool generate_guillotine_candidate(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    Candidate& outCand,\n    uint64_t seed,\n    int mode,\n    unsigned char src = 1\n) {\n    int N = (int)dayA.size();\n    vector<int> vals(N);\n    for (int i = 0; i < N; i++) vals[i] = dayA[ord[i]];\n\n    vector<ll> ps(N + 1, 0);\n    for (int i = 0; i < N; i++) ps[i + 1] = ps[i] + vals[i];\n\n    mt19937_64 rng(seed);\n\n    struct Opt {\n        int orient; // 0 vertical split, 1 horizontal split\n        int m, cut;\n        ll score;\n    };\n\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n\n    function<bool(int,int,int,int,int,int)> dfs = [&](int l, int r, int y0, int y1, int x0, int x1) -> bool {\n        if (r - l == 1) {\n            if (!(y0 < y1 && x0 < x1)) return false;\n            cells.push_back({y0, x0, y1, x1});\n            return true;\n        }\n\n        int h = y1 - y0, w = x1 - x0;\n        if (h <= 0 || w <= 0) return false;\n\n        ll S = ps[r] - ps[l];\n        if (S <= 0) return false;\n\n        int pref = (w >= h ? 0 : 1);\n        if (mode > 0 && (rng() & 1ULL)) pref ^= 1;\n\n        vector<Opt> opts;\n        opts.reserve((r - l - 1) * 4);\n\n        for (int pass = 0; pass < 2; pass++) {\n            int orient = (pass == 0 ? pref : (pref ^ 1));\n            for (int m = l + 1; m < r; m++) {\n                ll s1 = ps[m] - ps[l];\n                ll s2 = S - s1;\n\n                auto add_cut = [&](int cut, int orientFlag) {\n                    ll score;\n                    if (orientFlag == 0) {\n                        ll cap1 = 1LL * cut * h;\n                        ll cap2 = 1LL * (w - cut) * h;\n                        ll sl1 = cap1 - s1, sl2 = cap2 - s2;\n                        ll bal = llabs(2LL * (m - l) - (r - l));\n                        score = sl1 * sl1 + sl2 * sl2 + 4LL * bal;\n                    } else {\n                        ll cap1 = 1LL * cut * w;\n                        ll cap2 = 1LL * (h - cut) * w;\n                        ll sl1 = cap1 - s1, sl2 = cap2 - s2;\n                        ll bal = llabs(2LL * (m - l) - (r - l));\n                        score = sl1 * sl1 + sl2 * sl2 + 4LL * bal;\n                    }\n                    if (orientFlag != pref) score += 180;\n                    if (mode == 1) score += (ll)(rng() % 2500ULL);\n                    if (mode == 2) score += (ll)(rng() % 9000ULL);\n                    opts.push_back({orientFlag, m, cut, score});\n                };\n\n                if (orient == 0) {\n                    ll min1 = max(1LL, (s1 + h - 1) / h);\n                    ll min2 = max(1LL, (s2 + h - 1) / h);\n                    if (min1 + min2 > w) continue;\n                    int low = (int)min1, high = w - (int)min2;\n                    int c0 = (int)llround((double)w * (double)s1 / (double)S);\n                    c0 = max(low, min(high, c0));\n\n                    vector<int> cuts = {c0};\n                    if (mode >= 1) {\n                        int cm = (low + high) / 2;\n                        if (cm != c0) cuts.push_back(cm);\n                    }\n                    if (mode >= 2 && high - low >= 3) {\n                        int cr = low + (int)(rng() % (uint64_t)(high - low + 1));\n                        bool ex = false;\n                        for (int c : cuts) if (c == cr) ex = true;\n                        if (!ex) cuts.push_back(cr);\n                    }\n                    for (int cut : cuts) add_cut(cut, 0);\n\n                } else {\n                    ll min1 = max(1LL, (s1 + w - 1) / w);\n                    ll min2 = max(1LL, (s2 + w - 1) / w);\n                    if (min1 + min2 > h) continue;\n                    int low = (int)min1, high = h - (int)min2;\n                    int c0 = (int)llround((double)h * (double)s1 / (double)S);\n                    c0 = max(low, min(high, c0));\n\n                    vector<int> cuts = {c0};\n                    if (mode >= 1) {\n                        int cm = (low + high) / 2;\n                        if (cm != c0) cuts.push_back(cm);\n                    }\n                    if (mode >= 2 && high - low >= 3) {\n                        int cr = low + (int)(rng() % (uint64_t)(high - low + 1));\n                        bool ex = false;\n                        for (int c : cuts) if (c == cr) ex = true;\n                        if (!ex) cuts.push_back(cr);\n                    }\n                    for (int cut : cuts) add_cut(cut, 1);\n                }\n            }\n        }\n\n        if (opts.empty()) return false;\n        sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) { return a.score < b.score; });\n\n        int top = min<int>((mode == 0 ? 5 : 8), (int)opts.size());\n        vector<int> ordIdx(top);\n        iota(ordIdx.begin(), ordIdx.end(), 0);\n        if (mode > 0) shuffle(ordIdx.begin(), ordIdx.end(), rng);\n\n        int lim = min(top, 5);\n        for (int z = 0; z < lim; z++) {\n            const auto& op = opts[ordIdx[z]];\n            size_t old = cells.size();\n\n            bool ok = false;\n            if (op.orient == 0) {\n                int xm = x0 + op.cut;\n                ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                     dfs(op.m, r, y0, y1, xm, x1);\n            } else {\n                int ym = y0 + op.cut;\n                ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                     dfs(op.m, r, ym, y1, x0, x1);\n            }\n            if (ok) return true;\n            cells.resize(old);\n        }\n\n        if (mode > 0) {\n            int lim2 = min<int>(3, (int)opts.size());\n            for (int z = 0; z < lim2; z++) {\n                const auto& op = opts[z];\n                size_t old = cells.size();\n\n                bool ok = false;\n                if (op.orient == 0) {\n                    int xm = x0 + op.cut;\n                    ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                         dfs(op.m, r, y0, y1, xm, x1);\n                } else {\n                    int ym = y0 + op.cut;\n                    ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                         dfs(op.m, r, ym, y1, x0, x1);\n                }\n                if (ok) return true;\n                cells.resize(old);\n            }\n        }\n\n        return false;\n    };\n\n    bool ok = dfs(0, N, 0, W, 0, W);\n    if (!ok || (int)cells.size() != N) return false;\n    outCand = build_candidate_from_cells(W, dayA, cells, src);\n    return true;\n}\n\nstatic vector<Candidate> dedup_shape_only(vector<Candidate> pool) {\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n    unordered_map<uint64_t, vector<int>> mp;\n    mp.reserve(pool.size() * 2 + 1);\n\n    for (auto& c : pool) {\n        auto& vec = mp[c.hash];\n        bool merged = false;\n        for (int id : vec) {\n            if (same_shape(c, uniq[id])) {\n                unsigned char srcU = (unsigned char)(uniq[id].src | c.src);\n                bool better = false;\n                if (c.boundaryLen < uniq[id].boundaryLen) better = true;\n                else if (c.boundaryLen == uniq[id].boundaryLen && c.shortage < uniq[id].shortage) better = true;\n                if (better) {\n                    Candidate t = c;\n                    t.src = srcU;\n                    uniq[id] = move(t);\n                } else {\n                    uniq[id].src = srcU;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) {\n            vec.push_back((int)uniq.size());\n            uniq.push_back(move(c));\n        }\n    }\n    return uniq;\n}\n\nstatic void dedup_and_trim(vector<Candidate>& pool, int maxCand, int freeArea) {\n    if (pool.empty()) return;\n    maxCand = max(maxCand, 1);\n\n    // Dedup by shape\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n    unordered_map<uint64_t, vector<int>> mp;\n    mp.reserve(pool.size() * 2 + 1);\n\n    for (auto& c : pool) {\n        auto& vec = mp[c.hash];\n        bool merged = false;\n        for (int id : vec) {\n            if (same_shape(c, uniq[id])) {\n                unsigned char srcU = (unsigned char)(uniq[id].src | c.src);\n                bool better = false;\n                if (c.shortage < uniq[id].shortage) better = true;\n                else if (c.shortage == uniq[id].shortage && c.boundaryLen < uniq[id].boundaryLen) better = true;\n                if (better) {\n                    Candidate t = c;\n                    t.src = srcU;\n                    uniq[id] = move(t);\n                } else {\n                    uniq[id].src = srcU;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) {\n            vec.push_back((int)uniq.size());\n            uniq.push_back(move(c));\n        }\n    }\n\n    if ((int)uniq.size() <= maxCand) {\n        pool.swap(uniq);\n        return;\n    }\n\n    int M = (int)uniq.size();\n    vector<int> ids(M);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byShort = ids;\n    sort(byShort.begin(), byShort.end(), [&](int i, int j) {\n        if (uniq[i].shortage != uniq[j].shortage) return uniq[i].shortage < uniq[j].shortage;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    vector<int> byBound = ids;\n    sort(byBound.begin(), byBound.end(), [&](int i, int j) {\n        if (uniq[i].boundaryLen != uniq[j].boundaryLen) return uniq[i].boundaryLen < uniq[j].boundaryLen;\n        return uniq[i].shortage < uniq[j].shortage;\n    });\n\n    vector<int> byMix = ids;\n    sort(byMix.begin(), byMix.end(), [&](int i, int j) {\n        ll si = uniq[i].shortage + 16LL * uniq[i].boundaryLen;\n        ll sj = uniq[j].shortage + 16LL * uniq[j].boundaryLen;\n        if (si != sj) return si < sj;\n        if (uniq[i].shortage != uniq[j].shortage) return uniq[i].shortage < uniq[j].shortage;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    vector<int> proto = ids;\n    proto.erase(remove_if(proto.begin(), proto.end(), [&](int id) {\n        return !(uniq[id].src & (2 | 4));\n    }), proto.end());\n    sort(proto.begin(), proto.end(), [&](int i, int j) {\n        ll si = uniq[i].shortage + 10LL * uniq[i].boundaryLen;\n        ll sj = uniq[j].shortage + 10LL * uniq[j].boundaryLen;\n        if (si != sj) return si < sj;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    // adaptive quotas by free area\n    double t = (freeArea - 5000.0) / 250000.0;\n    if (t < 0.0) t = 0.0;\n    if (t > 1.0) t = 1.0;\n\n    ll bestS = uniq[byShort[0]].shortage;\n    ll margin = (ll)llround(50000.0 + 170000.0 * t);\n\n    vector<int> near;\n    near.reserve(M);\n    for (int id : ids) {\n        if (uniq[id].shortage <= bestS + margin) near.push_back(id);\n    }\n    sort(near.begin(), near.end(), [&](int i, int j) {\n        if (uniq[i].boundaryLen != uniq[j].boundaryLen) return uniq[i].boundaryLen < uniq[j].boundaryLen;\n        return uniq[i].shortage < uniq[j].shortage;\n    });\n\n    int qShort = (int)llround(maxCand * (0.70 - 0.30 * t));\n    int qProto = (int)llround(maxCand * (0.15 + 0.20 * t));\n    int qNear  = (int)llround(maxCand * (0.10 + 0.05 * t));\n    qShort = max(qShort, 1);\n    qProto = max(qProto, 0);\n    qNear  = max(qNear, 0);\n\n    int minProtoKeep = min((int)proto.size(), (freeArea > 120000 ? 8 : 4));\n    qProto = max(qProto, minProtoKeep);\n\n    while (qShort + qProto + qNear > maxCand) {\n        if (qNear > 0) qNear--;\n        else if (qShort > 1) qShort--;\n        else if (qProto > minProtoKeep) qProto--;\n        else if (qProto > 0) qProto--;\n        else break;\n    }\n    int qMix = max(0, maxCand - qShort - qProto - qNear);\n\n    vector<char> used(M, 0);\n    vector<int> sel;\n    sel.reserve(maxCand);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxCand || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    pick(byShort, qShort);\n    pick(proto, qProto);\n    pick(near, qNear);\n    pick(byMix, qMix);\n    pick(byBound, maxCand);\n    pick(byShort, maxCand);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) out.push_back(move(uniq[id]));\n    pool.swap(out);\n}\n\nstruct TwoPathResult {\n    ll costMain;\n    vector<int> pathMain;\n    ll costAlt;\n    vector<int> pathAlt;\n};\n\n// Solve DP for transition weight 1 (main) and altW (smooth prototypes) simultaneously.\nstatic TwoPathResult solve_dp_two_paths(const vector<vector<Candidate>>& cands, int altW = 2) {\n    int D = (int)cands.size();\n    const ll INF = (1LL << 62);\n\n    vector<vector<int>> parMain(D), parAlt(D);\n    vector<ll> dpMainPrev(cands[0].size(), INF), dpAltPrev(cands[0].size(), INF);\n    vector<ll> dpMainCur, dpAltCur;\n\n    for (int i = 0; i < (int)cands[0].size(); i++) {\n        dpMainPrev[i] = cands[0][i].shortage; // L0=0\n        dpAltPrev[i] = cands[0][i].shortage;\n    }\n\n    for (int d = 1; d < D; d++) {\n        int P = (int)cands[d - 1].size();\n        int C = (int)cands[d].size();\n\n        dpMainCur.assign(C, INF);\n        dpAltCur.assign(C, INF);\n        parMain[d].assign(C, -1);\n        parAlt[d].assign(C, -1);\n\n        for (int i = 0; i < C; i++) {\n            ll add = cands[d][i].shortage;\n            ll bestM = INF, bestA = INF;\n            int bestMj = 0, bestAj = 0;\n\n            for (int j = 0; j < P; j++) {\n                ll tr = transition_cost(cands[d - 1][j], cands[d][i]);\n\n                ll vm = dpMainPrev[j] + tr + add;\n                if (vm < bestM) {\n                    bestM = vm;\n                    bestMj = j;\n                }\n\n                ll va = dpAltPrev[j] + (ll)altW * tr + add;\n                if (va < bestA) {\n                    bestA = va;\n                    bestAj = j;\n                }\n            }\n\n            dpMainCur[i] = bestM;\n            dpAltCur[i] = bestA;\n            parMain[d][i] = bestMj;\n            parAlt[d][i] = bestAj;\n        }\n\n        dpMainPrev.swap(dpMainCur);\n        dpAltPrev.swap(dpAltCur);\n    }\n\n    int lastM = 0;\n    for (int i = 1; i < (int)dpMainPrev.size(); i++) if (dpMainPrev[i] < dpMainPrev[lastM]) lastM = i;\n    int lastA = 0;\n    for (int i = 1; i < (int)dpAltPrev.size(); i++) if (dpAltPrev[i] < dpAltPrev[lastA]) lastA = i;\n\n    vector<int> pathM(D, 0), pathA(D, 0);\n    pathM[D - 1] = lastM;\n    pathA[D - 1] = lastA;\n    for (int d = D - 1; d >= 1; d--) {\n        pathM[d - 1] = parMain[d][pathM[d]];\n        pathA[d - 1] = parAlt[d][pathA[d]];\n    }\n\n    return {dpMainPrev[lastM], pathM, dpAltPrev[lastA], pathA};\n}\n\nstatic void add_order_unique(vector<vector<int>>& orders, const vector<int>& ord) {\n    for (auto& v : orders) if (v == ord) return;\n    orders.push_back(ord);\n}\n\nstatic void add_template_unique(vector<vector<int>>& templates, const vector<int>& h) {\n    if (h.empty()) return;\n    for (auto& t : templates) if (t == h) return;\n    templates.push_back(h);\n}\n\nstatic vector<int> make_snap_template(int W, int r, int Q) {\n    vector<int> b(r + 1);\n    b[0] = 0;\n    b[r] = W;\n    int prev = 0;\n    for (int i = 1; i < r; i++) {\n        double ideal = 1.0 * W * i / r;\n        int y = (int)llround(ideal / Q) * Q;\n        y = max(y, prev + 1);\n        y = min(y, W - (r - i));\n        b[i] = y;\n        prev = y;\n    }\n    vector<int> h(r);\n    for (int i = 0; i < r; i++) h[i] = b[i + 1] - b[i];\n    return h;\n}\n\nstatic vector<vector<int>> make_fixed_templates(int W, int N, bool smallScale) {\n    vector<int> rset;\n    if (smallScale) rset = {1,2,3,4,5,6,8,10,12,16};\n    else rset = {1,2,3,4,5,6,8,10,12};\n\n    vector<vector<int>> templates;\n    for (int r : rset) {\n        if (r <= 0 || r > N) continue;\n\n        vector<int> h1(r, W / r);\n        int rem = W % r;\n        for (int i = 0; i < rem; i++) h1[i]++;\n        add_template_unique(templates, h1);\n\n        if (rem > 0) {\n            vector<int> h2(r, W / r);\n            for (int i = 0; i < rem; i++) h2[r - 1 - i]++;\n            add_template_unique(templates, h2);\n        }\n\n        if (r <= 12) add_template_unique(templates, make_snap_template(W, r, 50));\n    }\n    return templates;\n}\n\nstatic vector<Candidate> select_global_prototypes(\n    const vector<vector<Candidate>>& cands,\n    const vector<vector<int>>& a,\n    int maxProto,\n    int avgFreeArea\n) {\n    vector<Candidate> pool;\n    for (auto& day : cands) for (auto& c : day) pool.push_back(c);\n    pool = dedup_shape_only(move(pool));\n    if (pool.empty()) return {};\n\n    int P = (int)pool.size();\n    int D = (int)a.size();\n    if (P <= maxProto) {\n        for (auto& c : pool) c.src = 2;\n        sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n            if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n            return x.shortage < y.shortage;\n        });\n        return pool;\n    }\n\n    double t = avgFreeArea / 250000.0;\n    if (t < 0.0) t = 0.0;\n    if (t > 1.0) t = 1.0;\n\n    ll lam = (ll)llround(2.0 + 2.0 * t);\n    int perDayBoundaryCoef = (int)llround(3.0 + 3.0 * t);\n\n    vector<ll> total(P, 0), gscore(P, 0);\n    vector<int> wins(P, 0);\n\n    int TOPK = min(4, P);\n    vector<pair<ll,int>> rank(P);\n\n    for (int d = 0; d < D; d++) {\n        for (int p = 0; p < P; p++) {\n            ll sh = calc_shortage(a[d], pool[p].areas);\n            total[p] += sh;\n            rank[p] = {sh + (ll)perDayBoundaryCoef * pool[p].boundaryLen, p};\n        }\n\n        if (TOPK < P) nth_element(rank.begin(), rank.begin() + TOPK, rank.end());\n        sort(rank.begin(), rank.begin() + TOPK);\n\n        for (int k = 0; k < TOPK; k++) wins[rank[k].second] += (TOPK - k);\n    }\n\n    for (int p = 0; p < P; p++) gscore[p] = total[p] + lam * 1LL * D * pool[p].boundaryLen;\n\n    vector<int> ids(P);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byGlobal = ids;\n    sort(byGlobal.begin(), byGlobal.end(), [&](int i, int j) {\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        if (pool[i].boundaryLen != pool[j].boundaryLen) return pool[i].boundaryLen < pool[j].boundaryLen;\n        return i < j;\n    });\n\n    vector<int> byWins = ids;\n    sort(byWins.begin(), byWins.end(), [&](int i, int j) {\n        if (wins[i] != wins[j]) return wins[i] > wins[j];\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        return i < j;\n    });\n\n    vector<int> byBound = ids;\n    sort(byBound.begin(), byBound.end(), [&](int i, int j) {\n        if (pool[i].boundaryLen != pool[j].boundaryLen) return pool[i].boundaryLen < pool[j].boundaryLen;\n        return gscore[i] < gscore[j];\n    });\n\n    vector<char> used(P, 0);\n    vector<int> sel;\n    sel.reserve(maxProto);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxProto || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    int q1 = maxProto * 50 / 100;\n    int q2 = maxProto * 30 / 100;\n    int q3 = maxProto - q1 - q2;\n\n    pick(byGlobal, q1);\n    pick(byWins, q2);\n    pick(byBound, q3);\n    pick(byGlobal, maxProto);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) {\n        pool[id].src = 2;\n        out.push_back(pool[id]);\n    }\n    return out;\n}\n\nstatic vector<Candidate> trim_prototypes(vector<Candidate> protos, const vector<vector<int>>& a, int maxK, int avgFree) {\n    protos = dedup_shape_only(move(protos));\n    if ((int)protos.size() <= maxK) return protos;\n\n    int P = (int)protos.size();\n    int D = (int)a.size();\n    double t = avgFree / 250000.0;\n    if (t < 0.0) t = 0.0;\n    if (t > 1.0) t = 1.0;\n    ll lam = (ll)llround(1.5 + 1.5 * t);\n\n    vector<pair<ll,int>> rk;\n    rk.reserve(P);\n    for (int i = 0; i < P; i++) {\n        ll total = 0;\n        for (int d = 0; d < D; d++) total += calc_shortage(a[d], protos[i].areas);\n        ll score = total + lam * 1LL * D * protos[i].boundaryLen;\n        rk.push_back({score, i});\n    }\n    sort(rk.begin(), rk.end());\n\n    vector<Candidate> out;\n    out.reserve(maxK);\n    for (int i = 0; i < maxK; i++) {\n        Candidate c = protos[rk[i].second];\n        c.src |= 2;\n        out.push_back(move(c));\n    }\n    return out;\n}\n\nstatic vector<Candidate> build_path_prototypes(\n    const vector<vector<Candidate>>& cands,\n    const vector<int>& choice,\n    const vector<vector<int>>& a,\n    int W,\n    int limit,\n    bool addTranspose,\n    unsigned char srcBit\n) {\n    int D = (int)cands.size();\n    vector<Candidate> pool;\n    pool.reserve(D * 2);\n\n    for (int d = 0; d < D; d++) {\n        Candidate p = cands[d][choice[d]];\n        p.src = srcBit;\n        pool.push_back(move(p));\n        if (addTranspose && (d % 2 == 0)) {\n            Candidate t = transpose_candidate(cands[d][choice[d]], W, a[d], srcBit);\n            pool.push_back(move(t));\n        }\n    }\n\n    pool = dedup_shape_only(move(pool));\n    sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n        if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n        return x.shortage < y.shortage;\n    });\n    if ((int)pool.size() > limit) pool.resize(limit);\n    for (auto& p : pool) p.src = srcBit;\n    return pool;\n}\n\n// Detect if a shape is shelf-like and extract row heights.\nstatic bool extract_shelf_heights(const Candidate& c, int W, vector<int>& heights) {\n    vector<int> ys = {0, W};\n\n    for (auto& h : c.hsegs) {\n        if (h.c <= 0 || h.c >= W) return false;\n        if (h.l != 0 || h.r != W) return false;\n        ys.push_back(h.c);\n    }\n\n    sort(ys.begin(), ys.end());\n    ys.erase(unique(ys.begin(), ys.end()), ys.end());\n    if (ys.front() != 0 || ys.back() != W) return false;\n\n    for (auto& v : c.vsegs) {\n        if (v.c <= 0 || v.c >= W) return false;\n        if (v.l < 0 || v.r > W || v.l >= v.r) return false;\n        auto it = upper_bound(ys.begin(), ys.end(), v.l);\n        if (it != ys.end() && *it < v.r) return false; // crosses horizontal line\n    }\n\n    heights.clear();\n    for (int i = 0; i + 1 < (int)ys.size(); i++) {\n        int h = ys[i + 1] - ys[i];\n        if (h <= 0) return false;\n        heights.push_back(h);\n    }\n\n    int sumH = 0;\n    for (int h : heights) sumH += h;\n    return (sumH == W);\n}\n\nstatic vector<int> blend_heights(const vector<int>& h1, const vector<int>& h2, int W, int snapQ = 0) {\n    if (h1.size() != h2.size() || h1.empty()) return {};\n    int r = (int)h1.size();\n\n    vector<int> b1(r + 1, 0), b2(r + 1, 0), b(r + 1, 0);\n    for (int i = 0; i < r; i++) {\n        b1[i + 1] = b1[i] + h1[i];\n        b2[i + 1] = b2[i] + h2[i];\n    }\n    if (b1[r] != W || b2[r] != W) return {};\n\n    b[0] = 0;\n    b[r] = W;\n    for (int i = 1; i < r; i++) {\n        int y = (int)llround((b1[i] + b2[i]) * 0.5);\n        if (snapQ > 0) {\n            int dn = (y / snapQ) * snapQ;\n            int up = ((y + snapQ - 1) / snapQ) * snapQ;\n            y = (abs(y - dn) <= abs(up - y) ? dn : up);\n        }\n        b[i] = y;\n    }\n\n    for (int i = 1; i < r; i++) b[i] = max(b[i], b[i - 1] + 1);\n    for (int i = r - 1; i >= 1; i--) b[i] = min(b[i], b[i + 1] - 1);\n    for (int i = 1; i < r; i++) {\n        if (!(b[i - 1] < b[i] && b[i] < b[i + 1])) return {};\n    }\n\n    vector<int> h(r);\n    int sumH = 0;\n    for (int i = 0; i < r; i++) {\n        h[i] = b[i + 1] - b[i];\n        if (h[i] <= 0) return {};\n        sumH += h[i];\n    }\n    if (sumH != W) return {};\n    return h;\n}\n\nstatic vector<Candidate> build_synthetic_prototypes(\n    int W,\n    const vector<vector<int>>& a,\n    const vector<int>& ordAsc,\n    const vector<int>& ordDesc,\n    const vector<int>& zig1,\n    int capRows,\n    const vector<int>& widthModes,\n    bool smallScale\n) {\n    int D = (int)a.size();\n    int N = (int)a[0].size();\n\n    vector<int> meanA(N), medA(N), q25A(N), q75A(N);\n    for (int k = 0; k < N; k++) {\n        vector<int> vals(D);\n        ll s = 0;\n        for (int d = 0; d < D; d++) {\n            vals[d] = a[d][k];\n            s += a[d][k];\n        }\n        sort(vals.begin(), vals.end());\n        meanA[k] = (int)((s + D / 2) / D);\n        medA[k] = vals[D / 2];\n        q25A[k] = vals[D / 4];\n        q75A[k] = vals[(3 * D) / 4];\n    }\n\n    auto fix_nondec = [&](vector<int>& x) {\n        for (int i = 1; i < N; i++) x[i] = max(x[i], x[i - 1]);\n    };\n    fix_nondec(meanA);\n    fix_nondec(medA);\n    fix_nondec(q25A);\n    fix_nondec(q75A);\n\n    vector<vector<int>> synthArrs = {meanA, medA};\n    if (smallScale) {\n        synthArrs.push_back(q25A);\n        synthArrs.push_back(q75A);\n    }\n\n    vector<vector<int>> orders;\n    add_order_unique(orders, ordAsc);\n    add_order_unique(orders, ordDesc);\n    if (smallScale) add_order_unique(orders, zig1);\n\n    vector<Candidate> pool;\n    int capRows2 = min(capRows, 8);\n\n    for (int id = 0; id < (int)synthArrs.size(); id++) {\n        auto& arr = synthArrs[id];\n\n        for (int oi = 0; oi < (int)orders.size(); oi++) {\n            auto vv = generate_shelf_one_order(W, arr, orders[oi], capRows2, widthModes);\n            sort(vv.begin(), vv.end(), [](const Candidate& x, const Candidate& y) {\n                ll sx = x.shortage + 6LL * x.boundaryLen;\n                ll sy = y.shortage + 6LL * y.boundaryLen;\n                if (sx != sy) return sx < sy;\n                return x.boundaryLen < y.boundaryLen;\n            });\n            if ((int)vv.size() > 5) vv.resize(5);\n\n            bool doTrans = (smallScale && oi == 0);\n            for (auto& c : vv) {\n                c.src = 2;\n                pool.push_back(c);\n                if (doTrans) pool.push_back(transpose_candidate(c, W, arr, 2));\n            }\n        }\n\n        Candidate g;\n        uint64_t seed = 0x9e3779b97f4a7c15ULL ^ (uint64_t)(id + 1) * 1000003ULL;\n        if (generate_guillotine_candidate(W, arr, ordAsc, g, seed, 0, 2)) {\n            g.src = 2;\n            pool.push_back(g);\n            if (smallScale) pool.push_back(transpose_candidate(g, W, arr, 2));\n        }\n    }\n\n    pool = dedup_shape_only(move(pool));\n    sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n        if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n        return x.shortage < y.shortage;\n    });\n    int cap = smallScale ? 32 : 20;\n    if ((int)pool.size() > cap) pool.resize(cap);\n    for (auto& p : pool) p.src = 2;\n    return pool;\n}\n\nstatic void targeted_random_enrich_day(\n    int W,\n    const vector<int>& dayA,\n    vector<Candidate>& pool,\n    int capRows,\n    const vector<int>& widthModes,\n    int shelfTries,\n    int guillTries,\n    uint64_t seedBase,\n    bool addTranspose\n) {\n    int N = (int)dayA.size();\n    int rowCap = max(3, min(capRows, 6));\n\n    for (int t = 0; t < shelfTries; t++) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        uint64_t sd = splitmix64(seedBase ^ (uint64_t)(t + 1) * 1000003ULL);\n        mt19937_64 rng(sd);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        auto vv = generate_shelf_one_order(W, dayA, ord, rowCap, widthModes);\n        sort(vv.begin(), vv.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.shortage != b.shortage) return a.shortage < b.shortage;\n            return a.boundaryLen < b.boundaryLen;\n        });\n        if ((int)vv.size() > 10) vv.resize(10);\n\n        for (auto& c : vv) {\n            c.src |= 1;\n            pool.push_back(c);\n            if (addTranspose && t == 0) {\n                pool.push_back(transpose_candidate(c, W, dayA, 1));\n            }\n        }\n\n        for (int g = 0; g < guillTries; g++) {\n            Candidate gc;\n            int mode = (g == 0 ? 1 : 2);\n            uint64_t sg = splitmix64(sd ^ (uint64_t)(g + 7) * 11995408973635179863ULL);\n            if (generate_guillotine_candidate(W, dayA, ord, gc, sg, mode, 1)) {\n                pool.push_back(gc);\n                if (addTranspose && g == 0) {\n                    pool.push_back(transpose_candidate(gc, W, dayA, 1));\n                }\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) cin >> a[d][k];\n    }\n\n    vector<int> freeArea(D, 0);\n    int totalFree = 0;\n    for (int d = 0; d < D; d++) {\n        ll s = 0;\n        for (int x : a[d]) s += x;\n        freeArea[d] = (int)(1LL * W * W - s);\n        totalFree += freeArea[d];\n    }\n    int avgFree = totalFree / D;\n\n    int scale = D * N;\n    bool smallScale = (scale <= 1600);\n    bool largeScale = (scale > 2200);\n\n    int CAP_ROWS = smallScale ? min(N, 8) : (largeScale ? min(N, 5) : min(N, 6));\n    int INIT_MAX = smallScale ? 64 : (largeScale ? 46 : 54);\n    int MAX_CAND = smallScale ? 94 : (largeScale ? 70 : 82);\n    int GPROTO = smallScale ? 56 : (largeScale ? 36 : 46);\n    int PATHPROTO = smallScale ? 60 : (largeScale ? 42 : 50);\n    int GUILL_TRIES = smallScale ? 3 : 2;\n    int ITER = smallScale ? 3 : 2;\n\n    vector<int> widthModesLocal = {0, 2}; // last, even\n    if (smallScale) widthModesLocal.push_back(3); // proportional\n    vector<int> widthModesFixed = {0, 2};\n    if (smallScale) widthModesFixed.push_back(3);\n\n    bool useFixedTemplates = true;\n    if (largeScale && avgFree < 60000) useFixedTemplates = false; // dense+large: speed/quality balance\n\n    vector<vector<int>> fixedTemplates = make_fixed_templates(W, N, smallScale);\n\n    vector<int> ordAsc(N), ordDesc(N), zig1, zig2;\n    iota(ordAsc.begin(), ordAsc.end(), 0);\n    for (int i = 0; i < N; i++) ordDesc[i] = N - 1 - i;\n\n    {\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            if (l == r) { zig1.push_back(l); break; }\n            zig1.push_back(l++);\n            zig1.push_back(r--);\n        }\n    }\n    {\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            if (l == r) { zig2.push_back(r); break; }\n            zig2.push_back(r--);\n            zig2.push_back(l++);\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> ll {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<vector<Candidate>> cands(D);\n\n    // Initial local generation\n    for (int d = 0; d < D; d++) {\n        mt19937 rng(71236721u + 911u * d + 31u * N);\n        vector<int> rnd1 = ordAsc, rnd2 = ordAsc;\n        shuffle(rnd1.begin(), rnd1.end(), rng);\n        shuffle(rnd2.begin(), rnd2.end(), rng);\n\n        vector<vector<int>> shelfOrders, guillOrders;\n        add_order_unique(shelfOrders, ordAsc);\n        add_order_unique(shelfOrders, ordDesc);\n        add_order_unique(shelfOrders, zig1);\n        if (smallScale) add_order_unique(shelfOrders, zig2);\n        add_order_unique(shelfOrders, rnd1);\n        if (smallScale) add_order_unique(shelfOrders, rnd2);\n\n        add_order_unique(guillOrders, ordAsc);\n        add_order_unique(guillOrders, ordDesc);\n        add_order_unique(guillOrders, rnd1);\n\n        bool transposeAllShelf = smallScale;\n        bool transposeGuillAll = smallScale;\n\n        vector<Candidate> pool;\n        pool.reserve(1500);\n\n        // Shelf candidates\n        for (int oi = 0; oi < (int)shelfOrders.size(); oi++) {\n            auto vv = generate_shelf_one_order(W, a[d], shelfOrders[oi], CAP_ROWS, widthModesLocal);\n            bool doTrans = transposeAllShelf || oi < 2;\n            for (auto& c : vv) {\n                pool.push_back(c);\n                if (doTrans) pool.push_back(transpose_candidate(c, W, a[d], 1));\n            }\n        }\n\n        // Fixed templates\n        if (useFixedTemplates) {\n            vector<vector<int>> fixedOrders;\n            add_order_unique(fixedOrders, ordAsc);\n            add_order_unique(fixedOrders, ordDesc);\n            if (smallScale) add_order_unique(fixedOrders, zig1);\n\n            for (int oi = 0; oi < (int)fixedOrders.size(); oi++) {\n                auto vv = generate_fixed_height_templates(W, a[d], fixedOrders[oi], fixedTemplates, widthModesFixed, 1);\n                bool doTrans = smallScale && oi == 0;\n                for (auto& c : vv) {\n                    pool.push_back(c);\n                    if (doTrans) pool.push_back(transpose_candidate(c, W, a[d], 1));\n                }\n            }\n        }\n\n        // Guillotine candidates\n        for (auto& ord : guillOrders) {\n            for (int t = 0; t < GUILL_TRIES; t++) {\n                int mode = (t == 0 ? 0 : (t == 1 ? 1 : 2));\n                uint64_t seed = 0x9e3779b97f4a7c15ULL\n                              ^ (uint64_t)(d + 1) * 1000003ULL\n                              ^ (uint64_t)(t + 1) * 911382323ULL\n                              ^ (uint64_t)ord[0] * 972663749ULL;\n\n                Candidate g;\n                if (generate_guillotine_candidate(W, a[d], ord, g, seed, mode, 1)) {\n                    pool.push_back(g);\n                    if (transposeGuillAll || t == 0) {\n                        pool.push_back(transpose_candidate(g, W, a[d], 1));\n                    }\n                }\n            }\n        }\n\n        pool.push_back(fallback_horizontal(W, a[d]));\n        pool.push_back(fallback_vertical(W, a[d]));\n\n        dedup_and_trim(pool, INIT_MAX, freeArea[d]);\n        if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n        cands[d] = move(pool);\n    }\n\n    // Synthetic global prototypes and initial injection\n    vector<Candidate> synthProtos = build_synthetic_prototypes(\n        W, a, ordAsc, ordDesc, zig1, CAP_ROWS, widthModesLocal, smallScale\n    );\n\n    if (!synthProtos.empty()) {\n        int initAug = min(MAX_CAND, INIT_MAX + (smallScale ? 12 : 8));\n        for (int d = 0; d < D; d++) {\n            auto& pool = cands[d];\n            for (auto& p : synthProtos) pool.push_back(clone_for_day(p, a[d], 2));\n            dedup_and_trim(pool, initAug, freeArea[d]);\n            if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n        }\n    }\n\n    int altW = (avgFree > 140000 ? 3 : 2);\n\n    // Initial solve: true + smoother path\n    auto res = solve_dp_two_paths(cands, altW);\n    ll bestCost = res.costMain;\n    vector<int> choiceMain = res.pathMain;\n    vector<int> choiceSmooth = res.pathAlt;\n\n    vector<vector<array<int, 4>>> bestRects(D);\n    for (int d = 0; d < D; d++) bestRects[d] = cands[d][choiceMain[d]].rects;\n\n    vector<Candidate> globalProtos = select_global_prototypes(cands, a, GPROTO, avgFree);\n    for (auto& p : synthProtos) globalProtos.push_back(p);\n    globalProtos = trim_prototypes(move(globalProtos), a, GPROTO + (smallScale ? 10 : 6), avgFree);\n\n    vector<vector<int>> adaptOrders;\n    add_order_unique(adaptOrders, ordAsc);\n    add_order_unique(adaptOrders, ordDesc);\n    if (smallScale) add_order_unique(adaptOrders, zig1);\n\n    // Iterative enrichment\n    for (int iter = 0; iter < ITER; iter++) {\n        if (elapsed_ms() > 2550) break;\n\n        // freeze current path shapes before mutating cands\n        vector<Candidate> mainPathShape(D), smoothPathShape(D);\n        for (int d = 0; d < D; d++) {\n            mainPathShape[d] = cands[d][choiceMain[d]];\n            smoothPathShape[d] = cands[d][choiceSmooth[d]];\n            mainPathShape[d].src = 4;\n            smoothPathShape[d].src = 4;\n        }\n\n        auto pathP1 = build_path_prototypes(cands, choiceMain, a, W, PATHPROTO / 2, (iter == 0), 4);\n        auto pathP2 = build_path_prototypes(cands, choiceSmooth, a, W, PATHPROTO / 2, false, 4);\n\n        vector<Candidate> protoAll = globalProtos;\n        for (auto& p : pathP1) protoAll.push_back(p);\n        for (auto& p : pathP2) protoAll.push_back(p);\n        if (iter == 0) {\n            for (auto& p : synthProtos) protoAll.push_back(p);\n        }\n\n        int protoCap = smallScale ? 86 : 64;\n        protoAll = trim_prototypes(move(protoAll), a, protoCap, avgFree);\n\n        // hard-day detection on current main path\n        vector<pair<ll,int>> hardRank;\n        hardRank.reserve(D);\n        for (int d = 0; d < D; d++) {\n            ll imp = mainPathShape[d].shortage;\n            if (d > 0) imp += transition_cost(mainPathShape[d - 1], mainPathShape[d]);\n            if (d + 1 < D) imp += transition_cost(mainPathShape[d], mainPathShape[d + 1]);\n            hardRank.push_back({imp, d});\n        }\n        sort(hardRank.begin(), hardRank.end(), [&](auto& x, auto& y) { return x.first > y.first; });\n\n        int hardK = smallScale ? 8 : 5;\n        vector<char> hardFlag(D, 0);\n        for (int i = 0; i < min(hardK, D); i++) hardFlag[hardRank[i].second] = 1;\n\n        bool allowHeavy = elapsed_ms() < (smallScale ? 2200 : 2050);\n\n        for (int d = 0; d < D; d++) {\n            vector<Candidate> pool = cands[d];\n            pool.reserve(pool.size() + (int)protoAll.size() + 140);\n\n            for (auto& p : protoAll) {\n                pool.push_back(clone_for_day(p, a[d], p.src));\n            }\n\n            auto add_neighbors = [&](const vector<Candidate>& pathShape) {\n                if (d - 1 >= 0) pool.push_back(clone_for_day(pathShape[d - 1], a[d], 4));\n                if (d + 1 < D)  pool.push_back(clone_for_day(pathShape[d + 1], a[d], 4));\n                if (iter == 0) {\n                    if (d - 2 >= 0) pool.push_back(clone_for_day(pathShape[d - 2], a[d], 4));\n                    if (d + 2 < D)  pool.push_back(clone_for_day(pathShape[d + 2], a[d], 4));\n                }\n            };\n            add_neighbors(mainPathShape);\n            add_neighbors(smoothPathShape);\n\n            bool doLocalTemplate = allowHeavy && (!largeScale || ((d + iter) & 1) == 0) &&\n                                   elapsed_ms() < (smallScale ? 2400 : 2200);\n\n            // Targeted enrichment: neighbor shelf heights + blended heights\n            if (doLocalTemplate) {\n                vector<vector<int>> baseTemps;\n\n                auto collect = [&](const Candidate& c) {\n                    vector<int> hs;\n                    if (extract_shelf_heights(c, W, hs)) add_template_unique(baseTemps, hs);\n                };\n\n                if (d - 1 >= 0) {\n                    collect(mainPathShape[d - 1]);\n                    collect(smoothPathShape[d - 1]);\n                }\n                if (d + 1 < D) {\n                    collect(mainPathShape[d + 1]);\n                    collect(smoothPathShape[d + 1]);\n                }\n                if (hardFlag[d]) {\n                    collect(mainPathShape[d]);\n                    collect(smoothPathShape[d]);\n                }\n\n                vector<vector<int>> localTemps = baseTemps;\n\n                for (int i = 0; i < (int)baseTemps.size(); i++) {\n                    for (int j = i + 1; j < (int)baseTemps.size(); j++) {\n                        if (baseTemps[i].size() != baseTemps[j].size()) continue;\n                        auto b0 = blend_heights(baseTemps[i], baseTemps[j], W, 0);\n                        add_template_unique(localTemps, b0);\n                        if (smallScale) {\n                            auto b1 = blend_heights(baseTemps[i], baseTemps[j], W, 50);\n                            add_template_unique(localTemps, b1);\n                        }\n                        if ((int)localTemps.size() >= 6) break;\n                    }\n                    if ((int)localTemps.size() >= 6) break;\n                }\n\n                if ((int)localTemps.size() > 5) localTemps.resize(5);\n\n                if (!localTemps.empty()) {\n                    int ordLim = min(2, (int)adaptOrders.size()); // asc/desc\n                    for (int oi = 0; oi < ordLim; oi++) {\n                        auto vv = generate_fixed_height_templates(W, a[d], adaptOrders[oi], localTemps, widthModesFixed, 4);\n                        for (auto& c : vv) {\n                            c.src = 4;\n                            pool.push_back(c);\n                        }\n                    }\n                }\n            }\n\n            // Hard-day targeted random enrichment (time-gated)\n            bool doRand = !largeScale && hardFlag[d] &&\n                          elapsed_ms() < (smallScale ? 2250 : 2000);\n            if (doRand) {\n                int shelfTries = smallScale ? 2 : 1;\n                int guillTries = 1;\n                uint64_t seedBase = 0x517cc1b727220a95ULL\n                                  ^ (uint64_t)(iter + 1) * 1000003ULL\n                                  ^ (uint64_t)(d + 1) * 911382323ULL\n                                  ^ (uint64_t)(freeArea[d] + 12345);\n                targeted_random_enrich_day(\n                    W, a[d], pool, CAP_ROWS, widthModesLocal,\n                    shelfTries, guillTries, seedBase, smallScale\n                );\n            }\n\n            dedup_and_trim(pool, MAX_CAND, freeArea[d]);\n            if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n            cands[d] = move(pool);\n        }\n\n        res = solve_dp_two_paths(cands, altW);\n        choiceMain = res.pathMain;\n        choiceSmooth = res.pathAlt;\n\n        if (res.costMain < bestCost) {\n            bestCost = res.costMain;\n            for (int d = 0; d < D; d++) bestRects[d] = cands[d][choiceMain[d]].rects;\n        }\n\n        if (elapsed_ms() < 2400) {\n            int nextG = max(22, GPROTO - 6 - 2 * iter);\n            globalProtos = select_global_prototypes(cands, a, nextG, avgFree);\n            for (auto& p : synthProtos) globalProtos.push_back(p);\n            globalProtos = trim_prototypes(move(globalProtos), a, nextG + (smallScale ? 8 : 5), avgFree);\n        }\n    }\n\n    // Output best found\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            auto& r = bestRects[d][k];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\nstatic constexpr int N = 9;\nstatic constexpr int K = 81;\nstatic constexpr int CELLS = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return static_cast<int>(next_u64() % static_cast<uint64_t>(n));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Action {\n    uint8_t cell[9];\n    uint32_t val[9];\n    uint32_t thr[9]; // MOD - val\n    long long raw = 0; // sum val\n    int m = 0, p = 0, q = 0;\n};\n\nstruct State {\n    array<uint32_t, CELLS> board{};\n    array<int, K> ops{};\n    long long score = 0;\n};\n\ninline long long gain_add(const uint32_t* b, const Action& a) {\n    int wraps = 0;\n    for (int k = 0; k < 9; k++) wraps += (b[a.cell[k]] >= a.thr[k]);\n    return a.raw - 1LL * MOD * wraps;\n}\n\ninline void apply_add(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        int idx = a.cell[k];\n        uint32_t ov = b[idx];\n        uint32_t nv = ov + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)ov;\n    }\n}\n\ninline void apply_remove(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        int idx = a.cell[k];\n        uint32_t ov = b[idx];\n        uint32_t v = a.val[k];\n        uint32_t nv = (ov >= v) ? (ov - v) : (ov + MOD - v);\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)ov;\n    }\n}\n\nState make_empty_state(const array<uint32_t, CELLS>& base, int dummy_id) {\n    State st;\n    st.board = base;\n    st.ops.fill(dummy_id);\n    st.score = 0;\n    for (uint32_t v : base) st.score += v;\n    return st;\n}\n\ninline void shuffle_order(array<int, K>& ord, XorShift64& rng) {\n    for (int i = K - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nbool one_sweep(State& st, const vector<Action>& actions, int dummy_id,\n               array<int, K>& order, XorShift64& rng) {\n    shuffle_order(order, rng);\n    bool changed = false;\n    const int A = dummy_id;\n\n    for (int t = 0; t < K; t++) {\n        int pos = order[t];\n        int old = st.ops[pos];\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int best = dummy_id;\n        long long best_gain = 0; // dummy gain\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain || (g == best_gain && id == old)) {\n                best_gain = g;\n                best = id;\n            }\n        }\n\n        if (best != dummy_id) apply_add(st, actions[best]);\n        st.ops[pos] = best;\n        if (best != old) changed = true;\n    }\n    return changed;\n}\n\nvoid local_opt(State& st, const vector<Action>& actions, int dummy_id,\n               Timer& timer, double tl, XorShift64& rng, int max_sweeps) {\n    array<int, K> ord;\n    iota(ord.begin(), ord.end(), 0);\n    for (int sw = 0; sw < max_sweeps; sw++) {\n        if (timer.elapsed() >= tl) break;\n        bool changed = one_sweep(st, actions, dummy_id, ord, rng);\n        if (!changed) break;\n    }\n}\n\nState construct_best_greedy(const array<uint32_t, CELLS>& base,\n                            const vector<Action>& actions, int dummy_id) {\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        int best = dummy_id;\n        long long best_gain = 0;\n        const uint32_t* b = st.board.data();\n\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain) {\n                best_gain = g;\n                best = id;\n            }\n        }\n        if (best == dummy_id) break;\n        st.ops[pos] = best;\n        apply_add(st, actions[best]);\n    }\n    return st;\n}\n\nState construct_random_greedy(const array<uint32_t, CELLS>& base,\n                              const vector<Action>& actions, int dummy_id,\n                              XorShift64& rng, int topR) {\n    constexpr int LIM = 8;\n    topR = max(1, min(topR, LIM));\n\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        array<long long, LIM> bestG;\n        array<int, LIM> bestId;\n        bestG.fill(LLONG_MIN);\n        bestId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g <= 0) continue;\n            if (g <= bestG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > bestG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                bestG[t] = bestG[t - 1];\n                bestId[t] = bestId[t - 1];\n            }\n            bestG[at] = g;\n            bestId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && bestId[cnt] != -1) cnt++;\n        if (cnt == 0) break;\n\n        int pick;\n        int r = rng.next_int(100);\n        if (r < 55) pick = bestId[0];\n        else if (r < 80) pick = bestId[rng.next_int(min(cnt, 2))];\n        else pick = bestId[rng.next_int(cnt)];\n\n        st.ops[pos] = pick;\n        apply_add(st, actions[pick]);\n    }\n    return st;\n}\n\nvoid compute_marginals(State& st, const vector<Action>& actions, int dummy_id,\n                       array<long long, K>& mg) {\n    static constexpr long long DUMMY_WEAK = -(1LL << 55);\n    for (int i = 0; i < K; i++) {\n        int id = st.ops[i];\n        if (id == dummy_id) {\n            mg[i] = DUMMY_WEAK;\n            continue;\n        }\n        apply_remove(st, actions[id]);\n        mg[i] = gain_add(st.board.data(), actions[id]); // reinsertion gain\n        apply_add(st, actions[id]);\n    }\n}\n\nvector<int> select_positions(State& st, const vector<Action>& actions, int dummy_id,\n                             XorShift64& rng, int cnt, double worst_ratio, bool focus_bad) {\n    cnt = max(0, min(cnt, K));\n    vector<int> res;\n    res.reserve(cnt);\n    array<unsigned char, K> used{};\n    used.fill(0);\n\n    if (focus_bad && cnt > 0) {\n        array<long long, K> mg;\n        compute_marginals(st, actions, dummy_id, mg);\n\n        array<int, K> idx;\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (mg[a] != mg[b]) return mg[a] < mg[b];\n            return a < b;\n        });\n\n        int bad = (int)llround(cnt * worst_ratio);\n        bad = max(1, min(bad, cnt));\n        int pool = min(K, max(bad + 4, bad * 3));\n\n        for (int t = 0; t < bad; t++) {\n            int chosen = -1;\n            for (int tr = 0; tr < 20; tr++) {\n                int cand = idx[rng.next_int(pool)];\n                if (!used[cand]) {\n                    chosen = cand;\n                    break;\n                }\n            }\n            if (chosen == -1) {\n                for (int j = 0; j < K; j++) {\n                    int cand = idx[j];\n                    if (!used[cand]) {\n                        chosen = cand;\n                        break;\n                    }\n                }\n            }\n            if (chosen == -1) break;\n            used[chosen] = 1;\n            res.push_back(chosen);\n        }\n    }\n\n    while ((int)res.size() < cnt) {\n        int p = rng.next_int(K);\n        if (used[p]) continue;\n        used[p] = 1;\n        res.push_back(p);\n    }\n\n    for (int i = (int)res.size() - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(res[i], res[j]);\n    }\n    return res;\n}\n\nvoid destroy_repair_guided(State& st, const vector<Action>& actions, int dummy_id,\n                           vector<int> positions, XorShift64& rng,\n                           int topR, bool allow_negative) {\n    constexpr int LIM = 8;\n    topR = max(1, min(topR, LIM));\n    const int A = dummy_id;\n\n    for (int pos : positions) {\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n        st.ops[pos] = dummy_id;\n    }\n\n    for (int i = (int)positions.size() - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(positions[i], positions[j]);\n    }\n\n    for (int pos : positions) {\n        array<long long, LIM> bestG;\n        array<int, LIM> bestId;\n        bestG.fill(LLONG_MIN);\n        bestId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (!allow_negative && g <= 0) continue;\n            if (g <= bestG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > bestG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                bestG[t] = bestG[t - 1];\n                bestId[t] = bestId[t - 1];\n            }\n            bestG[at] = g;\n            bestId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && bestId[cnt] != -1) cnt++;\n\n        int pick = dummy_id;\n        if (cnt > 0) {\n            int r = rng.next_int(100);\n            if (allow_negative && bestG[0] <= 0) {\n                if (r < 70) {\n                    pick = dummy_id;\n                } else if (r < 88) {\n                    pick = bestId[0];\n                } else {\n                    pick = bestId[rng.next_int(cnt)];\n                }\n            } else {\n                if (r < 58) pick = bestId[0];\n                else if (r < 83) pick = bestId[rng.next_int(min(cnt, 2))];\n                else pick = bestId[rng.next_int(cnt)];\n            }\n        }\n\n        st.ops[pos] = pick;\n        if (pick != dummy_id) apply_add(st, actions[pick]);\n    }\n}\n\nvoid random_perturb(State& st, const vector<Action>& actions, int dummy_id,\n                    XorShift64& rng, int cnt) {\n    const int A = dummy_id;\n    for (int t = 0; t < cnt; t++) {\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int nid = dummy_id;\n        int mode = rng.next_int(100);\n\n        if (mode < 12) {\n            nid = dummy_id;\n        } else if (mode < 70) {\n            long long bestg = LLONG_MIN;\n            int bestid = dummy_id;\n            for (int s = 0; s < 24; s++) {\n                int id = rng.next_int(A);\n                long long g = gain_add(st.board.data(), actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            if (bestg > 0 || rng.next_int(100) < 35) nid = bestid;\n        } else if (mode < 90) {\n            int id = rng.next_int(A);\n            long long g = gain_add(st.board.data(), actions[id]);\n            if (g > -(long long)MOD / 5 || rng.next_int(100) < 20) nid = id;\n        } else {\n            long long bestg = 0;\n            int bestid = dummy_id;\n            const uint32_t* b = st.board.data();\n            for (int id = 0; id < A; id++) {\n                long long g = gain_add(b, actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            nid = bestid;\n        }\n\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n    }\n}\n\nbool pair_improve_once(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, const vector<int>* pool,\n                       int top_first, bool allow_neg_first) {\n    constexpr int LIM = 8;\n    top_first = max(1, min(top_first, LIM));\n\n    int p1, p2;\n    if (pool && (int)pool->size() >= 2) {\n        p1 = (*pool)[rng.next_int((int)pool->size())];\n        do p2 = (*pool)[rng.next_int((int)pool->size())];\n        while (p2 == p1);\n        if (rng.next_int(100) < 25) {\n            int q = rng.next_int(K - 1);\n            if (q >= p1) q++;\n            p2 = q;\n        }\n    } else {\n        p1 = rng.next_int(K);\n        p2 = rng.next_int(K - 1);\n        if (p2 >= p1) p2++;\n    }\n\n    long long before = st.score;\n    int old1 = st.ops[p1];\n    int old2 = st.ops[p2];\n\n    if (old1 != dummy_id) apply_remove(st, actions[old1]);\n    if (old2 != dummy_id) apply_remove(st, actions[old2]);\n    st.ops[p1] = dummy_id;\n    st.ops[p2] = dummy_id;\n\n    array<long long, LIM> firstG;\n    array<int, LIM> firstId;\n    firstG.fill(LLONG_MIN);\n    firstId.fill(-1);\n\n    const int A = dummy_id;\n    const uint32_t* b = st.board.data();\n    for (int id = 0; id < A; id++) {\n        long long g = gain_add(b, actions[id]);\n        if (!allow_neg_first && g <= 0) continue;\n        if (g <= firstG[top_first - 1]) continue;\n\n        int at = top_first - 1;\n        while (at > 0 && g > firstG[at - 1]) --at;\n        for (int t = top_first - 1; t > at; --t) {\n            firstG[t] = firstG[t - 1];\n            firstId[t] = firstId[t - 1];\n        }\n        firstG[at] = g;\n        firstId[at] = id;\n    }\n\n    array<long long, LIM + 1> candG{};\n    array<int, LIM + 1> candId{};\n    int candCnt = 1;\n    candG[0] = 0;\n    candId[0] = dummy_id;\n    for (int i = 0; i < top_first; i++) {\n        if (firstId[i] == -1) break;\n        candG[candCnt] = firstG[i];\n        candId[candCnt] = firstId[i];\n        candCnt++;\n    }\n\n    long long bestTot = LLONG_MIN;\n    int best1 = dummy_id, best2 = dummy_id;\n\n    for (int c = 0; c < candCnt; c++) {\n        int id1 = candId[c];\n        long long g1 = candG[c];\n\n        if (id1 != dummy_id) apply_add(st, actions[id1]);\n\n        long long bestg2 = 0;\n        int bestid2 = dummy_id;\n        const uint32_t* b2 = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g2 = gain_add(b2, actions[id]);\n            if (g2 > bestg2) {\n                bestg2 = g2;\n                bestid2 = id;\n            }\n        }\n\n        long long tot = g1 + bestg2;\n        if (tot > bestTot) {\n            bestTot = tot;\n            best1 = id1;\n            best2 = bestid2;\n        }\n\n        if (id1 != dummy_id) apply_remove(st, actions[id1]);\n    }\n\n    if (best1 != dummy_id) apply_add(st, actions[best1]);\n    if (best2 != dummy_id) apply_add(st, actions[best2]);\n    st.ops[p1] = best1;\n    st.ops[p2] = best2;\n\n    if (st.score > before) return true;\n\n    // revert\n    if (best1 != dummy_id) apply_remove(st, actions[best1]);\n    if (best2 != dummy_id) apply_remove(st, actions[best2]);\n    if (old1 != dummy_id) apply_add(st, actions[old1]);\n    if (old2 != dummy_id) apply_add(st, actions[old2]);\n    st.ops[p1] = old1;\n    st.ops[p2] = old2;\n    return false;\n}\n\nbool pair_local_search(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, int trials, int top_first,\n                       bool targeted, bool allow_neg_first,\n                       Timer& timer, double tl) {\n    vector<int> pool;\n    if (targeted) {\n        int ps = min(30, K);\n        pool = select_positions(st, actions, dummy_id, rng, ps, 0.85, true);\n    }\n\n    bool improved = false;\n    for (int t = 0; t < trials; t++) {\n        if ((t & 3) == 0 && timer.elapsed() >= tl) break;\n        if (pair_improve_once(st, actions, dummy_id, rng,\n                              targeted ? &pool : nullptr,\n                              top_first, allow_neg_first)) {\n            improved = true;\n        }\n    }\n    return improved;\n}\n\nvoid anneal_kick(State& st, const vector<Action>& actions, int dummy_id,\n                 XorShift64& rng, int steps, int sample_n,\n                 double T0, double T1, Timer& timer, double tl) {\n    const int A = dummy_id;\n    for (int t = 0; t < steps; t++) {\n        if ((t & 15) == 0 && timer.elapsed() >= tl) break;\n\n        double T = T0 + (T1 - T0) * (double)t / (double)max(1, steps - 1);\n\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n        long long oldScore = st.score;\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int nid = dummy_id;\n        int mode = rng.next_int(100);\n        if (mode < 10) {\n            nid = dummy_id;\n        } else {\n            long long bestg = LLONG_MIN;\n            int bestid = dummy_id;\n            for (int s = 0; s < sample_n; s++) {\n                int id = rng.next_int(A);\n                long long g = gain_add(st.board.data(), actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            nid = bestid;\n\n            if (mode >= 85) { // occasional random candidate\n                int rid = rng.next_int(A);\n                long long rg = gain_add(st.board.data(), actions[rid]);\n                if (rg > bestg - (long long)MOD / 8) nid = rid;\n            }\n        }\n\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (!accept) {\n            if (nid != dummy_id) apply_remove(st, actions[nid]);\n            if (old != dummy_id) apply_add(st, actions[old]);\n            st.ops[pos] = old;\n        }\n    }\n}\n\nvoid insert_elite(vector<State>& elite, const State& cand, int cap) {\n    for (const auto& e : elite) {\n        if (cand.score == e.score && cand.ops == e.ops) return;\n    }\n    elite.push_back(cand);\n    sort(elite.begin(), elite.end(), [](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)elite.size() > cap) elite.resize(cap);\n}\n\nint pick_elite_index(const vector<State>& elite, XorShift64& rng) {\n    int sz = (int)elite.size();\n    if (sz == 1) return 0;\n    int r = rng.next_int(100);\n    if (r < 55) return 0;\n    if (r < 82) return rng.next_int(min(sz, 3));\n    if (r < 94) return rng.next_int(min(sz, 5));\n    return rng.next_int(sz);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, M, Kin;\n    cin >> Nin >> M >> Kin;\n\n    array<uint32_t, CELLS> base{};\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(Nin); mix(M); mix(Kin);\n\n    for (int i = 0; i < Nin; i++) {\n        for (int j = 0; j < Nin; j++) {\n            uint32_t v;\n            cin >> v;\n            base[i * N + j] = v;\n            mix(v);\n        }\n    }\n\n    vector<array<array<uint32_t, 3>, 3>> stamp(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                uint32_t v;\n                cin >> v;\n                stamp[m][i][j] = v;\n                mix(v);\n            }\n        }\n    }\n\n    vector<Action> actions;\n    actions.reserve(M * (N - 2) * (N - 2));\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                ac.raw = 0;\n\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        uint32_t v = stamp[m][i][j];\n                        ac.val[t] = v;\n                        ac.thr[t] = MOD - v;\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.raw += v;\n                        t++;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n\n    const int dummy_id = (int)actions.size(); // 980\n    XorShift64 rng(seed);\n    Timer timer;\n    const double TL = 1.90;\n    const double MAIN_END = TL * 0.90;\n\n    // Initial solution\n    State best = construct_best_greedy(base, actions, dummy_id);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 45);\n    pair_local_search(best, actions, dummy_id, rng, 14, 6, true, false, timer, TL);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 16);\n\n    const int ELITE_CAP = 8;\n    vector<State> elite;\n    elite.reserve(ELITE_CAP + 4);\n    insert_elite(elite, best, ELITE_CAP);\n\n    // Multi-start initialization\n    while (timer.elapsed() < TL * 0.24) {\n        int topR = 3 + rng.next_int(5); // 3..7\n        State cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 22);\n\n        if (rng.next_int(100) < 65 && timer.elapsed() < TL * 0.23) {\n            int R = 6 + rng.next_int(5); // 6..10\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.70, true);\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, 4 + rng.next_int(2), false);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 8);\n        }\n\n        if (rng.next_int(100) < 50) {\n            pair_local_search(cand, actions, dummy_id, rng, 8, 6, true, false, timer, TL);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 6);\n        }\n\n        if (cand.score > best.score) best = cand;\n        insert_elite(elite, cand, ELITE_CAP);\n    }\n\n    int stagnation = 0;\n\n    // Main search loop\n    while (timer.elapsed() < MAIN_END) {\n        int ei = pick_elite_index(elite, rng);\n        State cand = elite[ei];\n\n        int mode = rng.next_int(100);\n\n        if (mode < 46) {\n            int R = (stagnation < 20) ? (5 + rng.next_int(5)) : (8 + rng.next_int(6));\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.78, true);\n            bool allow_neg = (stagnation > 35 && rng.next_int(100) < 35);\n            int topR = 4 + rng.next_int(3); // 4..6\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, topR, allow_neg);\n        } else if (mode < 67) {\n            int cnt = 2 + rng.next_int((stagnation < 25) ? 10 : 20);\n            random_perturb(cand, actions, dummy_id, rng, cnt);\n        } else if (mode < 84) {\n            int steps = (stagnation < 25) ? 60 : 110;\n            int sample_n = (stagnation < 25) ? 22 : 30;\n            double T0 = (stagnation < 25) ? 3.0e8 : 5.0e8;\n            anneal_kick(cand, actions, dummy_id, rng, steps, sample_n, T0, 3.0e6, timer, MAIN_END);\n        } else {\n            int topR = 3 + rng.next_int(5);\n            cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, MAIN_END, rng, 9 + (stagnation > 30 ? 5 : 0));\n\n        if (rng.next_int(100) < 42) {\n            bool allow_neg_pair = (stagnation > 40 && rng.next_int(100) < 40);\n            pair_local_search(cand, actions, dummy_id, rng,\n                              6 + (stagnation > 25 ? 4 : 0),\n                              6, true, allow_neg_pair, timer, MAIN_END);\n            local_opt(cand, actions, dummy_id, timer, MAIN_END, rng, 4);\n        }\n\n        if (cand.score > best.score) {\n            best = cand;\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n        insert_elite(elite, cand, ELITE_CAP);\n\n        if (stagnation > 70 && timer.elapsed() < MAIN_END * 0.98) {\n            State kick = best;\n            auto pos = select_positions(kick, actions, dummy_id, rng, 12, 0.82, true);\n            destroy_repair_guided(kick, actions, dummy_id, pos, rng, 6, true);\n            local_opt(kick, actions, dummy_id, timer, MAIN_END, rng, 14);\n\n            if (kick.score > best.score) {\n                best = kick;\n                stagnation = 0;\n                insert_elite(elite, best, ELITE_CAP);\n            } else {\n                stagnation = 30;\n            }\n        }\n    }\n\n    // Final intensification\n    while (timer.elapsed() < TL) {\n        State cand = best;\n        int mode = rng.next_int(100);\n\n        if (mode < 68) {\n            int R = 7 + rng.next_int(5); // 7..11\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.85, true);\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, 6, true);\n        } else {\n            anneal_kick(cand, actions, dummy_id, rng, 90, 28, 2.5e8, 2.0e6, timer, TL);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 12);\n        pair_local_search(cand, actions, dummy_id, rng, 10, 6, true, true, timer, TL);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 8);\n\n        if (cand.score > best.score) {\n            best = cand;\n            insert_elite(elite, best, ELITE_CAP);\n        }\n\n        if (timer.elapsed() > TL - 0.018) break;\n    }\n\n    vector<tuple<int, int, int>> ans;\n    ans.reserve(K);\n    for (int i = 0; i < K; i++) {\n        int id = best.ops[i];\n        if (id == dummy_id) continue;\n        const auto& ac = actions[id];\n        ans.emplace_back(ac.m, ac.p, ac.q);\n    }\n\n    cout << ans.size() << '\\n';\n    for (auto [m, p, q] : ans) {\n        cout << m << ' ' << p << ' ' << q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n/* ===================== Greedy strict baseline ===================== */\n\nstruct GreedySolver {\n    int N;\n    const vector<vector<int>>& A;\n    int revealDepthW;\n\n    vector<int> nextIn;\n    vector<vector<int>> grid; // -1 or container id\n    int pr = 0, pc = 0;\n    int hold = -1;\n\n    vector<int> srcRow, srcIdx;\n    vector<char> dispatched;\n    vector<int> need; // next required in each dispatch row\n    int dispatchedCnt = 0;\n\n    int turn = 0;\n    string acts;\n\n    GreedySolver(int n, const vector<vector<int>>& a, int rw)\n        : N(n), A(a), revealDepthW(rw) {\n        nextIn.assign(N, 0);\n        grid.assign(N, vector<int>(N, -1));\n        srcRow.assign(N * N, -1);\n        srcIdx.assign(N * N, -1);\n        dispatched.assign(N * N, 0);\n        need.resize(N);\n        for (int r = 0; r < N; r++) need[r] = r * N;\n\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n    }\n\n    inline int md(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    inline bool is_ready(int v) const {\n        int dr = v / N;\n        int hi = dr * N + (N - 1);\n        return (need[dr] <= hi && v == need[dr]);\n    }\n\n    void spawn_step() {\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] >= N) continue;\n            if (grid[r][0] != -1) continue;\n            // spawn blocked only if crane is holding at gate\n            if (pr == r && pc == 0 && hold != -1) continue;\n            grid[r][0] = A[r][nextIn[r]];\n            nextIn[r]++;\n        }\n    }\n\n    void dispatch_step() {\n        int dc = N - 1;\n        for (int r = 0; r < N; r++) {\n            if (grid[r][dc] == -1) continue;\n            int v = grid[r][dc];\n            grid[r][dc] = -1;\n\n            if (!dispatched[v]) {\n                dispatched[v] = 1;\n                dispatchedCnt++;\n            }\n\n            int dr = v / N;\n            int hi = dr * N + (N - 1);\n            while (need[dr] <= hi && dispatched[need[dr]]) need[dr]++;\n        }\n    }\n\n    // one full turn: spawn -> action -> dispatch\n    void apply(char act) {\n        if (turn >= 10000) return;\n\n        spawn_step();\n\n        char real = act;\n        if (act == 'P') {\n            if (!(hold == -1 && grid[pr][pc] != -1)) real = '.';\n        } else if (act == 'Q') {\n            if (!(hold != -1 && grid[pr][pc] == -1)) real = '.';\n        } else if (act == 'U') {\n            if (pr == 0) real = '.';\n        } else if (act == 'D') {\n            if (pr == N - 1) real = '.';\n        } else if (act == 'L') {\n            if (pc == 0) real = '.';\n        } else if (act == 'R') {\n            if (pc == N - 1) real = '.';\n        } else if (act != '.') {\n            real = '.';\n        }\n\n        switch (real) {\n            case 'P':\n                hold = grid[pr][pc];\n                grid[pr][pc] = -1;\n                break;\n            case 'Q':\n                grid[pr][pc] = hold;\n                hold = -1;\n                break;\n            case 'U': pr--; break;\n            case 'D': pr++; break;\n            case 'L': pc--; break;\n            case 'R': pc++; break;\n            case '.': break;\n        }\n\n        dispatch_step();\n        acts.push_back(real);\n        turn++;\n    }\n\n    bool find_container(int v, int& rr, int& cc) const {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == v) {\n                    rr = r; cc = c;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool has_ready_container(int& bestV, int& bestR, int& bestC) const {\n        int bestScore = INT_MAX;\n        bestV = -1; bestR = -1; bestC = -1;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (!find_container(x, r, c)) continue;\n\n            int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestV = x; bestR = r; bestC = c;\n            }\n        }\n        return bestV != -1;\n    }\n\n    int choose_reveal_row() const {\n        int bestRow = -1;\n        int bestScore = INT_MAX;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (find_container(x, r, c)) continue; // already on board\n\n            int s = srcRow[x];\n            int frontIdx = (grid[s][0] != -1 ? nextIn[s] - 1 : nextIn[s]);\n            int depth = srcIdx[x] - frontIdx;\n            if (depth < 0) depth = 0;\n\n            int sc = depth * revealDepthW + md(pr, pc, s, 0);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestRow = dr;\n            }\n        }\n        return bestRow;\n    }\n\n    pair<int,int> choose_storage_cell() const {\n        int bestR = -1, bestC = -1;\n        int bestScore = INT_MAX;\n        int dr = (hold == -1 ? 0 : hold / N);\n\n        // prefer internal columns\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= N - 2; c++) {\n                if (grid[r][c] != -1) continue;\n                int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestR = r; bestC = c;\n                }\n            }\n        }\n\n        // then exhausted receiving gates\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] != N) continue;\n            if (grid[r][0] != -1) continue;\n            int sc = md(pr, pc, r, 0) + md(r, 0, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestR = r; bestC = 0;\n            }\n        }\n\n        // fallback: any free receiving gate (active) with penalty\n        for (int r = 0; r < N; r++) {\n            if (grid[r][0] != -1) continue;\n            int pen = (nextIn[r] < N ? 35 : 0);\n            int sc = md(pr, pc, r, 0) + md(r, 0, dr, N - 1) + pen;\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestR = r; bestC = 0;\n            }\n        }\n\n        return {bestR, bestC};\n    }\n\n    pair<int,int> nearest_container() const {\n        int bestR = -1, bestC = -1, best = INT_MAX;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == -1) continue;\n                int d = md(pr, pc, r, c);\n                if (d < best) {\n                    best = d;\n                    bestR = r; bestC = c;\n                }\n            }\n        }\n        return {bestR, bestC};\n    }\n\n    void move_to(int tr, int tc) {\n        while (turn < 10000 && (pr != tr || pc != tc)) {\n            if (pc < tc) apply('R');\n            else if (pc > tc) apply('L');\n            else if (pr < tr) apply('D');\n            else apply('U');\n        }\n    }\n\n    void dispatch_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        int dr = hold / N;\n        move_to(dr, N - 1);\n        if (turn < 10000) apply('Q');\n    }\n\n    void store_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        auto [sr, sc] = choose_storage_cell();\n        if (sr == -1) {\n            apply('.');\n            return;\n        }\n        move_to(sr, sc);\n        if (turn < 10000) apply('Q');\n    }\n\n    vector<char> solve(bool& complete) {\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n                continue;\n            }\n\n            int v, r, c;\n            if (has_ready_container(v, r, c)) {\n                move_to(r, c);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) {\n                    if (is_ready(hold)) dispatch_holding();\n                    else store_holding();\n                }\n                continue;\n            }\n\n            int rr = choose_reveal_row();\n            if (rr != -1) {\n                int x = need[rr];\n                int s = srcRow[x];\n                move_to(s, 0);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) {\n                    if (is_ready(hold)) dispatch_holding();\n                    else store_holding();\n                }\n                continue;\n            }\n\n            auto [nr, nc] = nearest_container();\n            if (nr == -1) {\n                bool anyQueue = false;\n                for (int i = 0; i < N; i++) if (nextIn[i] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(nr, nc);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n            }\n        }\n\n        if (turn < 10000 && hold != -1) {\n            if (is_ready(hold)) dispatch_holding();\n            else store_holding();\n        }\n\n        // safety cleanup\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n                continue;\n            }\n\n            auto [nr, nc] = nearest_container();\n            if (nr == -1) {\n                bool anyQueue = false;\n                for (int i = 0; i < N; i++) if (nextIn[i] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(nr, nc);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n            }\n        }\n\n        complete = (dispatchedCnt == N * N && hold == -1);\n        vector<char> res(acts.begin(), acts.end());\n        if (res.empty()) res.push_back('.');\n        return res;\n    }\n};\n\n/* ===================== Strict simulator + beam ===================== */\n\nstruct BeamSolver {\n    static constexpr int N = 5;\n    vector<vector<int>> A;\n    array<int, 25> srcRow{}, srcIdx{};\n    int dist[25][25]{};\n\n    struct State {\n        array<int8_t, 25> cell;   // -1 empty, 0..24 container\n        array<int8_t, 25> loc;    // -3 dispatched, -2 hold, -1 not yet on board, 0..24 on board\n        array<uint8_t, 5> nextIn; // 0..5\n        array<uint8_t, 5> need;   // current required by dispatch row\n        int8_t hold;              // -1 or 0..24\n        uint8_t pos;              // 0..24\n    };\n\n    struct Trace {\n        int parent;\n        char act;\n    };\n\n    struct BeamItem {\n        State st;\n        int trace;\n        int eval;\n    };\n\n    struct Cand {\n        State st;\n        int parentTrace;\n        char act;\n        int eval;\n        uint64_t h;\n    };\n\n    BeamSolver(const vector<vector<int>>& a) : A(a) {\n        srcRow.fill(-1);\n        srcIdx.fill(-1);\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n        for (int i = 0; i < 25; i++) {\n            for (int j = 0; j < 25; j++) {\n                dist[i][j] = abs(i / N - j / N) + abs(i % N - j % N);\n            }\n        }\n    }\n\n    State initial_state() const {\n        State s;\n        s.cell.fill(-1);\n        s.loc.fill(-1);\n        s.nextIn.fill(0);\n        for (int r = 0; r < N; r++) s.need[r] = (uint8_t)(r * N);\n        s.hold = -1;\n        s.pos = 0;\n        return s;\n    }\n\n    inline int dispatched_count(const State& s) const {\n        int d = 0;\n        for (int r = 0; r < N; r++) d += (int)s.need[r] - r * N;\n        return d;\n    }\n\n    inline bool is_goal(const State& s) const {\n        return dispatched_count(s) == 25 && s.hold == -1;\n    }\n\n    void spawn(State& s) const {\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] != -1) continue;\n            if (s.pos == g && s.hold != -1) continue;\n            int v = A[r][s.nextIn[r]];\n            s.nextIn[r]++;\n            s.cell[g] = (int8_t)v;\n            s.loc[v] = (int8_t)g;\n        }\n    }\n\n    // sp: already after spawn\n    bool apply_action_dispatch(const State& sp, char act, State& ns) const {\n        ns = sp;\n        int p = ns.pos;\n        int r = p / N, c = p % N;\n\n        switch (act) {\n            case '.':\n                break;\n            case 'P': {\n                if (ns.hold != -1) return false;\n                int v = ns.cell[p];\n                if (v < 0) return false;\n                ns.hold = (int8_t)v;\n                ns.cell[p] = -1;\n                ns.loc[v] = -2;\n                break;\n            }\n            case 'Q': {\n                if (ns.hold == -1) return false;\n                if (ns.cell[p] != -1) return false;\n                if (c == N - 1) {\n                    // strict in-order dispatch only\n                    if (ns.hold != (int8_t)ns.need[r]) return false;\n                }\n                int v = ns.hold;\n                ns.hold = -1;\n                ns.cell[p] = (int8_t)v;\n                ns.loc[v] = (int8_t)p;\n                break;\n            }\n            case 'U':\n                if (r == 0) return false;\n                ns.pos = (uint8_t)(p - N);\n                break;\n            case 'D':\n                if (r == N - 1) return false;\n                ns.pos = (uint8_t)(p + N);\n                break;\n            case 'L':\n                if (c == 0) return false;\n                ns.pos = (uint8_t)(p - 1);\n                break;\n            case 'R':\n                if (c == N - 1) return false;\n                ns.pos = (uint8_t)(p + 1);\n                break;\n            default:\n                return false;\n        }\n\n        // strict dispatch\n        for (int rr = 0; rr < N; rr++) {\n            int idx = rr * N + (N - 1);\n            int v = ns.cell[idx];\n            if (v == -1) continue;\n            if (v != ns.need[rr]) return false;\n            ns.need[rr]++;\n            ns.cell[idx] = -1;\n            ns.loc[v] = -3;\n        }\n\n        return true;\n    }\n\n    int lower_bound(const State& s) const {\n        int lb = 0;\n        int pos = s.pos;\n\n        for (int v = 0; v < 25; v++) {\n            int dr = v / N;\n            if (v < (int)s.need[dr]) continue;\n\n            int gate = dr * N + (N - 1);\n            if (s.hold == v) {\n                lb += dist[pos][gate] + 1; // carry + drop\n                continue;\n            }\n\n            int lp = s.loc[v];\n            if (lp >= 0) {\n                lb += dist[lp][gate] + 2; // pick + carry + drop\n            } else if (lp == -1) {\n                int sr = srcRow[v];\n                lb += (abs(sr - dr) + (N - 1)) + 2;\n            } else if (lp == -2) {\n                lb += dist[pos][gate] + 1;\n            }\n        }\n        return lb;\n    }\n\n    int eval_state(const State& s, int lb, int mode, uint64_t seed, uint64_t h) const {\n        int disp = dispatched_count(s);\n        int ready = 0;\n        for (int r = 0; r < N; r++) {\n            int x = s.need[r];\n            if (x >= r * N + N) continue;\n            if (s.hold == x || s.loc[x] >= 0) ready++;\n        }\n\n        int e = disp * 100000 - lb * 450 + ready * 2500;\n        if (mode == 1) e += ready * 700;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            if (v == s.need[dr]) {\n                e += 6000 - dist[s.pos][dr * N + (N - 1)] * 180;\n            } else {\n                e -= 1200;\n            }\n        }\n\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] == -1) continue;\n            if (s.nextIn[r] == 0) continue;\n            int expected = A[r][s.nextIn[r] - 1];\n            if ((int)s.cell[g] != expected) e -= 5000;\n        }\n\n        if (seed != 0) {\n            int noise = (int)(splitmix64(h ^ seed) & 127ULL) - 63;\n            e += noise;\n        }\n\n        return e;\n    }\n\n    uint64_t hash_state(const State& s) const {\n        uint64_t h = 1469598103934665603ULL;\n        auto add = [&](uint8_t x) {\n            h ^= x;\n            h *= 1099511628211ULL;\n        };\n\n        add((uint8_t)s.pos);\n        add((uint8_t)(s.hold + 1));\n        for (int r = 0; r < N; r++) {\n            add(s.nextIn[r]);\n            add((uint8_t)((int)s.need[r] - r * N));\n        }\n        for (int i = 0; i < 25; i++) {\n            add((uint8_t)(s.cell[i] + 1));\n        }\n        return h;\n    }\n\n    void gen_actions(const State& s, array<char, 12>& acts, int& acnt, int mode) const {\n        acnt = 0;\n        bool used[256] = {};\n        auto add = [&](char ch) {\n            unsigned u = (unsigned char)ch;\n            if (!used[u]) {\n                used[u] = true;\n                acts[acnt++] = ch;\n            }\n        };\n        auto add_toward = [&](int target) {\n            int p = s.pos;\n            int r = p / N, c = p % N;\n            int tr = target / N, tc = target % N;\n            if (r < tr) add('D');\n            if (r > tr) add('U');\n            if (c < tc) add('R');\n            if (c > tc) add('L');\n        };\n\n        int kReady = (mode == 1 ? 4 : 3);\n        int kReveal = (mode == 1 ? 3 : 2);\n        int kStore = (mode == 1 ? 3 : 2);\n\n        int pos = s.pos;\n        int r = pos / N, c = pos % N;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            int gate = dr * N + (N - 1);\n\n            if (v == s.need[dr]) {\n                if (pos == gate && s.cell[pos] == -1) add('Q');\n                add_toward(gate);\n            } else {\n                if (s.cell[pos] == -1 && c != N - 1) add('Q');\n\n                pair<int,int> cand[25];\n                int m = 0;\n                for (int idx = 0; idx < 25; idx++) {\n                    int rr = idx / N, cc = idx % N;\n                    if (cc == N - 1) continue;\n                    if (s.cell[idx] != -1) continue;\n                    int pen = (cc == 0 && s.nextIn[rr] < N) ? 30 : 0;\n                    int sc = dist[pos][idx] + dist[idx][gate] + pen;\n                    cand[m++] = {sc, idx};\n                }\n                sort(cand, cand + m);\n                for (int i = 0; i < min(kStore, m); i++) add_toward(cand[i].second);\n            }\n        } else {\n            if (s.cell[pos] != -1) add('P');\n\n            pair<int,int> ready[5];\n            int rcnt = 0;\n            for (int rr = 0; rr < N; rr++) {\n                int x = s.need[rr];\n                if (x >= rr * N + N) continue;\n                int lp = s.loc[x];\n                if (lp >= 0) {\n                    int sc = dist[pos][lp] + dist[lp][rr * N + (N - 1)];\n                    ready[rcnt++] = {sc, lp};\n                }\n            }\n\n            if (rcnt > 0) {\n                sort(ready, ready + rcnt);\n                for (int i = 0; i < min(kReady, rcnt); i++) add_toward(ready[i].second);\n            } else {\n                pair<int,int> rev[5];\n                int vcnt = 0;\n                for (int rr = 0; rr < N; rr++) {\n                    int x = s.need[rr];\n                    if (x >= rr * N + N) continue;\n                    int sr = srcRow[x];\n                    int front = (int)s.nextIn[sr] - (s.cell[sr * N] == -1 ? 0 : 1);\n                    int depth = srcIdx[x] - front;\n                    if (depth < 0) depth = 0;\n                    int gp = sr * N;\n                    int sc = depth * 10 + dist[pos][gp];\n                    rev[vcnt++] = {sc, gp};\n                }\n                sort(rev, rev + vcnt);\n                for (int i = 0; i < min(kReveal, vcnt); i++) add_toward(rev[i].second);\n            }\n        }\n\n        if (acnt < 2) {\n            if (r > 0) add('U');\n            if (r < N - 1) add('D');\n            if (c > 0) add('L');\n            if (c < N - 1) add('R');\n        }\n\n        if (acnt == 0) add('.');\n    }\n\n    vector<char> reconstruct(int traceId, const vector<Trace>& traces) const {\n        vector<char> rev;\n        while (traceId > 0) {\n            rev.push_back(traces[traceId].act);\n            traceId = traces[traceId].parent;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    bool validate(const vector<char>& actions) const {\n        State s = initial_state();\n        for (char a : actions) {\n            State sp = s, ns;\n            spawn(sp);\n            if (!apply_action_dispatch(sp, a, ns)) return false;\n            s = ns;\n        }\n        return is_goal(s);\n    }\n\n    // Find improved solution:\n    // - need length < improveLen\n    // - prune with boundLen (can be > improveLen for looser pruning)\n    bool search(int improveLen, int boundLen, int width, int mode, uint64_t seed,\n                const Clock::time_point& deadline, vector<char>& outActions) const {\n        if (improveLen <= 1) return false;\n        boundLen = max(boundLen, improveLen);\n        int maxDepth = min(improveLen - 1, 10000);\n\n        vector<Trace> traces;\n        traces.reserve((size_t)width * 400 + 16);\n        traces.push_back({-1, '?'});\n\n        vector<BeamItem> cur, nxt;\n        cur.reserve(width + 16);\n        nxt.reserve(width + 16);\n\n        State init = initial_state();\n        int lb0 = lower_bound(init);\n        if (lb0 >= boundLen) return false;\n        cur.push_back({init, 0, eval_state(init, lb0, mode, seed, hash_state(init))});\n\n        vector<Cand> cands;\n        cands.reserve((size_t)width * 7 + 128);\n\n        auto over = [&]() -> bool {\n            return Clock::now() >= deadline;\n        };\n\n        for (int depth = 0; depth < maxDepth; depth++) {\n            if (over()) return false;\n            cands.clear();\n\n            int it = 0;\n            for (const auto& bi : cur) {\n                if ((it++ & 127) == 0 && over()) return false;\n\n                State sp = bi.st;\n                spawn(sp);\n\n                array<char, 12> acts{};\n                int acnt = 0;\n                gen_actions(sp, acts, acnt, mode);\n\n                for (int i = 0; i < acnt; i++) {\n                    State ns;\n                    char act = acts[i];\n                    if (!apply_action_dispatch(sp, act, ns)) continue;\n\n                    int nd = depth + 1;\n                    if (is_goal(ns)) {\n                        // nd < improveLen guaranteed by depth loop\n                        int tr = (int)traces.size();\n                        traces.push_back({bi.trace, act});\n                        outActions = reconstruct(tr, traces);\n                        return true;\n                    }\n\n                    int lb = lower_bound(ns);\n                    if (nd + lb >= boundLen) continue;\n\n                    uint64_t h = hash_state(ns);\n                    int ev = eval_state(ns, lb, mode, seed, h);\n                    cands.push_back({ns, bi.trace, act, ev, h});\n                }\n            }\n\n            if (cands.empty()) return false;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                if (a.h != b.h) return a.h < b.h;\n                return a.eval > b.eval;\n            });\n\n            vector<Cand> uniq;\n            uniq.reserve(cands.size());\n            for (size_t i = 0; i < cands.size();) {\n                size_t j = i + 1;\n                Cand best = cands[i];\n                while (j < cands.size() && cands[j].h == cands[i].h) {\n                    if (cands[j].eval > best.eval) best = cands[j];\n                    j++;\n                }\n                uniq.push_back(std::move(best));\n                i = j;\n            }\n\n            if ((int)uniq.size() > width) {\n                nth_element(uniq.begin(), uniq.begin() + width, uniq.end(),\n                            [](const Cand& a, const Cand& b) {\n                                return a.eval > b.eval;\n                            });\n                uniq.resize(width);\n            }\n\n            nxt.clear();\n            nxt.reserve(uniq.size());\n            for (const auto& cd : uniq) {\n                int tr = (int)traces.size();\n                traces.push_back({cd.parentTrace, cd.act});\n                nxt.push_back({cd.st, tr, cd.eval});\n            }\n\n            cur.swap(nxt);\n            if (cur.empty()) return false;\n        }\n\n        return false;\n    }\n};\n\n/* ===================== tiny local compression ===================== */\n\nstatic bool isOppMove(char a, char b) {\n    return (a == 'U' && b == 'D') || (a == 'D' && b == 'U') ||\n           (a == 'L' && b == 'R') || (a == 'R' && b == 'L');\n}\n\nstatic vector<char> compress_actions(vector<char> acts, const BeamSolver& beam,\n                                     const Clock::time_point& deadline) {\n    auto over = [&]() -> bool { return Clock::now() >= deadline; };\n\n    auto try_remove = [&](int l, int k) -> bool {\n        if (l < 0 || l + k > (int)acts.size()) return false;\n        vector<char> t;\n        t.reserve((int)acts.size() - k);\n        t.insert(t.end(), acts.begin(), acts.begin() + l);\n        t.insert(t.end(), acts.begin() + l + k, acts.end());\n        if (beam.validate(t)) {\n            acts.swap(t);\n            return true;\n        }\n        return false;\n    };\n\n    bool changed = true;\n    while (changed && !over()) {\n        changed = false;\n        for (int i = 0; i < (int)acts.size() && !over(); i++) {\n            if (acts[i] != '.') continue;\n            if (try_remove(i, 1)) {\n                changed = true;\n                break;\n            }\n        }\n    }\n\n    changed = true;\n    while (changed && !over()) {\n        changed = false;\n        for (int i = 0; i + 1 < (int)acts.size() && !over(); i++) {\n            if (!isOppMove(acts[i], acts[i + 1])) continue;\n            if (try_remove(i, 2)) {\n                changed = true;\n                break;\n            }\n        }\n    }\n\n    if (acts.empty()) acts.push_back('.');\n    return acts;\n}\n\n/* ===================== main ===================== */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> A(N, vector<int>(N));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> A[i][j];\n    }\n\n    auto start = Clock::now();\n\n    // Unexpected N fallback (problem states N=5 always)\n    if (N != 5) {\n        GreedySolver g(N, A, 100);\n        bool complete = false;\n        vector<char> acts = g.solve(complete);\n        if (acts.empty()) acts.push_back('.');\n        int T = (int)acts.size();\n        cout << string(acts.begin(), acts.end()) << '\\n';\n        for (int i = 1; i < N; i++) {\n            string s(T, '.');\n            s[0] = 'B';\n            cout << s << '\\n';\n        }\n        return 0;\n    }\n\n    BeamSolver beam(A);\n\n    // Multi-start greedy baseline\n    vector<int> revealWs = {100, 90, 110, 75};\n    const int INF = 1e9;\n\n    vector<char> bestStrictActs;\n    int bestStrictLen = INF;\n\n    vector<char> bestCompleteActs;\n    int bestCompleteLen = INF;\n\n    vector<char> bestAnyActs;\n    int bestAnyLen = INF;\n\n    for (int rw : revealWs) {\n        GreedySolver g(N, A, rw);\n        bool complete = false;\n        vector<char> acts = g.solve(complete);\n        if (acts.empty()) acts.push_back('.');\n        int L = (int)acts.size();\n\n        if (L < bestAnyLen) {\n            bestAnyLen = L;\n            bestAnyActs = acts;\n        }\n\n        if (complete && L < bestCompleteLen) {\n            bestCompleteLen = L;\n            bestCompleteActs = acts;\n        }\n\n        if (complete && beam.validate(acts) && L < bestStrictLen) {\n            bestStrictLen = L;\n            bestStrictActs = acts;\n        }\n    }\n\n    vector<char> bestActs;\n    bool bestStrict = false;\n\n    if (bestStrictLen < INF) {\n        bestActs = bestStrictActs;\n        bestStrict = true;\n    } else if (bestCompleteLen < INF) {\n        bestActs = bestCompleteActs;\n        bestStrict = beam.validate(bestActs);\n    } else {\n        bestActs = bestAnyActs;\n        bestStrict = beam.validate(bestActs);\n    }\n\n    if (bestActs.empty()) bestActs.push_back('.');\n    int bestLen = (int)bestActs.size();\n\n    vector<char> safeFallback = bestActs;\n    if (!beam.validate(safeFallback) && !bestStrictActs.empty()) {\n        safeFallback = bestStrictActs;\n    }\n\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            seed = splitmix64(seed ^ (uint64_t)(A[i][j] + 1) * 0x9e3779b97f4a7c15ULL);\n        }\n    }\n\n    auto hardDeadline = start + chrono::milliseconds(2780);\n\n    // Beam attempt 1 (deterministic)\n    if (bestStrict && Clock::now() + chrono::milliseconds(50) < hardDeadline) {\n        vector<char> cand;\n        int width1 = (bestLen <= 305 ? 2600 : 2300);\n        auto d1 = min(hardDeadline, start + chrono::milliseconds(2150));\n\n        bool ok = beam.search(\n            bestLen,                      // must beat this\n            min(10000, bestLen + 8),     // looser prune bound\n            width1,\n            0,                           // mode\n            0ULL,                        // deterministic\n            d1,\n            cand\n        );\n\n        if (ok && !cand.empty() && (int)cand.size() < bestLen && beam.validate(cand)) {\n            bestActs = cand;\n            bestLen = (int)bestActs.size();\n            bestStrict = true;\n        }\n    }\n\n    // Beam attempt 2 (diversified)\n    if (bestStrict && Clock::now() + chrono::milliseconds(40) < hardDeadline) {\n        vector<char> cand;\n        int width2 = (bestLen <= 305 ? 2000 : 1700);\n\n        bool ok = beam.search(\n            bestLen,\n            min(10000, bestLen + 10),\n            width2,\n            1,        // slightly different mode\n            seed,     // tiny randomized tie-break in eval\n            hardDeadline,\n            cand\n        );\n\n        if (ok && !cand.empty() && (int)cand.size() < bestLen && beam.validate(cand)) {\n            bestActs = cand;\n            bestLen = (int)bestActs.size();\n            bestStrict = true;\n        }\n    }\n\n    // Tiny post-compression\n    if (bestStrict && Clock::now() + chrono::milliseconds(20) < hardDeadline) {\n        vector<char> cmp = compress_actions(bestActs, beam, hardDeadline);\n        if (!cmp.empty() && (int)cmp.size() <= bestLen && beam.validate(cmp)) {\n            bestActs = cmp;\n            bestLen = (int)bestActs.size();\n        }\n    }\n\n    // Final safety\n    if (!beam.validate(bestActs)) {\n        bestActs = safeFallback;\n        if (bestActs.empty()) bestActs.push_back('.');\n    }\n\n    int T = (int)bestActs.size();\n    if (T <= 0) {\n        bestActs = {'.'};\n        T = 1;\n    }\n\n    cout << string(bestActs.begin(), bestActs.end()) << '\\n';\n    for (int i = 1; i < N; i++) {\n        string s(T, '.');\n        s[0] = 'B';\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SimResult {\n    long long cost = (1LL << 62);\n    int turns = 0;\n    bool valid = false;\n    vector<string> ops;\n};\n\nclass Solver {\n    static constexpr int MAX_N = 20;\n    static constexpr int MAX_M = 400;\n    static constexpr int MAX_TURNS = 100000;\n    static constexpr long long INF64 = (1LL << 62);\n    static constexpr int INF_CAP = 1000000000;\n    inline static const array<int, 11> CAPS = {\n        160, 220, 300, 400, 550, 750, 1000, 1400, 2000, 3000, INF_CAP\n    };\n\n    int N = 0, M = 0;\n    int init_h[MAX_M]{};\n    int rr[MAX_M]{}, cc[MAX_M]{};\n    uint8_t distm[MAX_M][MAX_M]{};\n\n    int init_near_pos[MAX_M]{};\n    int init_near_neg[MAX_M]{};\n    long long total_positive = 0;\n\n    uint64_t input_hash = 0;\n\n    vector<vector<int>> cycles;\n    vector<vector<int>> paths;\n\n    struct GParam {\n        int cap = 800;\n        int mode = 0;               // 0: strict, 1: mixed, 2: trip-aware\n        int dist_scale = 256;\n        int link_scale = 80;        // mainly mode=2\n        int src_bias = 2;\n        int dst_bias = 2;\n        bool collect_when_loaded = false;\n        int force_sink_ratio = 70;\n        int src_loaded_pen = 1;\n        int sink_empty_pen = 1;\n        int axis_pref = 2;          // 0 vertical, 1 horizontal, 2 adaptive\n        int path_unload_bonus = 130;\n        int path_load_bonus = 70;\n        int back_penalty = 40;\n        bool retarget_on_change = true;\n    };\n\n    enum class BestType { NONE, CYCLE, PATH, GREEDY };\n\n    struct CycleSpec {\n        int ci = 0;\n        int dir = 1;\n        int shift = 0;\n    };\n    struct PathSpec {\n        int pi = 0;\n        int cleanup_type = 0;\n    };\n    struct GreedySpec {\n        GParam p{};\n        uint64_t seed = 1;\n    };\n    struct EliteItem {\n        GParam p{};\n        uint64_t seed = 1;\n        long long cost = INF64;\n    };\n\n    static uint64_t xorshift64(uint64_t &x) {\n        if (x == 0) x = 88172645463325252ULL;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n\n    static int randInt(uint64_t &x, int l, int r) {\n        return l + (int)(xorshift64(x) % (uint64_t)(r - l + 1));\n    }\n\n    int modM(int x) const {\n        x %= M;\n        if (x < 0) x += M;\n        return x;\n    }\n\n    vector<int> buildBaseCycle() const {\n        // Hamiltonian cycle for even N\n        vector<int> cyc;\n        cyc.reserve(M);\n\n        for (int c = 0; c < N; c++) cyc.push_back(c);\n        for (int r = 1; r < N; r++) {\n            if (r & 1) for (int c = N - 1; c >= 1; c--) cyc.push_back(r * N + c);\n            else for (int c = 1; c < N; c++) cyc.push_back(r * N + c);\n        }\n        for (int r = N - 1; r >= 1; r--) cyc.push_back(r * N);\n\n        return cyc;\n    }\n\n    pair<int, int> transformPoint(int r, int c, int t) const {\n        switch (t) {\n            case 0: return {r, c};\n            case 1: return {r, N - 1 - c};\n            case 2: return {N - 1 - r, c};\n            case 3: return {N - 1 - r, N - 1 - c};\n            case 4: return {c, r};\n            case 5: return {c, N - 1 - r};\n            case 6: return {N - 1 - c, r};\n            case 7: return {N - 1 - c, N - 1 - r};\n        }\n        return {r, c};\n    }\n\n    vector<int> transformCycle(const vector<int> &base, int t) const {\n        vector<int> out;\n        out.reserve(M);\n        for (int id : base) {\n            int r = id / N, c = id % N;\n            auto [nr, nc] = transformPoint(r, c, t);\n            out.push_back(nr * N + nc);\n        }\n        auto it = find(out.begin(), out.end(), 0);\n        if (it != out.end()) rotate(out.begin(), it, out.end());\n        return out;\n    }\n\n    vector<int> buildRowSnake() const {\n        vector<int> v;\n        v.reserve(M);\n        for (int r = 0; r < N; r++) {\n            if ((r & 1) == 0) for (int c = 0; c < N; c++) v.push_back(r * N + c);\n            else for (int c = N - 1; c >= 0; c--) v.push_back(r * N + c);\n        }\n        return v;\n    }\n\n    vector<int> buildColSnake() const {\n        vector<int> v;\n        v.reserve(M);\n        for (int c = 0; c < N; c++) {\n            if ((c & 1) == 0) for (int r = 0; r < N; r++) v.push_back(r * N + c);\n            else for (int r = N - 1; r >= 0; r--) v.push_back(r * N + c);\n        }\n        return v;\n    }\n\n    vector<int> buildSpiralCW() const {\n        vector<int> ord;\n        ord.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int c = left; c <= right; c++) ord.push_back(top * N + c);\n            top++;\n            for (int r = top; r <= bottom; r++) ord.push_back(r * N + right);\n            right--;\n            if (top <= bottom) {\n                for (int c = right; c >= left; c--) ord.push_back(bottom * N + c);\n                bottom--;\n            }\n            if (left <= right) {\n                for (int r = bottom; r >= top; r--) ord.push_back(r * N + left);\n                left++;\n            }\n        }\n        return ord;\n    }\n\n    vector<int> buildSpiralCCW() const {\n        vector<int> ord;\n        ord.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int r = top; r <= bottom; r++) ord.push_back(r * N + left);\n            left++;\n            for (int c = left; c <= right; c++) ord.push_back(bottom * N + c);\n            bottom--;\n            if (left <= right) {\n                for (int r = bottom; r >= top; r--) ord.push_back(r * N + right);\n                right--;\n            }\n            if (top <= bottom) {\n                for (int c = right; c >= left; c--) ord.push_back(top * N + c);\n                top++;\n            }\n        }\n        return ord;\n    }\n\n    bool isValidPath(const vector<int> &ord) const {\n        if ((int)ord.size() != M) return false;\n        if (ord[0] != 0) return false;\n\n        static int seen[MAX_M];\n        for (int i = 0; i < M; i++) seen[i] = 0;\n\n        for (int i = 0; i < M; i++) {\n            int id = ord[i];\n            if (id < 0 || id >= M || seen[id]) return false;\n            seen[id] = 1;\n            if (i > 0 && distm[ord[i - 1]][id] != 1) return false;\n        }\n        return true;\n    }\n\n    void addPathIfValid(const vector<int> &ord) {\n        if (!isValidPath(ord)) return;\n        for (auto &p : paths) if (p == ord) return;\n        paths.push_back(ord);\n    }\n\n    void addPathTransforms(const vector<int> &base) {\n        for (int t = 0; t < 8; t++) {\n            vector<int> p;\n            p.reserve(M);\n            for (int id : base) {\n                int r = id / N, c = id % N;\n                auto [nr, nc] = transformPoint(r, c, t);\n                p.push_back(nr * N + nc);\n            }\n            addPathIfValid(p);\n            reverse(p.begin(), p.end());\n            addPathIfValid(p);\n        }\n    }\n\n    template <bool RECORD>\n    SimResult simulateCycle(const vector<int> &cyc, int dir, int shift, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0, idx = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(30000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        // initial shift\n        for (int t = 0; t < shift; t++) {\n            idx = modM(idx + dir);\n            if (!doMove(cyc[idx])) return fail();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n        }\n\n        // one-pass processing\n        for (int t = 0; t < M; t++) {\n            int cell = cyc[idx];\n            if (h[cell] > 0) {\n                doLoad(h[cell]);\n                h[cell] = 0;\n            } else if (h[cell] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[cell]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                idx = modM(idx + dir);\n                if (!doMove(cyc[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // cleanup remaining deficits if load > 0\n        while (load > 0) {\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (load == 0) break;\n\n            int best = -1, bestDist = INT_MAX, bestDef = -1;\n            for (int id = 0; id < M; id++) if (h[id] < 0) {\n                int d = distm[pos][id];\n                int def = -h[id];\n                if (d < bestDist || (d == bestDist && def > bestDef)) {\n                    bestDist = d;\n                    bestDef = def;\n                    best = id;\n                }\n            }\n            if (best < 0) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (nxt < 0) return fail();\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!doMove(nxt)) return fail();\n\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (turns <= MAX_TURNS && load == 0 && posRemain == 0 && negRemain == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    template <bool RECORD>\n    SimResult simulatePath(const vector<int> &ord, int cleanup_type, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(35000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        for (int t = 0; t < M; t++) {\n            int cell = ord[t];\n            if (cell != pos) return fail();\n\n            if (h[cell] > 0) {\n                doLoad(h[cell]);\n                h[cell] = 0;\n            } else if (h[cell] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[cell]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                if (!doMove(ord[t + 1])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // optional reverse backtrack before nearest cleanup\n        if (cleanup_type == 1) {\n            int idx = M - 1;\n            while (load > 0 && idx > 0) {\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n                if (load == 0) break;\n\n                idx--;\n                if (!doMove(ord[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        while (load > 0) {\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (load == 0) break;\n\n            int best = -1, bestDist = INT_MAX, bestDef = -1;\n            for (int id = 0; id < M; id++) if (h[id] < 0) {\n                int d = distm[pos][id];\n                int def = -h[id];\n                if (d < bestDist || (d == bestDist && def > bestDef)) {\n                    bestDist = d;\n                    bestDef = def;\n                    best = id;\n                }\n            }\n            if (best < 0) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (nxt < 0) return fail();\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!doMove(nxt)) return fail();\n\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (turns <= MAX_TURNS && load == 0 && posRemain == 0 && negRemain == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    template <bool RECORD>\n    SimResult simulateGreedy(const GParam &p, uint64_t seed, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0, prevPos = -1;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(100000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        auto canLoadPolicy = [&](long long curLoad) -> bool {\n            if (curLoad >= p.cap) return false;\n            if (curLoad == 0) return true;\n            return p.collect_when_loaded;\n        };\n\n        auto processHere = [&]() {\n            if (load > 0 && h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (h[pos] > 0 && canLoadPolicy(load)) {\n                long long room = (long long)p.cap - load;\n                if (room > 0) {\n                    int d = (int)min<long long>(room, (long long)h[pos]);\n                    if (d > 0) {\n                        doLoad(d);\n                        h[pos] -= d;\n                    }\n                }\n            }\n        };\n\n        struct TargetInfo {\n            int id = -1;\n            long long val = INF64;\n            int gain = -1;\n        };\n\n        auto bestSource = [&](int from, long long curLoad) -> TargetInfo {\n            TargetInfo best;\n            if (!canLoadPolicy(curLoad)) return best;\n            long long room = (long long)p.cap - curLoad;\n            if (room <= 0) return best;\n\n            for (int id = 0; id < M; id++) {\n                int amt = h[id];\n                if (amt <= 0) continue;\n\n                int gain = (int)min<long long>((long long)amt, room);\n                int d = distm[from][id];\n\n                long long val = 1LL * p.dist_scale * d - 1LL * p.src_bias * gain;\n                if (p.mode == 2) val += 1LL * p.link_scale * init_near_neg[id];\n\n                if (val < best.val ||\n                    (val == best.val && gain > best.gain) ||\n                    (val == best.val && gain == best.gain && (xorshift64(seed) & 1ULL))) {\n                    best.id = id;\n                    best.val = val;\n                    best.gain = gain;\n                }\n            }\n            return best;\n        };\n\n        auto bestSink = [&](int from, long long curLoad) -> TargetInfo {\n            TargetInfo best;\n            if (curLoad <= 0) return best;\n\n            for (int id = 0; id < M; id++) {\n                int amt = -h[id];\n                if (amt <= 0) continue;\n\n                int gain = (int)min<long long>((long long)amt, curLoad);\n                int d = distm[from][id];\n\n                long long val = 1LL * p.dist_scale * d - 1LL * p.dst_bias * gain;\n                if (p.mode == 2) val += 1LL * p.link_scale * init_near_pos[id];\n\n                if (val < best.val ||\n                    (val == best.val && gain > best.gain) ||\n                    (val == best.val && gain == best.gain && (xorshift64(seed) & 1ULL))) {\n                    best.id = id;\n                    best.val = val;\n                    best.gain = gain;\n                }\n            }\n            return best;\n        };\n\n        auto chooseNext = [&](int target, int prevCell) -> int {\n            int r = rr[pos], c = cc[pos];\n            int tr = rr[target], tc = cc[target];\n\n            int cand[2];\n            int sz = 0;\n            if (r < tr) cand[sz++] = pos + N;\n            else if (r > tr) cand[sz++] = pos - N;\n            if (c < tc) cand[sz++] = pos + 1;\n            else if (c > tc) cand[sz++] = pos - 1;\n\n            if (sz == 0) return -1;\n            if (sz == 1) return cand[0];\n\n            auto scoreCell = [&](int id) -> long long {\n                long long s = 0;\n                if (load > 0 && h[id] < 0) {\n                    s += 1LL * p.path_unload_bonus * min<long long>(load, -1LL * h[id]);\n                }\n                if (canLoadPolicy(load) && h[id] > 0) {\n                    long long room = (long long)p.cap - load;\n                    if (room > 0) {\n                        s += 1LL * p.path_load_bonus * min<long long>(room, (long long)h[id]);\n                    }\n                }\n                if (id == prevCell) s -= p.back_penalty;\n                return s;\n            };\n\n            long long s0 = scoreCell(cand[0]);\n            long long s1 = scoreCell(cand[1]);\n            if (s1 > s0) return cand[1];\n            if (s1 < s0) return cand[0];\n\n            bool v0 = (rr[cand[0]] != r);\n            bool v1 = (rr[cand[1]] != r);\n\n            if (p.axis_pref == 0) {\n                if (v0 != v1) return v0 ? cand[0] : cand[1];\n            } else if (p.axis_pref == 1) {\n                if (v0 != v1) return v0 ? cand[1] : cand[0];\n            } else {\n                int dr = abs(tr - r), dc = abs(tc - c);\n                if (dr != dc && v0 != v1) {\n                    if (dr > dc) return v0 ? cand[0] : cand[1];\n                    else return v0 ? cand[1] : cand[0];\n                }\n            }\n\n            return (xorshift64(seed) & 1ULL) ? cand[0] : cand[1];\n        };\n\n        int stagnation = 0;\n\n        for (int outer = 0; outer < 180000; outer++) {\n            long long beforePos = posRemain;\n            long long beforeNeg = negRemain;\n            long long beforeLoad = load;\n            int beforeCell = pos;\n\n            processHere();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n            TargetInfo src = bestSource(pos, load);\n            TargetInfo sink = bestSink(pos, load);\n\n            bool seekSource = false;\n            if (p.mode == 0) {\n                seekSource = (load == 0);\n            } else {\n                if (load == 0) {\n                    seekSource = true;\n                } else {\n                    long long refCap = (p.cap >= INF_CAP / 2)\n                        ? min<long long>(max<long long>(400, total_positive / 3), 4000)\n                        : p.cap;\n\n                    if (load * 100 >= 1LL * p.force_sink_ratio * refCap) {\n                        seekSource = false;\n                    } else {\n                        long long srcEval = (src.id == -1 ? INF64 : src.val + 1LL * p.src_loaded_pen * load);\n                        long long sinkEval = (sink.id == -1 ? INF64 : sink.val + 1LL * p.sink_empty_pen * max<long long>(0, refCap - load));\n\n                        if (p.mode == 2) {\n                            sinkEval -= load / 5;\n                            if (load > refCap / 2) srcEval += load / 8;\n                        }\n                        seekSource = (srcEval < sinkEval);\n                    }\n                }\n            }\n\n            if (seekSource && src.id == -1) seekSource = false;\n            if (!seekSource && sink.id == -1) seekSource = true;\n\n            int target = seekSource ? src.id : sink.id;\n            if (target < 0) return fail();\n\n            long long startLoad = load;\n            int guard = 0;\n\n            while (pos != target) {\n                int nxt = chooseNext(target, prevPos);\n                if (nxt < 0) return fail();\n\n                int old = pos;\n                if (!doMove(nxt)) return fail();\n                prevPos = old;\n\n                processHere();\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n                if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n                if (seekSource) {\n                    if (load >= p.cap) break;\n                    if (!p.collect_when_loaded && load > 0) break;\n                    if (p.retarget_on_change && load > startLoad) break;\n                } else {\n                    if (load == 0) break;\n                    if (p.retarget_on_change && load < startLoad) break;\n                }\n\n                if (++guard > 3000) break;\n            }\n\n            if (beforePos == posRemain && beforeNeg == negRemain &&\n                beforeLoad == load && beforeCell == pos) stagnation++;\n            else stagnation = 0;\n\n            if (stagnation > 3200) return fail();\n        }\n\n        bool valid = (turns <= MAX_TURNS && posRemain == 0 && negRemain == 0 && load == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    int capIndex(int cap) const {\n        int best = 0;\n        long long bestDiff = llabs((long long)CAPS[0] - cap);\n        for (int i = 1; i < (int)CAPS.size(); i++) {\n            long long d = llabs((long long)CAPS[i] - cap);\n            if (d < bestDiff) {\n                bestDiff = d;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    GParam randomParam(uint64_t &rng) const {\n        GParam p;\n        p.cap = CAPS[randInt(rng, 0, (int)CAPS.size() - 1)];\n        p.mode = randInt(rng, 0, 2);\n        p.dist_scale = randInt(rng, 150, 430);\n        p.link_scale = randInt(rng, 0, 260);\n        p.src_bias = randInt(rng, 0, 12);\n        p.dst_bias = randInt(rng, 0, 12);\n\n        int collectProb = (p.mode == 0 ? 25 : 45);\n        p.collect_when_loaded = (randInt(rng, 0, 99) < collectProb);\n\n        p.force_sink_ratio = randInt(rng, 40, 95);\n        p.src_loaded_pen = randInt(rng, 0, 8);\n        p.sink_empty_pen = randInt(rng, 0, 8);\n        p.axis_pref = randInt(rng, 0, 2);\n        p.path_unload_bonus = randInt(rng, 60, 260);\n        p.path_load_bonus = randInt(rng, 10, 190);\n        p.back_penalty = randInt(rng, 0, 180);\n        p.retarget_on_change = (randInt(rng, 0, 1) == 1);\n        return p;\n    }\n\n    GParam mutateParam(const GParam &base, uint64_t &rng) const {\n        GParam p = base;\n\n        auto clampi = [&](int &x, int l, int r) {\n            if (x < l) x = l;\n            if (x > r) x = r;\n        };\n\n        int changes = randInt(rng, 1, 5);\n        for (int it = 0; it < changes; it++) {\n            int sw = randInt(rng, 0, 14);\n            int delta = (int)(xorshift64(rng) % 5ULL) - 2; // [-2,2]\n\n            switch (sw) {\n                case 0: {\n                    int idx = capIndex(p.cap);\n                    idx += delta;\n                    idx = max(0, min((int)CAPS.size() - 1, idx));\n                    p.cap = CAPS[idx];\n                    break;\n                }\n                case 1:\n                    p.mode = randInt(rng, 0, 2);\n                    break;\n                case 2:\n                    p.dist_scale += delta * 20;\n                    clampi(p.dist_scale, 130, 520);\n                    break;\n                case 3:\n                    p.link_scale += delta * 20;\n                    clampi(p.link_scale, 0, 340);\n                    break;\n                case 4:\n                    p.src_bias += delta;\n                    clampi(p.src_bias, 0, 16);\n                    break;\n                case 5:\n                    p.dst_bias += delta;\n                    clampi(p.dst_bias, 0, 16);\n                    break;\n                case 6:\n                    p.collect_when_loaded = !p.collect_when_loaded;\n                    break;\n                case 7:\n                    p.force_sink_ratio += delta * 5;\n                    clampi(p.force_sink_ratio, 30, 99);\n                    break;\n                case 8:\n                    p.src_loaded_pen += delta;\n                    clampi(p.src_loaded_pen, 0, 12);\n                    break;\n                case 9:\n                    p.sink_empty_pen += delta;\n                    clampi(p.sink_empty_pen, 0, 12);\n                    break;\n                case 10:\n                    p.axis_pref = randInt(rng, 0, 2);\n                    break;\n                case 11:\n                    p.path_unload_bonus += delta * 20;\n                    clampi(p.path_unload_bonus, 30, 340);\n                    break;\n                case 12:\n                    p.path_load_bonus += delta * 20;\n                    clampi(p.path_load_bonus, 0, 260);\n                    break;\n                case 13:\n                    p.back_penalty += delta * 20;\n                    clampi(p.back_penalty, 0, 240);\n                    break;\n                case 14:\n                    p.retarget_on_change = !p.retarget_on_change;\n                    break;\n            }\n        }\n        return p;\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        M = N * N;\n\n        bool allZero = true;\n        input_hash = 1469598103934665603ULL;\n        total_positive = 0;\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int x;\n                cin >> x;\n                int id = r * N + c;\n                init_h[id] = x;\n                rr[id] = r;\n                cc[id] = c;\n                if (x != 0) allZero = false;\n                if (x > 0) total_positive += x;\n\n                input_hash ^= (uint64_t)(x + 1000);\n                input_hash *= 1099511628211ULL;\n            }\n        }\n\n        if (allZero) return;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                distm[i][j] = (uint8_t)(abs(rr[i] - rr[j]) + abs(cc[i] - cc[j]));\n            }\n        }\n\n        vector<int> posIds, negIds;\n        posIds.reserve(M);\n        negIds.reserve(M);\n        for (int i = 0; i < M; i++) {\n            if (init_h[i] > 0) posIds.push_back(i);\n            else if (init_h[i] < 0) negIds.push_back(i);\n        }\n\n        for (int i = 0; i < M; i++) {\n            int bp = INT_MAX, bn = INT_MAX;\n            for (int id : posIds) bp = min(bp, (int)distm[i][id]);\n            for (int id : negIds) bn = min(bn, (int)distm[i][id]);\n            init_near_pos[i] = (bp == INT_MAX ? 0 : bp);\n            init_near_neg[i] = (bn == INT_MAX ? 0 : bn);\n        }\n\n        // Build cycle candidates\n        cycles.clear();\n        vector<int> baseCycle = buildBaseCycle();\n        for (int t = 0; t < 8; t++) {\n            auto cyc = transformCycle(baseCycle, t);\n            if ((int)cyc.size() != M || cyc[0] != 0) continue;\n            bool dup = false;\n            for (auto &v : cycles) if (v == cyc) { dup = true; break; }\n            if (!dup) cycles.push_back(move(cyc));\n        }\n        if (cycles.empty()) cycles.push_back(baseCycle);\n\n        // Build path candidates (with transforms/reverse)\n        paths.clear();\n        addPathTransforms(buildRowSnake());\n        addPathTransforms(buildColSnake());\n        addPathTransforms(buildSpiralCW());\n        addPathTransforms(buildSpiralCCW());\n        if (paths.empty()) addPathIfValid(buildRowSnake());\n\n        auto tStart = chrono::steady_clock::now();\n        auto elapsed = [&]() -> double {\n            return chrono::duration<double>(chrono::steady_clock::now() - tStart).count();\n        };\n        const double TIME_LIMIT = 1.90;\n\n        long long bestCost = INF64;\n        BestType bestType = BestType::NONE;\n        CycleSpec bestCycle;\n        PathSpec bestPath;\n        GreedySpec bestGreedy;\n\n        // quick baseline\n        if (!paths.empty()) {\n            auto b = simulatePath<false>(paths[0], 1, INF64);\n            if (b.valid && b.cost < bestCost) {\n                bestCost = b.cost;\n                bestType = BestType::PATH;\n                bestPath = {0, 1};\n            }\n        }\n\n        // cycle search\n        for (int ci = 0; ci < (int)cycles.size(); ci++) {\n            for (int dir : {1, -1}) {\n                for (int shift = 0; shift < M; shift++) {\n                    auto cur = simulateCycle<false>(cycles[ci], dir, shift, bestCost);\n                    if (cur.valid && cur.cost < bestCost) {\n                        bestCost = cur.cost;\n                        bestType = BestType::CYCLE;\n                        bestCycle = {ci, dir, shift};\n                    }\n                }\n            }\n        }\n\n        // path search\n        for (int pi = 0; pi < (int)paths.size(); pi++) {\n            for (int ct = 0; ct <= 1; ct++) {\n                auto cur = simulatePath<false>(paths[pi], ct, bestCost);\n                if (cur.valid && cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::PATH;\n                    bestPath = {pi, ct};\n                }\n            }\n        }\n\n        vector<EliteItem> elite;\n        auto addElite = [&](const GParam &p, uint64_t sd, long long c) {\n            if (c >= INF64 / 2) return;\n            elite.push_back({p, sd, c});\n            sort(elite.begin(), elite.end(), [](const EliteItem &a, const EliteItem &b) {\n                return a.cost < b.cost;\n            });\n            const int EL = 12;\n            if ((int)elite.size() > EL) elite.resize(EL);\n        };\n\n        // deterministic greedy seeds\n        vector<GParam> seedParams;\n        auto makeP = [&](int cap, int mode, int dist, int link, int sb, int db, bool collect,\n                         int force, int slp, int sep, int axis, int ub, int lb, int back, bool ret) {\n            GParam p;\n            p.cap = cap;\n            p.mode = mode;\n            p.dist_scale = dist;\n            p.link_scale = link;\n            p.src_bias = sb;\n            p.dst_bias = db;\n            p.collect_when_loaded = collect;\n            p.force_sink_ratio = force;\n            p.src_loaded_pen = slp;\n            p.sink_empty_pen = sep;\n            p.axis_pref = axis;\n            p.path_unload_bonus = ub;\n            p.path_load_bonus = lb;\n            p.back_penalty = back;\n            p.retarget_on_change = ret;\n            return p;\n        };\n\n        vector<int> capList = {220, 400, 750, 1400, 3000, INF_CAP};\n        for (int cap : capList) {\n            seedParams.push_back(makeP(cap, 0, 250, 60, 2, 2, false, 70, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 1, 240, 70, 2, 2, false, 68, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 1, 230, 80, 2, 2, true,  65, 1, 1, 2, 120, 90, 45, true));\n            seedParams.push_back(makeP(cap, 2, 230, 100, 2, 2, false, 70, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 2, 220, 120, 2, 2, true,  65, 1, 1, 2, 120, 95, 45, true));\n        }\n        seedParams.push_back(makeP(INF_CAP, 2, 250, 140, 1, 3, false, 75, 2, 1, 0, 110, 70, 60, true));\n        seedParams.push_back(makeP(INF_CAP, 2, 250, 140, 1, 3, false, 75, 2, 1, 1, 110, 70, 60, true));\n\n        const uint64_t MUL = 0x9e3779b97f4a7c15ULL;\n\n        bool stopSeed = false;\n        for (int i = 0; i < (int)seedParams.size() && !stopSeed; i++) {\n            for (int rep = 0; rep < 2; rep++) {\n                if (elapsed() > 1.20) { stopSeed = true; break; }\n\n                uint64_t sd = input_hash ^ (MUL * (uint64_t)(i * 2 + rep + 1));\n                if (sd == 0) sd = 88172645463325252ULL;\n\n                auto cur = simulateGreedy<false>(seedParams[i], sd, INF64);\n                if (!cur.valid) continue;\n\n                addElite(seedParams[i], sd, cur.cost);\n\n                if (cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::GREEDY;\n                    bestGreedy = {seedParams[i], sd};\n                }\n            }\n        }\n\n        // randomized elite local search\n        uint64_t rng = input_hash ^ 0xd1b54a32d192ed03ULL;\n        if (rng == 0) rng = 88172645463325252ULL;\n\n        int iter = 0;\n        while (elapsed() < TIME_LIMIT) {\n            GParam p;\n            if (!elite.empty() && randInt(rng, 0, 99) < 85) {\n                int top = min<int>((int)elite.size(), 6);\n                int idx = randInt(rng, 0, top - 1);\n                p = mutateParam(elite[idx].p, rng);\n                if (randInt(rng, 0, 99) < 8) p = randomParam(rng);\n            } else {\n                p = randomParam(rng);\n            }\n\n            uint64_t sd = xorshift64(rng) ^ (MUL * (uint64_t)(iter + 10007));\n            if (sd == 0) sd = 88172645463325252ULL;\n\n            long long cutoff = INF64;\n            if (bestCost < INF64 / 2) {\n                if ((iter & 3) != 0) cutoff = bestCost;\n                else cutoff = min(INF64, bestCost + 20000);\n            }\n\n            auto cur = simulateGreedy<false>(p, sd, cutoff);\n            if (cur.valid) {\n                addElite(p, sd, cur.cost);\n\n                if (cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::GREEDY;\n                    bestGreedy = {p, sd};\n                }\n            }\n            iter++;\n        }\n\n        SimResult ans;\n        if (bestType == BestType::CYCLE) {\n            ans = simulateCycle<true>(cycles[bestCycle.ci], bestCycle.dir, bestCycle.shift, INF64);\n        } else if (bestType == BestType::PATH) {\n            ans = simulatePath<true>(paths[bestPath.pi], bestPath.cleanup_type, INF64);\n        } else if (bestType == BestType::GREEDY) {\n            ans = simulateGreedy<true>(bestGreedy.p, bestGreedy.seed, INF64);\n        }\n\n        // safety fallback\n        if (!ans.valid) {\n            bool ok = false;\n\n            if (!elite.empty()) {\n                auto r = simulateGreedy<true>(elite[0].p, elite[0].seed, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            for (int pi = 0; pi < (int)paths.size() && !ok; pi++) {\n                auto r = simulatePath<true>(paths[pi], 1, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            for (int ci = 0; ci < (int)cycles.size() && !ok; ci++) {\n                auto r = simulateCycle<true>(cycles[ci], 1, 0, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            if (!ok) {\n                // legal fallback: do nothing\n                ans.valid = true;\n            }\n        }\n\n        for (const auto &s : ans.ops) {\n            cout << s << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nclass Solver {\n    static constexpr int MAXS = 60;\n    static constexpr int MAXM = 15;\n\n    struct Params {\n        double progress = 0.0; // 0..1\n\n        // pair score = mu + cSigma * sigma + cGain * gain\n        double cSigma = 1.0;\n        double cGain = 0.5;\n\n        // layout objective\n        double wSum = 1.0;\n        double wBest1 = 0.0;   // best edge\n        double wBest24 = 0.0;  // 2nd+3rd+4th edge\n        double beta1 = 0.0;    // coverage top1 per dimension\n        double beta2 = 0.0;    // coverage top2\n        double beta3 = 0.0;    // coverage top3\n\n        // base seed score\n        double rareExact = 0.0; // count of coords == initial max\n        double rareNear = 0.0;  // count of coords >= initial max-2\n        double rareCur2 = 0.0;  // count of coords >= current 2nd-best\n\n        int topV = 20;          // bonus to top-V seeds\n        double bonusV = 8.0;\n        bool preserveInitial = false;\n\n        // SA\n        int restarts = 2;\n        int iters = 8000;\n        double swapProb = 0.4;\n        double temp0 = 70.0;\n        double temp1 = 0.35;\n    };\n\n    int N = 0, M = 0, T = 0;\n    int S = 0, P = 0;\n\n    int X[MAXS][MAXM]{};\n    int V[MAXS]{};\n\n    int initMax[MAXM]{};\n    int curMax[MAXM]{}, cur2[MAXM]{}, cur3[MAXM]{};\n\n    double pairSc[MAXS][MAXS]{};\n    double baseSc[MAXS]{};\n\n    vector<pair<int, int>> edges; // size 2N(N-1)\n    vector<vector<int>> nbr;\n    vector<int> posOrder;\n    vector<int> baseOrder;\n    vector<int> ordV;\n\n    XorShift64 rng;\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> T)) return;\n        S = 2 * N * (N - 1);\n        P = N * N;\n\n        build_field();\n\n        if (!read_seeds()) return;\n\n        // initial per-dimension maxima from initial seeds\n        for (int l = 0; l < M; ++l) {\n            int mx = 0;\n            for (int i = 0; i < S; ++i) mx = max(mx, X[i][l]);\n            initMax[l] = mx;\n        }\n\n        for (int turn = 0; turn < T; ++turn) {\n            vector<int> layout = decide_layout(turn);\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = 0; j < N; ++j) {\n                    if (j) cout << ' ';\n                    cout << layout[i * N + j];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (turn + 1 == T) break; // no need to read after final output\n            if (!read_seeds()) return;\n        }\n    }\n\nprivate:\n    bool read_seeds() {\n        for (int i = 0; i < S; ++i) {\n            for (int l = 0; l < M; ++l) {\n                if (!(cin >> X[i][l])) return false;\n                if (X[i][l] < 0) return false; // interactive error signal\n            }\n            for (int l = M; l < MAXM; ++l) X[i][l] = 0;\n        }\n        return true;\n    }\n\n    void build_field() {\n        edges.clear();\n        nbr.assign(P, {});\n\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p = i * N + j;\n                if (j + 1 < N) {\n                    int q = p + 1;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n                if (i + 1 < N) {\n                    int q = p + N;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n            }\n        }\n\n        posOrder.resize(P);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        const double c = (N - 1) * 0.5;\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            int da = (int)nbr[a].size();\n            int db = (int)nbr[b].size();\n            if (da != db) return da > db;\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n            double ra = fabs(ai - c) + fabs(aj - c);\n            double rb = fabs(bi - c) + fabs(bj - c);\n            if (ra != rb) return ra < rb;\n            return a < b;\n        });\n    }\n\n    Params make_params(int turn) const {\n        Params prm;\n        double p = (T <= 1 ? 1.0 : (double)turn / (double)(T - 1));\n        double q = 1.0 - p;\n        prm.progress = p;\n\n        prm.cSigma = 0.75 + 0.95 * p;\n        prm.cGain  = 0.25 + 0.55 * p;\n\n        prm.wSum    = 1.0 - 0.15 * p;\n        prm.wBest1  = 0.4 + 8.0 * p;\n        prm.wBest24 = 0.15 + 3.0 * p;\n\n        prm.beta1 = 12.0 * q * q + 1.0;\n        prm.beta2 = 4.5 * q * q;\n        prm.beta3 = 1.4 * q * q;\n\n        prm.rareExact = 10.0 * q + 3.0;\n        prm.rareNear  = 3.0 * q + 1.0;\n        prm.rareCur2  = 1.2 * q + 0.2;\n\n        prm.topV = 20 + (int)llround(8.0 * p);\n        prm.bonusV = 7.0 + 2.0 * p;\n\n        prm.preserveInitial = (turn <= 3);\n\n        prm.swapProb = 0.30 + 0.25 * p;\n        prm.temp0 = 75.0 - 18.0 * p;\n        prm.temp1 = 0.35;\n\n        if (turn <= 1) {\n            prm.restarts = 3;\n            prm.iters = 6200 + 500 * turn;\n        } else {\n            prm.restarts = 2;\n            prm.iters = 7000 + 500 * turn;\n        }\n        return prm;\n    }\n\n    void compute_turn_tables(const Params& prm) {\n        // V\n        for (int i = 0; i < S; ++i) {\n            int s = 0;\n            for (int l = 0; l < M; ++l) s += X[i][l];\n            V[i] = s;\n        }\n\n        // ordV\n        ordV.resize(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        // current per-dimension top1/2/3\n        for (int l = 0; l < M; ++l) {\n            int m1 = -1, m2 = -1, m3 = -1;\n            for (int i = 0; i < S; ++i) {\n                int v = X[i][l];\n                if (v > m1) {\n                    m3 = m2;\n                    m2 = m1;\n                    m1 = v;\n                } else if (v > m2) {\n                    m3 = m2;\n                    m2 = v;\n                } else if (v > m3) {\n                    m3 = v;\n                }\n            }\n            if (m2 < 0) m2 = 0;\n            if (m3 < 0) m3 = 0;\n            curMax[l] = m1;\n            cur2[l] = m2;\n            cur3[l] = m3;\n        }\n\n        // base seed score\n        for (int i = 0; i < S; ++i) {\n            int cExact = 0, cNear = 0, cCur2 = 0;\n            for (int l = 0; l < M; ++l) {\n                if (X[i][l] == initMax[l]) ++cExact;\n                if (X[i][l] >= max(0, initMax[l] - 2)) ++cNear;\n                if (X[i][l] >= cur2[l]) ++cCur2;\n            }\n            baseSc[i] = (double)V[i]\n                      + prm.rareExact * cExact\n                      + prm.rareNear  * cNear\n                      + prm.rareCur2  * cCur2;\n        }\n\n        // pair scores\n        for (int i = 0; i < S; ++i) {\n            pairSc[i][i] = (double)V[i];\n            for (int j = i + 1; j < S; ++j) {\n                long long d2 = 0;\n                int sumMax = 0;\n                for (int l = 0; l < M; ++l) {\n                    int a = X[i][l], b = X[j][l];\n                    int d = a - b;\n                    d2 += 1LL * d * d;\n                    sumMax += max(a, b);\n                }\n                double mu = 0.5 * (V[i] + V[j]);\n                double sigma = 0.5 * sqrt((double)d2);\n                double gain = (double)sumMax - mu;\n                double sc = mu + prm.cSigma * sigma + prm.cGain * gain;\n                pairSc[i][j] = pairSc[j][i] = sc;\n            }\n        }\n\n        // base order\n        baseOrder.resize(S);\n        iota(baseOrder.begin(), baseOrder.end(), 0);\n        sort(baseOrder.begin(), baseOrder.end(), [&](int a, int b) {\n            if (baseSc[a] != baseSc[b]) return baseSc[a] > baseSc[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n    }\n\n    vector<int> select_seeds(const Params& prm, int mode) {\n        vector<double> pri(S);\n        for (int i = 0; i < S; ++i) pri[i] = baseSc[i];\n\n        // Top-V bonus\n        int tv = min(prm.topV, S);\n        for (int k = 0; k < tv; ++k) {\n            int id = ordV[k];\n            pri[id] += prm.bonusV * (double)(tv - k) / (double)tv;\n        }\n\n        // Small diversification for alternate restarts\n        if (mode > 0) {\n            double amp = 1.8 * mode;\n            for (int i = 0; i < S; ++i) {\n                pri[i] += (rng.next_double() - 0.5) * amp;\n            }\n        }\n\n        vector<int> selected;\n        vector<char> inSel(S, 0);\n\n        auto add_seed = [&](int id) {\n            if (!inSel[id]) {\n                inSel[id] = 1;\n                selected.push_back(id);\n            }\n        };\n\n        // Preserve initial maxima in early turns\n        if (prm.preserveInitial) {\n            for (int l = 0; l < M; ++l) {\n                int best = -1;\n                double bs = -1e100;\n                for (int i = 0; i < S; ++i) {\n                    if (X[i][l] == initMax[l]) {\n                        double s = pri[i] + 0.05 * V[i];\n                        if (s > bs) {\n                            bs = s;\n                            best = i;\n                        }\n                    }\n                }\n                if (best != -1) add_seed(best);\n            }\n        }\n\n        // Very early: also preserve current maxima\n        if (prm.progress < 0.25) {\n            for (int l = 0; l < M; ++l) {\n                int best = -1;\n                double bs = -1e100;\n                for (int i = 0; i < S; ++i) {\n                    if (X[i][l] == curMax[l]) {\n                        if (pri[i] > bs) {\n                            bs = pri[i];\n                            best = i;\n                        }\n                    }\n                }\n                if (best != -1) add_seed(best);\n            }\n        }\n\n        // If too many by mandatory, keep strongest\n        if ((int)selected.size() > P) {\n            sort(selected.begin(), selected.end(), [&](int a, int b) {\n                if (pri[a] != pri[b]) return pri[a] > pri[b];\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            selected.resize(P);\n            fill(inSel.begin(), inSel.end(), 0);\n            for (int id : selected) inSel[id] = 1;\n        }\n\n        // Fill by priority\n        vector<int> ord(S);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (pri[a] != pri[b]) return pri[a] > pri[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        for (int id : ord) {\n            if ((int)selected.size() >= P) break;\n            if (!inSel[id]) add_seed(id);\n        }\n\n        return selected;\n    }\n\n    vector<int> construct_layout(const vector<int>& selected, const Params& prm, int mode) {\n        vector<int> rem = selected;\n        // good seeds first\n        sort(rem.begin(), rem.end(), [&](int a, int b) {\n            if (baseSc[a] != baseSc[b]) return baseSc[a] > baseSc[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<int> order = posOrder;\n        if (mode > 0) {\n            // randomize within same degree tendency\n            for (int i = P - 1; i > 0; --i) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n            stable_sort(order.begin(), order.end(), [&](int a, int b) {\n                return (int)nbr[a].size() > (int)nbr[b].size();\n            });\n        }\n\n        vector<int> a(P, -1);\n        double neighCoef = 1.25 + 0.25 * prm.progress;\n\n        for (int t = 0; t < P; ++t) {\n            int pos = order[t];\n            int bestIdx = -1;\n            double bestSc = -1e100;\n\n            for (int idx = 0; idx < (int)rem.size(); ++idx) {\n                int s = rem[idx];\n                double sc = baseSc[s];\n\n                double nb = 0.0;\n                for (int q : nbr[pos]) {\n                    int sq = a[q];\n                    if (sq != -1) nb += pairSc[s][sq];\n                }\n                sc += neighCoef * nb;\n\n                if (mode > 0) sc += (rng.next_double() - 0.5) * 0.8;\n\n                if (sc > bestSc) {\n                    bestSc = sc;\n                    bestIdx = idx;\n                }\n            }\n\n            int pick = rem[bestIdx];\n            a[pos] = pick;\n            rem[bestIdx] = rem.back();\n            rem.pop_back();\n        }\n\n        return a;\n    }\n\n    double evaluate_layout(const vector<int>& a, const Params& prm) const {\n        double sumE = 0.0;\n        double b1 = -1e100, b2 = -1e100, b3 = -1e100, b4 = -1e100;\n\n        for (const auto& e : edges) {\n            double s = pairSc[a[e.first]][a[e.second]];\n            sumE += s;\n\n            if (s > b1) {\n                b4 = b3; b3 = b2; b2 = b1; b1 = s;\n            } else if (s > b2) {\n                b4 = b3; b3 = b2; b2 = s;\n            } else if (s > b3) {\n                b4 = b3; b3 = s;\n            } else if (s > b4) {\n                b4 = s;\n            }\n        }\n\n        double cov1 = 0.0, cov2 = 0.0, cov3 = 0.0;\n        for (int l = 0; l < M; ++l) {\n            int m1 = -1, m2 = -1, m3 = -1;\n            for (int p = 0; p < P; ++p) {\n                int v = X[a[p]][l];\n                if (v > m1) {\n                    m3 = m2; m2 = m1; m1 = v;\n                } else if (v > m2) {\n                    m3 = m2; m2 = v;\n                } else if (v > m3) {\n                    m3 = v;\n                }\n            }\n            if (m2 < 0) m2 = 0;\n            if (m3 < 0) m3 = 0;\n            cov1 += m1;\n            cov2 += m2;\n            cov3 += m3;\n        }\n\n        return prm.wSum * sumE\n             + prm.wBest1 * b1\n             + prm.wBest24 * (b2 + b3 + b4)\n             + prm.beta1 * cov1\n             + prm.beta2 * cov2\n             + prm.beta3 * cov3;\n    }\n\n    int pick_unused_good_seed(const vector<int>& seedPos) {\n        int k1 = min(S, 24);\n        int k2 = min(S, 42);\n\n        for (int t = 0; t < 22; ++t) {\n            int id = baseOrder[rng.next_int(k1)];\n            if (seedPos[id] == -1) return id;\n        }\n        for (int t = 0; t < 22; ++t) {\n            int id = baseOrder[rng.next_int(k2)];\n            if (seedPos[id] == -1) return id;\n        }\n        for (int t = 0; t < 80; ++t) {\n            int id = rng.next_int(S);\n            if (seedPos[id] == -1) return id;\n        }\n        return rng.next_int(S); // fallback (possibly used)\n    }\n\n    pair<vector<int>, double> sa_optimize(const vector<int>& init, const Params& prm, int iters) {\n        vector<int> a = init;\n        vector<int> bestA = a;\n\n        vector<int> seedPos(S, -1);\n        for (int p = 0; p < P; ++p) seedPos[a[p]] = p;\n\n        double cur = evaluate_layout(a, prm);\n        double best = cur;\n\n        for (int it = 0; it < iters; ++it) {\n            double temp = prm.temp0 + (prm.temp1 - prm.temp0) * (double)it / (double)iters;\n\n            bool moved = false;\n            double nxt = cur;\n\n            if (rng.next_double() < prm.swapProb) {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                seedPos[sp] = q;\n                seedPos[sq] = p;\n\n                nxt = evaluate_layout(a, prm);\n                moved = true;\n\n                double d = nxt - cur;\n                bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestA = a;\n                    }\n                } else {\n                    swap(a[p], a[q]);\n                    seedPos[sp] = p;\n                    seedPos[sq] = q;\n                }\n            } else {\n                int p = rng.next_int(P);\n                int s = pick_unused_good_seed(seedPos);\n                int q = seedPos[s];\n                if (q == p) continue;\n\n                int old = a[p];\n                if (q == -1) {\n                    a[p] = s;\n                    seedPos[s] = p;\n                    seedPos[old] = -1;\n\n                    nxt = evaluate_layout(a, prm);\n                    moved = true;\n\n                    double d = nxt - cur;\n                    bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n                    if (ok) {\n                        cur = nxt;\n                        if (cur > best) {\n                            best = cur;\n                            bestA = a;\n                        }\n                    } else {\n                        a[p] = old;\n                        seedPos[old] = p;\n                        seedPos[s] = -1;\n                    }\n                } else {\n                    // swap with existing seed\n                    swap(a[p], a[q]); // s moves to p\n                    seedPos[s] = p;\n                    seedPos[old] = q;\n\n                    nxt = evaluate_layout(a, prm);\n                    moved = true;\n\n                    double d = nxt - cur;\n                    bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n                    if (ok) {\n                        cur = nxt;\n                        if (cur > best) {\n                            best = cur;\n                            bestA = a;\n                        }\n                    } else {\n                        swap(a[p], a[q]);\n                        seedPos[s] = q;\n                        seedPos[old] = p;\n                    }\n                }\n            }\n\n            (void)moved;\n        }\n\n        return {bestA, best};\n    }\n\n    double greedy_polish(vector<int>& a, const Params& prm) {\n        vector<int> seedPos(S, -1);\n        for (int p = 0; p < P; ++p) seedPos[a[p]] = p;\n\n        double cur = evaluate_layout(a, prm);\n\n        vector<int> plist(P);\n        iota(plist.begin(), plist.end(), 0);\n        for (int i = P - 1; i > 0; --i) {\n            int j = rng.next_int(i + 1);\n            swap(plist[i], plist[j]);\n        }\n\n        for (int p : plist) {\n            int old = a[p];\n\n            double bestSc = cur;\n            int bestS = -1;\n            int bestQ = -2; // -1 replacement, >=0 swap target pos\n\n            for (int s = 0; s < S; ++s) {\n                int q = seedPos[s];\n                if (q == p) continue;\n\n                double candSc;\n                if (q == -1) {\n                    a[p] = s;\n                    seedPos[s] = p;\n                    seedPos[old] = -1;\n\n                    candSc = evaluate_layout(a, prm);\n\n                    a[p] = old;\n                    seedPos[old] = p;\n                    seedPos[s] = -1;\n                } else {\n                    swap(a[p], a[q]); // s -> p\n                    seedPos[s] = p;\n                    seedPos[old] = q;\n\n                    candSc = evaluate_layout(a, prm);\n\n                    swap(a[p], a[q]);\n                    seedPos[s] = q;\n                    seedPos[old] = p;\n                }\n\n                if (candSc > bestSc + 1e-9) {\n                    bestSc = candSc;\n                    bestS = s;\n                    bestQ = q;\n                }\n            }\n\n            if (bestS != -1) {\n                if (bestQ == -1) {\n                    int out = a[p];\n                    a[p] = bestS;\n                    seedPos[bestS] = p;\n                    seedPos[out] = -1;\n                } else {\n                    int q = bestQ;\n                    int out = a[p];\n                    swap(a[p], a[q]);\n                    seedPos[bestS] = p;\n                    seedPos[out] = q;\n                }\n                cur = bestSc;\n            }\n        }\n\n        return cur;\n    }\n\n    void perturb_layout(vector<int>& a, int steps) {\n        vector<int> pos(S, -1);\n        for (int p = 0; p < P; ++p) pos[a[p]] = p;\n\n        for (int st = 0; st < steps; ++st) {\n            if (rng.next_double() < 0.55) {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                pos[sp] = q;\n                pos[sq] = p;\n            } else {\n                int p = rng.next_int(P);\n                int s = -1;\n                for (int t = 0; t < 40; ++t) {\n                    int c = rng.next_int(S);\n                    if (pos[c] == -1) {\n                        s = c;\n                        break;\n                    }\n                }\n                if (s == -1) continue;\n                int old = a[p];\n                a[p] = s;\n                pos[s] = p;\n                pos[old] = -1;\n            }\n        }\n    }\n\n    double mc_eval_layout(const vector<int>& a, const vector<uint16_t>& masks, int samples) const {\n        const int E = (int)edges.size();\n        double acc = 0.0;\n\n        for (int t = 0; t < samples; ++t) {\n            int best = 0;\n            int base = t * E;\n\n            for (int e = 0; e < E; ++e) {\n                int p = edges[e].first;\n                int q = edges[e].second;\n                int s1 = a[p], s2 = a[q];\n                uint16_t mask = masks[base + e];\n\n                int v = 0;\n                for (int l = 0; l < M; ++l) {\n                    if ((mask >> l) & 1) v += X[s1][l];\n                    else v += X[s2][l];\n                }\n                if (v > best) best = v;\n            }\n            acc += (double)best;\n        }\n\n        return acc / (double)samples;\n    }\n\n    vector<int> choose_by_mc(const vector<vector<int>>& cands) {\n        vector<vector<int>> uniq;\n        uniq.reserve(cands.size());\n\n        for (const auto& c : cands) {\n            bool dup = false;\n            for (const auto& u : uniq) {\n                if (u == c) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) uniq.push_back(c);\n        }\n\n        if (uniq.empty()) return cands[0];\n        if (uniq.size() == 1) return uniq[0];\n\n        int C = (int)uniq.size();\n        int E = (int)edges.size();\n        uint16_t allMask = (uint16_t)((1u << M) - 1u);\n\n        auto gen_masks = [&](int samples) {\n            vector<uint16_t> m(samples * E);\n            for (int i = 0; i < samples * E; ++i) {\n                m[i] = (uint16_t)(rng.next_u64() & allMask);\n            }\n            return m;\n        };\n\n        const int s1 = 96;\n        const int s2 = 320;\n\n        vector<uint16_t> masks1 = gen_masks(s1);\n        vector<double> est(C, 0.0);\n\n        for (int i = 0; i < C; ++i) {\n            est[i] = mc_eval_layout(uniq[i], masks1, s1);\n        }\n\n        vector<int> ids(C);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return est[a] > est[b];\n        });\n\n        int L = min(3, C);\n        vector<uint16_t> masks2 = gen_masks(s2);\n        for (int t = 0; t < L; ++t) {\n            int i = ids[t];\n            double e2 = mc_eval_layout(uniq[i], masks2, s2);\n            est[i] = (est[i] * s1 + e2 * s2) / (double)(s1 + s2);\n        }\n\n        int best = 0;\n        for (int i = 1; i < C; ++i) {\n            if (est[i] > est[best]) best = i;\n        }\n        return uniq[best];\n    }\n\n    vector<int> decide_layout(int turn) {\n        Params prm = make_params(turn);\n        compute_turn_tables(prm);\n\n        vector<vector<int>> allCands;\n        vector<double> allScores;\n\n        vector<int> bestLayout;\n        double bestScore = -1e100;\n\n        for (int r = 0; r < prm.restarts; ++r) {\n            vector<int> selected = select_seeds(prm, r);\n            vector<int> init = construct_layout(selected, prm, r);\n\n            int iters = prm.iters + 400 * r;\n            auto [lay, sc] = sa_optimize(init, prm, iters);\n\n            allCands.push_back(lay);\n            allScores.push_back(sc);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestLayout = lay;\n            }\n        }\n\n        bestScore = greedy_polish(bestLayout, prm);\n        allCands.push_back(bestLayout);\n        allScores.push_back(bestScore);\n\n        if (turn == T - 1) {\n            // final turn: add a few nearby candidates, then MC rerank\n            for (int z = 0; z < 3; ++z) {\n                vector<int> v = bestLayout;\n                perturb_layout(v, 4 + 2 * z);\n                auto [lay, sc] = sa_optimize(v, prm, 1100 + 400 * z);\n                (void)sc;\n                allCands.push_back(lay);\n            }\n            return choose_by_mc(allCands);\n        }\n\n        if (turn == T - 2) {\n            // mild diversification one turn before final\n            vector<int> v = bestLayout;\n            perturb_layout(v, 4);\n            auto [lay, sc] = sa_optimize(v, prm, 1300);\n            if (sc > bestScore) bestLayout = lay;\n        }\n\n        return bestLayout;\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MAXC = 900; // 30*30\n    static constexpr int MAXK = 14;  // V-1, V<=15\n\n    // dir: 0=R,1=D,2=L,3=U\n    const int DX[4] = {0, 1, 0, -1};\n    const int DY[4] = {1, 0, -1, 0};\n\n    int N, M, V;\n    int C, K, Vp;\n\n    vector<string> S, T;\n\n    // Arm state\n    vector<int> len;       // leaf length\n    vector<int> curDir;    // current direction per leaf\n    vector<char> hold;     // holding flag\n    int heldNow = 0;\n\n    // Remaining tasks\n    vector<uint8_t> src;   // s=1,t=0 still to pick\n    vector<uint8_t> dst;   // s=0,t=1 still to drop\n    int remSrc = 0, remDst = 0;\n    long long sumSrcX = 0, sumSrcY = 0;\n    long long sumDstX = 0, sumDstY = 0;\n\n    // Root\n    int curX = 0, curY = 0;\n    int initX = 0, initY = 0;\n\n    // Precompute\n    int rotD[4][4];\n    vector<int> rx, ry;    // cell id -> x,y\n    vector<int> reach;     // ((rid*K + leaf)<<2)+dir -> cell or -1\n\n    // Output operations\n    vector<string> ops;\n\n    // Matching buffers (stamp technique)\n    int owner[MAXC], ownerDir[MAXC], ownerStamp[MAXC];\n    int vis[MAXC], cellMark[MAXC];\n    int stampOwner = 1, stampVis = 1, stampCell = 1;\n\n    // execution-time marks\n    int resMark[MAXC], usedMark[MAXC];\n    int stampRes = 1, stampUsed = 1;\n\n    // leaf priority for opportunistic actions (longer first)\n    vector<int> leafPriority;\n\n    struct MR {\n        int cnt = 0;\n        int rmax = 0;\n    };\n\n    struct Cand {\n        bool ok = false;\n        int rid = -1;\n        int lp = 0, ld = 0; // rot-limit for pick/drop groups\n        int pick = 0, drop = 0, cnt = 0;\n        int turns = 1;\n        int dist = 0;\n        int pen = 0;\n        int fut = 0;\n        int util = 0;\n    };\n\n    Solver() {\n        memset(ownerStamp, 0, sizeof(ownerStamp));\n        memset(vis, 0, sizeof(vis));\n        memset(cellMark, 0, sizeof(cellMark));\n        memset(resMark, 0, sizeof(resMark));\n        memset(usedMark, 0, sizeof(usedMark));\n    }\n\n    inline int man(int x1, int y1, int x2, int y2) const {\n        return abs(x1 - x2) + abs(y1 - y2);\n    }\n\n    void input() {\n        cin >> N >> M >> V;\n        S.resize(N);\n        T.resize(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        C = N * N;\n        K = V - 1;\n        Vp = K + 1;\n\n        src.assign(C, 0);\n        dst.assign(C, 0);\n        remSrc = remDst = 0;\n        sumSrcX = sumSrcY = sumDstX = sumDstY = 0;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                int c = x * N + y;\n                bool sv = (S[x][y] == '1');\n                bool tv = (T[x][y] == '1');\n                if (sv && !tv) {\n                    src[c] = 1;\n                    remSrc++;\n                    sumSrcX += x;\n                    sumSrcY += y;\n                } else if (!sv && tv) {\n                    dst[c] = 1;\n                    remDst++;\n                    sumDstX += x;\n                    sumDstY += y;\n                }\n            }\n        }\n    }\n\n    void buildRot() {\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                int d = (b - a + 4) % 4;\n                rotD[a][b] = min(d, 4 - d);\n            }\n        }\n    }\n\n    void buildArm() {\n        // keep lengths <= floor((N-1)/2) for robust reach\n        int maxLen = max(1, (N - 1) / 2);\n\n        len.assign(K, 1);\n        if (K <= maxLen) {\n            if (K == 1) len[0] = 1;\n            else {\n                for (int i = 0; i < K; i++) {\n                    len[i] = 1 + (long long)i * (maxLen - 1) / (K - 1);\n                }\n            }\n        } else {\n            for (int i = 0; i < maxLen; i++) len[i] = i + 1;\n            for (int i = maxLen; i < K; i++) len[i] = 1 + ((i - maxLen) % maxLen);\n        }\n\n        curDir.assign(K, 0); // all right at start\n        hold.assign(K, 0);\n        heldNow = 0;\n\n        leafPriority.resize(K);\n        iota(leafPriority.begin(), leafPriority.end(), 0);\n        sort(leafPriority.begin(), leafPriority.end(), [&](int a, int b) {\n            if (len[a] != len[b]) return len[a] > len[b];\n            return a < b;\n        });\n    }\n\n    void precomputeReach() {\n        rx.resize(C);\n        ry.resize(C);\n        for (int c = 0; c < C; c++) {\n            rx[c] = c / N;\n            ry[c] = c % N;\n        }\n\n        reach.assign(C * K * 4, -1);\n        for (int rid = 0; rid < C; rid++) {\n            int x = rx[rid], y = ry[rid];\n            for (int leaf = 0; leaf < K; leaf++) {\n                int L = len[leaf];\n                int base = ((rid * K + leaf) << 2);\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + DX[d] * L;\n                    int ny = y + DY[d] * L;\n                    if (0 <= nx && nx < N && 0 <= ny && ny < N) {\n                        reach[base + d] = nx * N + ny;\n                    } else {\n                        reach[base + d] = -1;\n                    }\n                }\n            }\n        }\n    }\n\n    MR matchGroup(\n        int rid,\n        const int* leaves, int nLeaves,\n        const vector<uint8_t>& target,\n        int rotLimit,\n        int* outDir = nullptr,\n        int* outCell = nullptr\n    ) {\n        MR res;\n        if (nLeaves <= 0) return res;\n\n        int deg[MAXK];\n        int eCell[MAXK][4];\n        int eDir[MAXK][4];\n        uint8_t eRot[MAXK][4];\n\n        int candCells[4 * MAXK];\n        int candCnt = 0;\n        int cstamp = ++stampCell;\n\n        bool any = false;\n\n        for (int u = 0; u < nLeaves; u++) {\n            int leaf = leaves[u];\n            int base = ((rid * K + leaf) << 2);\n\n            int dcnt = 0;\n            for (int d = 0; d < 4; d++) {\n                int c = reach[base + d];\n                if (c < 0 || !target[c]) continue;\n\n                int rr = rotD[curDir[leaf]][d];\n                if (rr > rotLimit) continue;\n\n                eCell[u][dcnt] = c;\n                eDir[u][dcnt] = d;\n                eRot[u][dcnt] = (uint8_t)rr;\n                dcnt++;\n\n                if (cellMark[c] != cstamp) {\n                    cellMark[c] = cstamp;\n                    candCells[candCnt++] = c;\n                }\n            }\n\n            // prefer lower rotation edges\n            for (int i = 0; i < dcnt; i++) {\n                for (int j = i + 1; j < dcnt; j++) {\n                    if (eRot[u][j] < eRot[u][i]) {\n                        swap(eRot[u][i], eRot[u][j]);\n                        swap(eCell[u][i], eCell[u][j]);\n                        swap(eDir[u][i], eDir[u][j]);\n                    }\n                }\n            }\n\n            deg[u] = dcnt;\n            if (dcnt > 0) any = true;\n        }\n\n        if (!any) return res;\n\n        int ord[MAXK];\n        for (int i = 0; i < nLeaves; i++) ord[i] = i;\n        for (int i = 0; i < nLeaves; i++) {\n            int best = i;\n            for (int j = i + 1; j < nLeaves; j++) {\n                if (deg[ord[j]] < deg[ord[best]]) best = j;\n            }\n            if (best != i) swap(ord[i], ord[best]);\n        }\n\n        int myStamp = ++stampOwner;\n\n        auto dfs = [&](auto&& self, int u, int tag) -> bool {\n            for (int ei = 0; ei < deg[u]; ei++) {\n                int c = eCell[u][ei];\n                if (vis[c] == tag) continue;\n                vis[c] = tag;\n\n                if (ownerStamp[c] != myStamp || self(self, owner[c], tag)) {\n                    ownerStamp[c] = myStamp;\n                    owner[c] = u;\n                    ownerDir[c] = eDir[u][ei];\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        int cnt = 0;\n        for (int i = 0; i < nLeaves; i++) {\n            int u = ord[i];\n            int tag = ++stampVis;\n            if (dfs(dfs, u, tag)) cnt++;\n        }\n        res.cnt = cnt;\n        if (cnt == 0) return res;\n\n        int rmax = 0;\n        for (int i = 0; i < candCnt; i++) {\n            int c = candCells[i];\n            if (ownerStamp[c] != myStamp) continue;\n            int u = owner[c];\n            int leaf = leaves[u];\n            int d = ownerDir[c];\n            int rr = rotD[curDir[leaf]][d];\n            rmax = max(rmax, rr);\n\n            if (outDir) {\n                outDir[leaf] = d;\n                outCell[leaf] = c;\n            }\n        }\n        res.rmax = rmax;\n        return res;\n    }\n\n    int holdPenaltyAt(int rid, int held2, int scx, int scy, int dcx, int dcy) {\n        if (remSrc == 0 || remDst == 0) return held2;\n\n        int ds = man(rx[rid], ry[rid], scx, scy);\n        int dd = man(rx[rid], ry[rid], dcx, dcy);\n        int denom = ds + dd;\n        int targetHeld = (denom == 0) ? (K / 2) : (K * dd + denom / 2) / denom; // near src => hold more\n        targetHeld = max(0, min(K, targetHeld));\n        return abs(held2 - targetHeld);\n    }\n\n    bool betterCand(const Cand& a, const Cand& b) {\n        if (!a.ok) return false;\n        if (!b.ok) return true;\n\n        long long lhs = 1LL * a.util * b.turns;\n        long long rhs = 1LL * b.util * a.turns;\n        if (lhs != rhs) return lhs > rhs;\n\n        lhs = 1LL * a.cnt * b.turns;\n        rhs = 1LL * b.cnt * a.turns;\n        if (lhs != rhs) return lhs > rhs;\n\n        if (a.fut != b.fut) return a.fut < b.fut;\n        if (a.pen != b.pen) return a.pen < b.pen;\n        if (a.turns != b.turns) return a.turns < b.turns;\n        if (a.drop != b.drop) return a.drop > b.drop;\n        if (a.dist != b.dist) return a.dist < b.dist;\n\n        int ra = max(a.lp, a.ld);\n        int rb = max(b.lp, b.ld);\n        return ra < rb;\n    }\n\n    void chooseInitialRoot() {\n        if (remSrc == 0) {\n            initX = N / 2;\n            initY = N / 2;\n            curX = initX;\n            curY = initY;\n            return;\n        }\n\n        int allLeaves[MAXK];\n        for (int i = 0; i < K; i++) allLeaves[i] = i;\n\n        int scx = (int)(sumSrcX / remSrc);\n        int scy = (int)(sumSrcY / remSrc);\n\n        int bestRid = -1, bestCnt = -1, bestTurns = (int)1e9, bestDist = (int)1e9;\n        for (int rid = 0; rid < C; rid++) {\n            MR mr = matchGroup(rid, allLeaves, K, src, 2);\n            if (mr.cnt == 0) continue;\n\n            int turns = max(1, mr.rmax);\n            int dist = man(rx[rid], ry[rid], scx, scy);\n\n            bool better = false;\n            if (bestRid < 0) better = true;\n            else {\n                long long l = 1LL * mr.cnt * bestTurns;\n                long long r = 1LL * bestCnt * turns;\n                if (l != r) better = l > r;\n                else if (mr.cnt != bestCnt) better = mr.cnt > bestCnt;\n                else if (turns != bestTurns) better = turns < bestTurns;\n                else if (dist < bestDist) better = true;\n            }\n\n            if (better) {\n                bestRid = rid;\n                bestCnt = mr.cnt;\n                bestTurns = turns;\n                bestDist = dist;\n            }\n        }\n\n        if (bestRid < 0) bestRid = (N / 2) * N + (N / 2);\n        initX = rx[bestRid];\n        initY = ry[bestRid];\n        curX = initX;\n        curY = initY;\n    }\n\n    void executeMove(int rid, const vector<int>& assignDir, const vector<int>& assignCell) {\n        int bx = rx[rid], by = ry[rid];\n\n        bool activeWanted[MAXK] = {};\n        for (int i = 0; i < K; i++) activeWanted[i] = (assignDir[i] >= 0);\n\n        int D = man(curX, curY, bx, by);\n        int Ract = 0;\n        for (int i = 0; i < K; i++) if (activeWanted[i]) {\n            int diff = (assignDir[i] - curDir[i] + 4) % 4;\n            int rr = (diff == 0 ? 0 : (diff == 2 ? 2 : 1));\n            Ract = max(Ract, rr);\n        }\n\n        int turns = max(D, Ract);\n        if (turns == 0) turns = 1;\n\n        int remainAll = 100000 - (int)ops.size();\n        if (remainAll <= 0) return;\n\n        bool doAction = true;\n        if (turns > remainAll) {\n            turns = remainAll;\n            doAction = false;\n        }\n        if (turns <= 0) return;\n\n        bool fixed[MAXK] = {};\n        for (int i = 0; i < K; i++) fixed[i] = (doAction && activeWanted[i]);\n\n        int rstamp = 0;\n        if (doAction) {\n            rstamp = ++stampRes;\n            for (int i = 0; i < K; i++) {\n                if (fixed[i] && assignCell[i] >= 0) {\n                    resMark[assignCell[i]] = rstamp;\n                }\n            }\n        }\n\n        static const int MDX[5] = {0, -1, 1, 0, 0};\n        static const int MDY[5] = {0, 0, 0, -1, 1};\n        static const char MCH[5] = {'.', 'U', 'D', 'L', 'R'};\n        static const int ROPT[3] = {0, 1, -1};\n\n        for (int t = 0; t < turns; t++) {\n            int rem = turns - t;\n\n            int scx = remSrc ? (int)(sumSrcX / remSrc) : curX;\n            int scy = remSrc ? (int)(sumSrcY / remSrc) : curY;\n            int dcx = remDst ? (int)(sumDstX / remDst) : curX;\n            int dcy = remDst ? (int)(sumDstY / remDst) : curY;\n\n            // choose movement with feasibility d2 <= rem-1\n            int bestM = 0, bestScore = INT_MIN, bestDist2 = INT_MAX;\n            for (int m = 0; m < 5; m++) {\n                int nx = curX + MDX[m];\n                int ny = curY + MDY[m];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n\n                int d2 = man(nx, ny, bx, by);\n                if (d2 > rem - 1) continue;\n\n                int score = -20 * d2;\n\n                // estimate opportunistic potential for non-fixed leaves\n                for (int i = 0; i < K; i++) {\n                    if (fixed[i]) continue;\n\n                    bool canAct = false;\n                    int bestNear = INT_MAX;\n\n                    for (int oi = 0; oi < 3; oi++) {\n                        int opt = ROPT[oi];\n                        int nd = (curDir[i] + opt + 4) & 3;\n                        int tx = nx + DX[nd] * len[i];\n                        int ty = ny + DY[nd] * len[i];\n                        if (tx < 0 || tx >= N || ty < 0 || ty >= N) continue;\n                        int c = tx * N + ty;\n\n                        if (doAction && resMark[c] == rstamp) continue;\n\n                        if (hold[i]) {\n                            if (dst[c]) canAct = true;\n                            if (remDst > 0) bestNear = min(bestNear, man(tx, ty, dcx, dcy));\n                        } else {\n                            if (src[c]) canAct = true;\n                            if (remSrc > 0) bestNear = min(bestNear, man(tx, ty, scx, scy));\n                        }\n                    }\n\n                    if (canAct) score += 240;\n                    else if (bestNear != INT_MAX) score -= bestNear / 4;\n                }\n\n                int mixx, mixy;\n                if (heldNow > 0 && remDst > 0) {\n                    mixx = dcx; mixy = dcy;\n                } else if (remSrc > 0) {\n                    mixx = scx; mixy = scy;\n                } else {\n                    mixx = bx; mixy = by;\n                }\n                score -= man(nx, ny, mixx, mixy);\n\n                if (score > bestScore || (score == bestScore && d2 < bestDist2)) {\n                    bestScore = score;\n                    bestDist2 = d2;\n                    bestM = m;\n                }\n            }\n\n            curX += MDX[bestM];\n            curY += MDY[bestM];\n\n            string line(2 * Vp, '.');\n            line[0] = MCH[bestM];\n\n            int ustamp = ++stampUsed;\n\n            // rotations\n            for (int i = 0; i < K; i++) {\n                int chosenOpt = 0;\n\n                if (fixed[i]) {\n                    // ensure target direction reachable by final turn\n                    int td = assignDir[i];\n                    bool found = false;\n                    int bestCost = INT_MAX;\n\n                    for (int oi = 0; oi < 3; oi++) {\n                        int opt = ROPT[oi];\n                        int nd = (curDir[i] + opt + 4) & 3;\n                        int need = rotD[nd][td];\n                        if (need > rem - 1) continue;\n                        int cost = need * 10 + (opt != 0);\n                        if (cost < bestCost) {\n                            bestCost = cost;\n                            chosenOpt = opt;\n                            found = true;\n                        }\n                    }\n\n                    if (!found) {\n                        int bestNeed = INT_MAX;\n                        for (int oi = 0; oi < 3; oi++) {\n                            int opt = ROPT[oi];\n                            int nd = (curDir[i] + opt + 4) & 3;\n                            int need = rotD[nd][td];\n                            if (need < bestNeed) {\n                                bestNeed = need;\n                                chosenOpt = opt;\n                            }\n                        }\n                    }\n                } else {\n                    int bestVal = INT_MIN;\n\n                    for (int oi = 0; oi < 3; oi++) {\n                        int opt = ROPT[oi];\n                        int nd = (curDir[i] + opt + 4) & 3;\n                        int tx = curX + DX[nd] * len[i];\n                        int ty = curY + DY[nd] * len[i];\n\n                        int val = -1000000;\n                        if (0 <= tx && tx < N && 0 <= ty && ty < N) {\n                            int c = tx * N + ty;\n                            val = 0;\n\n                            if (!(doAction && resMark[c] == rstamp) && usedMark[c] != ustamp) {\n                                if (hold[i] && dst[c]) {\n                                    val += 100000;\n                                    if (heldNow * 3 >= 2 * K) val += 700;\n                                } else if (!hold[i] && src[c]) {\n                                    val += 100000;\n                                    if (heldNow * 3 <= K) val += 300;\n                                }\n                            }\n\n                            if (hold[i]) {\n                                if (remDst > 0) val -= man(tx, ty, dcx, dcy);\n                            } else {\n                                if (remSrc > 0) val -= man(tx, ty, scx, scy);\n                            }\n\n                            if (opt != 0) val -= 1;\n                        }\n\n                        if (val > bestVal) {\n                            bestVal = val;\n                            chosenOpt = opt;\n                        }\n                    }\n                }\n\n                if (chosenOpt == 1) {\n                    line[1 + i] = 'R';\n                    curDir[i] = (curDir[i] + 1) & 3;\n                } else if (chosenOpt == -1) {\n                    line[1 + i] = 'L';\n                    curDir[i] = (curDir[i] + 3) & 3;\n                }\n            }\n\n            int posCell[MAXK];\n            for (int i = 0; i < K; i++) {\n                int tx = curX + DX[curDir[i]] * len[i];\n                int ty = curY + DY[curDir[i]] * len[i];\n                if (0 <= tx && tx < N && 0 <= ty && ty < N) posCell[i] = tx * N + ty;\n                else posCell[i] = -1;\n            }\n\n            bool doP[MAXK] = {};\n\n            // planned final actions first\n            if (doAction && t == turns - 1) {\n                for (int i = 0; i < K; i++) if (fixed[i]) {\n                    int c = posCell[i];\n                    if (c >= 0 && usedMark[c] != ustamp) {\n                        doP[i] = true;\n                        usedMark[c] = ustamp;\n                    }\n                }\n            }\n\n            // opportunistic actions (prioritize constrained/long leaves)\n            for (int idx = 0; idx < K; idx++) {\n                int i = leafPriority[idx];\n                if (doAction && fixed[i]) continue;\n\n                int c = posCell[i];\n                if (c < 0) continue;\n                if (doAction && resMark[c] == rstamp) continue;\n                if (usedMark[c] == ustamp) continue;\n\n                if (hold[i]) {\n                    if (dst[c]) {\n                        doP[i] = true;\n                        usedMark[c] = ustamp;\n                    }\n                } else {\n                    if (src[c]) {\n                        doP[i] = true;\n                        usedMark[c] = ustamp;\n                    }\n                }\n            }\n\n            for (int i = 0; i < K; i++) {\n                if (doP[i]) line[Vp + (i + 1)] = 'P';\n            }\n\n            ops.push_back(move(line));\n\n            // apply actions in leaf order\n            for (int i = 0; i < K; i++) {\n                if (!doP[i]) continue;\n                int c = posCell[i];\n                if (c < 0) continue;\n\n                int x = c / N, y = c % N;\n\n                if (hold[i]) {\n                    // drop\n                    if (dst[c]) {\n                        dst[c] = 0;\n                        remDst--;\n                        sumDstX -= x;\n                        sumDstY -= y;\n                        hold[i] = 0;\n                        heldNow--;\n                    }\n                } else {\n                    // pick\n                    if (src[c]) {\n                        src[c] = 0;\n                        remSrc--;\n                        sumSrcX -= x;\n                        sumSrcY -= y;\n                        hold[i] = 1;\n                        heldNow++;\n                    }\n                }\n            }\n        }\n    }\n\n    bool emergencySingleAction() {\n        if ((int)ops.size() >= 100000) return false;\n\n        // Prefer one drop\n        if (heldNow > 0 && remDst > 0) {\n            int bestTurns = INT_MAX, bestDist = INT_MAX;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf = 0; leaf < K; leaf++) if (hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (dst[c]) {\n                    int tx = rx[c], ty = ry[c];\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int dist = man(curX, curY, rr, cc);\n                        int rot = rotD[curDir[leaf]][d];\n                        int turns = max(dist, rot);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && dist < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = dist;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf >= 0) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        // Or one pick\n        if (remSrc > 0) {\n            int bestTurns = INT_MAX, bestDist = INT_MAX;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf = 0; leaf < K; leaf++) if (!hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (src[c]) {\n                    int tx = rx[c], ty = ry[c];\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int dist = man(curX, curY, rr, cc);\n                        int rot = rotD[curDir[leaf]][d];\n                        int turns = max(dist, rot);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && dist < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = dist;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf >= 0) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void plan() {\n        int safety = 0;\n\n        while ((remDst > 0 || heldNow > 0) && (int)ops.size() < 100000 && safety < 250000) {\n            safety++;\n\n            int emptyLeaves[MAXK], holdLeaves[MAXK];\n            int nE = 0, nH = 0;\n            for (int i = 0; i < K; i++) {\n                if (hold[i]) holdLeaves[nH++] = i;\n                else emptyLeaves[nE++] = i;\n            }\n\n            bool hasP = (remSrc > 0 && nE > 0);\n            bool hasD = (remDst > 0 && nH > 0);\n\n            if (!hasP && !hasD) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            int scx = remSrc ? (int)(sumSrcX / remSrc) : curX;\n            int scy = remSrc ? (int)(sumSrcY / remSrc) : curY;\n            int dcx = remDst ? (int)(sumDstX / remDst) : curX;\n            int dcy = remDst ? (int)(sumDstY / remDst) : curY;\n\n            int wPick = 100, wDrop = 100;\n            if (remSrc == 0) {\n                wPick = 0;\n                wDrop = 140;\n            } else if (remDst == 0) {\n                wDrop = 0;\n                wPick = 140;\n            } else {\n                int targetHeld = (int)((long long)K * remDst / (remSrc + remDst));\n                int diff = heldNow - targetHeld;\n                if (diff > 0) wDrop += min(40, diff * 8);\n                else wPick += min(40, (-diff) * 8);\n\n                if (heldNow == 0) wPick += 10;\n                if (heldNow == K) wDrop += 10;\n            }\n\n            Cand best;\n\n            for (int rid = 0; rid < C; rid++) {\n                int dist = man(curX, curY, rx[rid], ry[rid]);\n\n                if (dist <= 2) {\n                    MR p[3]{}, d[3]{};\n                    for (int l = 0; l <= 2; l++) {\n                        if (hasP) p[l] = matchGroup(rid, emptyLeaves, nE, src, l);\n                        if (hasD) d[l] = matchGroup(rid, holdLeaves, nH, dst, l);\n                    }\n\n                    int lpMax = hasP ? 2 : 0;\n                    int ldMax = hasD ? 2 : 0;\n\n                    for (int lp = 0; lp <= lpMax; lp++) {\n                        for (int ld = 0; ld <= ldMax; ld++) {\n                            int pick = hasP ? p[lp].cnt : 0;\n                            int drop = hasD ? d[ld].cnt : 0;\n                            int cnt = pick + drop;\n                            if (cnt == 0) continue;\n\n                            int R = max(hasP ? p[lp].rmax : 0, hasD ? d[ld].rmax : 0);\n                            int turns = max(dist, R);\n                            if (turns == 0) turns = 1;\n\n                            int held2 = heldNow + pick - drop;\n                            int pen = holdPenaltyAt(rid, held2, scx, scy, dcx, dcy);\n\n                            int rs2 = remSrc - pick;\n                            int rd2 = remDst - drop;\n                            int fut = 0;\n                            if (rd2 > 0 && held2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                            else if (rs2 > 0 && held2 < K) fut = man(rx[rid], ry[rid], scx, scy);\n                            else if (rd2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                            else if (rs2 > 0) fut = man(rx[rid], ry[rid], scx, scy);\n\n                            Cand c;\n                            c.ok = true;\n                            c.rid = rid;\n                            c.lp = lp;\n                            c.ld = ld;\n                            c.pick = pick;\n                            c.drop = drop;\n                            c.cnt = cnt;\n                            c.turns = turns;\n                            c.dist = dist;\n                            c.pen = pen;\n                            c.fut = fut;\n                            c.util = pick * wPick + drop * wDrop;\n\n                            if (betterCand(c, best)) best = c;\n                        }\n                    }\n                } else {\n                    MR pp{}, dd{};\n                    if (hasP) pp = matchGroup(rid, emptyLeaves, nE, src, 2);\n                    if (hasD) dd = matchGroup(rid, holdLeaves, nH, dst, 2);\n\n                    int pick = pp.cnt;\n                    int drop = dd.cnt;\n                    int cnt = pick + drop;\n                    if (cnt == 0) continue;\n\n                    int R = max(pp.rmax, dd.rmax);\n                    int turns = max(dist, R);\n                    if (turns == 0) turns = 1;\n\n                    int held2 = heldNow + pick - drop;\n                    int pen = holdPenaltyAt(rid, held2, scx, scy, dcx, dcy);\n\n                    int rs2 = remSrc - pick;\n                    int rd2 = remDst - drop;\n                    int fut = 0;\n                    if (rd2 > 0 && held2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                    else if (rs2 > 0 && held2 < K) fut = man(rx[rid], ry[rid], scx, scy);\n                    else if (rd2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                    else if (rs2 > 0) fut = man(rx[rid], ry[rid], scx, scy);\n\n                    Cand c;\n                    c.ok = true;\n                    c.rid = rid;\n                    c.lp = hasP ? 2 : 0;\n                    c.ld = hasD ? 2 : 0;\n                    c.pick = pick;\n                    c.drop = drop;\n                    c.cnt = cnt;\n                    c.turns = turns;\n                    c.dist = dist;\n                    c.pen = pen;\n                    c.fut = fut;\n                    c.util = pick * wPick + drop * wDrop;\n\n                    if (betterCand(c, best)) best = c;\n                }\n            }\n\n            if (!best.ok) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            vector<int> assignDir(K, -1), assignCell(K, -1);\n\n            if (hasP && best.pick > 0) {\n                int lp = best.lp;\n                for (int l = 0; l < lp; l++) {\n                    if (matchGroup(best.rid, emptyLeaves, nE, src, l).cnt == best.pick) {\n                        lp = l;\n                        break;\n                    }\n                }\n                matchGroup(best.rid, emptyLeaves, nE, src, lp, assignDir.data(), assignCell.data());\n            }\n\n            if (hasD && best.drop > 0) {\n                int ld = best.ld;\n                for (int l = 0; l < ld; l++) {\n                    if (matchGroup(best.rid, holdLeaves, nH, dst, l).cnt == best.drop) {\n                        ld = l;\n                        break;\n                    }\n                }\n                matchGroup(best.rid, holdLeaves, nH, dst, ld, assignDir.data(), assignCell.data());\n            }\n\n            int acts = 0;\n            for (int i = 0; i < K; i++) if (assignDir[i] >= 0) acts++;\n\n            if (acts == 0) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            executeMove(best.rid, assignDir, assignCell);\n        }\n\n        // final guard\n        while ((remDst > 0 || heldNow > 0) && (int)ops.size() < 100000) {\n            if (!emergencySingleAction()) break;\n        }\n    }\n\n    void output() {\n        cout << Vp << '\\n';\n        for (int i = 0; i < K; i++) {\n            cout << 0 << ' ' << len[i] << '\\n';\n        }\n        cout << initX << ' ' << initY << '\\n';\n        for (const string& s : ops) cout << s << '\\n';\n    }\n\n    void run() {\n        input();\n        buildRot();\n        buildArm();\n        precomputeReach();\n        chooseInitialRoot();\n        plan();\n        output();\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}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing atcoder::mf_graph;\nusing ll = long long;\n\nstruct Point {\n    int x, y;\n};\n\nstruct RectCand {\n    int val, x1, x2, y1, y2;\n};\n\nstruct Component {\n    vector<int> cells;\n    int score = 0;\n    int perim = 0;\n    int minx = INT_MAX, maxx = -1;\n    int miny = INT_MAX, maxy = -1;\n};\n\nclass Solver {\n    static constexpr int COORD_MAX = 100000;\n    static constexpr int PERIM_LIMIT = 400000;\n    static constexpr double SOFT_LIMIT = 1.82;\n    static constexpr int KEEP_CANDS = 14;\n\n    int N;\n    vector<Point> pts;\n    vector<int> wt; // +1 mackerel, -1 sardine\n\n    // grid state\n    int STEP = 500;\n    int W = 0, H = 0, C = 0;\n    int PmaxUnits = 0;\n\n    vector<int> raw;\n    vector<int> outsideSides;\n    vector<pair<int, int>> adjPairs;\n    vector<int> prefix;\n    vector<vector<int>> pointCandCells; // point -> candidate cells\n    vector<vector<int>> cellPoints;     // cell -> points influenced\n\n    struct PolyCand {\n        int estDiff;\n        uint64_t h;\n        vector<Point> poly;\n    };\n    vector<PolyCand> cands;\n\n    chrono::steady_clock::time_point st;\n\n    inline int id(int x, int y) const { return y * W + x; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    double remaining() const { return SOFT_LIMIT - elapsed(); }\n    bool time_over() const { return elapsed() >= SOFT_LIMIT; }\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    // ---------- Input ----------\n    void read_input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        pts.resize(2 * N);\n        wt.resize(2 * N);\n\n        for (int i = 0; i < 2 * N; i++) {\n            cin >> pts[i].x >> pts[i].y;\n            wt[i] = (i < N ? +1 : -1);\n        }\n    }\n\n    // ---------- Grid ----------\n    void build_grid(int step) {\n        STEP = step;\n        W = COORD_MAX / STEP;\n        H = COORD_MAX / STEP;\n        C = W * H;\n        PmaxUnits = PERIM_LIMIT / STEP;\n\n        raw.assign(C, 0);\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x / STEP;\n            int y = pts[i].y / STEP;\n            if (x >= W) x = W - 1;\n            if (y >= H) y = H - 1;\n            raw[id(x, y)] += wt[i];\n        }\n\n        outsideSides.assign(C, 0);\n        adjPairs.clear();\n        adjPairs.reserve(C * 2);\n\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int v = id(x, y);\n\n                int out = 0;\n                if (x == 0) out++;\n                if (x + 1 == W) out++;\n                if (y == 0) out++;\n                if (y + 1 == H) out++;\n                outsideSides[v] = out;\n\n                if (x + 1 < W) adjPairs.push_back({v, id(x + 1, y)});\n                if (y + 1 < H) adjPairs.push_back({v, id(x, y + 1)});\n            }\n        }\n\n        // prefix sum over raw\n        prefix.assign((W + 1) * (H + 1), 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int cur = raw[id(x, y)];\n                int A = prefix[y * (W + 1) + (x + 1)];\n                int B = prefix[(y + 1) * (W + 1) + x];\n                int D = prefix[y * (W + 1) + x];\n                prefix[(y + 1) * (W + 1) + (x + 1)] = cur + A + B - D;\n            }\n        }\n\n        // exact inclusion candidate cells for each point (boundary inclusive)\n        pointCandCells.assign(2 * N, {});\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            int qx = x / STEP, qy = y / STEP;\n\n            vector<int> xs, ys;\n            if (qx >= W) xs = {W - 1};\n            else if (x % STEP == 0 && qx > 0) xs = {qx - 1, qx};\n            else xs = {qx};\n\n            if (qy >= H) ys = {H - 1};\n            else if (y % STEP == 0 && qy > 0) ys = {qy - 1, qy};\n            else ys = {qy};\n\n            vector<int> cand;\n            cand.reserve(4);\n            for (int xx : xs) for (int yy : ys) {\n                int v = id(xx, yy);\n                bool dup = false;\n                for (int z : cand) if (z == v) { dup = true; break; }\n                if (!dup) cand.push_back(v);\n            }\n            pointCandCells[i] = move(cand);\n        }\n\n        // inverse map: cell -> points that this cell can affect\n        cellPoints.assign(C, {});\n        for (int i = 0; i < 2 * N; i++) {\n            for (int c : pointCandCells[i]) cellPoints[c].push_back(i);\n        }\n    }\n\n    int rect_sum(int x1, int y1, int x2, int y2) const {\n        if (x1 > x2 || y1 > y2) return 0;\n        x1 = max(x1, 0);\n        y1 = max(y1, 0);\n        x2 = min(x2, W - 1);\n        y2 = min(y2, H - 1);\n        if (x1 > x2 || y1 > y2) return 0;\n\n        int A = prefix[(y2 + 1) * (W + 1) + (x2 + 1)];\n        int B = prefix[y1 * (W + 1) + (x2 + 1)];\n        int Cc = prefix[(y2 + 1) * (W + 1) + x1];\n        int D = prefix[y1 * (W + 1) + x1];\n        return A - B - Cc + D;\n    }\n\n    vector<int> build_profit(int r) const {\n        vector<int> p(C, 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int v = id(x, y);\n                int s = rect_sum(x - r, y - r, x + r, y + r);\n                if (r == 0) p[v] = raw[v] * 20;\n                else p[v] = s * 8 + raw[v] * 4;\n            }\n        }\n        return p;\n    }\n\n    // ---------- Segmentation ----------\n    vector<char> segment_cut(const vector<int>& profit, int lambda) const {\n        vector<char> sel(C, 0);\n\n        if (lambda == 0) {\n            for (int i = 0; i < C; i++) sel[i] = (profit[i] > 0);\n            return sel;\n        }\n\n        int S = C, T = C + 1;\n        mf_graph<int> g(C + 2);\n\n        for (int v = 0; v < C; v++) {\n            int c1 = -profit[v] + lambda * outsideSides[v];\n            if (c1 >= 0) g.add_edge(v, T, c1);\n            else g.add_edge(S, v, -c1);\n        }\n\n        for (auto [u, v] : adjPairs) {\n            g.add_edge(u, v, lambda);\n            g.add_edge(v, u, lambda);\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n        for (int i = 0; i < C; i++) sel[i] = cut[i] ? 1 : 0;\n        return sel;\n    }\n\n    vector<Component> top_components(const vector<char>& sel, int K) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n        vector<Component> comps;\n        comps.reserve(64);\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n\n            Component cp;\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cp.cells.push_back(v);\n                cp.score += raw[v];\n\n                int x = v % W, y = v / W;\n                cp.minx = min(cp.minx, x);\n                cp.maxx = max(cp.maxx, x);\n                cp.miny = min(cp.miny, y);\n                cp.maxy = max(cp.maxy, y);\n\n                if (x == 0 || !sel[v - 1]) cp.perim++;\n                else if (!vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n\n                if (x + 1 == W || !sel[v + 1]) cp.perim++;\n                else if (!vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n\n                if (y == 0 || !sel[v - W]) cp.perim++;\n                else if (!vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n\n                if (y + 1 == H || !sel[v + W]) cp.perim++;\n                else if (!vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (cp.score > 0) comps.push_back(move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [&](const Component& a, const Component& b) {\n            if (a.score != b.score) return a.score > b.score;\n            if (a.perim != b.perim) return a.perim < b.perim;\n            return a.cells.size() > b.cells.size();\n        });\n\n        if ((int)comps.size() > K) comps.resize(K);\n        return comps;\n    }\n\n    int bbox_dist(const Component& a, const Component& b) const {\n        int dx = 0, dy = 0;\n        if (a.maxx < b.minx) dx = b.minx - a.maxx - 1;\n        else if (b.maxx < a.minx) dx = a.minx - b.maxx - 1;\n\n        if (a.maxy < b.miny) dy = b.miny - a.maxy - 1;\n        else if (b.maxy < a.miny) dy = a.miny - b.maxy - 1;\n\n        return dx + dy;\n    }\n\n    bool connect_components_fast(const Component& A, const Component& B, vector<char>& outSel) const {\n        outSel.assign(C, 0);\n\n        vector<char> inB(C, 0);\n        vector<int> parent(C, -1);\n        queue<int> q;\n\n        for (int v : A.cells) {\n            outSel[v] = 1;\n            parent[v] = -2;\n            q.push(v);\n        }\n        for (int v : B.cells) {\n            outSel[v] = 1;\n            inB[v] = 1;\n        }\n\n        int target = -1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (inB[v]) { target = v; break; }\n\n            int x = v % W, y = v / W;\n            auto relax = [&](int to) {\n                if (parent[to] == -1) {\n                    parent[to] = v;\n                    q.push(to);\n                }\n            };\n\n            if (x > 0) relax(v - 1);\n            if (x + 1 < W) relax(v + 1);\n            if (y > 0) relax(v - W);\n            if (y + 1 < H) relax(v + W);\n        }\n\n        if (target == -1) return false;\n\n        int cur = target;\n        while (parent[cur] != -2) {\n            outSel[cur] = 1;\n            cur = parent[cur];\n            if (cur < 0) return false;\n        }\n        outSel[cur] = 1;\n        return true;\n    }\n\n    bool connect_components_weighted(const Component& A, const Component& B, vector<char>& outSel) const {\n        outSel.assign(C, 0);\n        vector<char> inA(C, 0), inB(C, 0);\n\n        for (int v : A.cells) {\n            outSel[v] = 1;\n            inA[v] = 1;\n        }\n        for (int v : B.cells) {\n            outSel[v] = 1;\n            inB[v] = 1;\n        }\n\n        const int INF = 1e9;\n        vector<int> dist(C, INF), par(C, -1);\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n        for (int v : A.cells) {\n            dist[v] = 0;\n            par[v] = -2;\n            pq.push({0, v});\n        }\n\n        int HARD = PmaxUnits * 8 + 220;\n        int target = -1;\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            if (d > HARD) break;\n            if (inB[v]) { target = v; break; }\n\n            int x = v % W, y = v / W;\n            auto relax = [&](int to) {\n                int add = 0;\n                if (!(inA[to] || inB[to])) {\n                    int neg = max(0, -raw[to]);\n                    add = 1 + 3 * neg;\n                }\n                int nd = d + add;\n                if (nd < dist[to] && nd <= HARD) {\n                    dist[to] = nd;\n                    par[to] = v;\n                    pq.push({nd, to});\n                }\n            };\n\n            if (x > 0) relax(v - 1);\n            if (x + 1 < W) relax(v + 1);\n            if (y > 0) relax(v - W);\n            if (y + 1 < H) relax(v + W);\n        }\n\n        if (target == -1) return false;\n\n        int cur = target;\n        while (par[cur] != -2) {\n            outSel[cur] = 1;\n            cur = par[cur];\n            if (cur < 0) return false;\n        }\n        outSel[cur] = 1;\n        return true;\n    }\n\n    // ---------- region utilities ----------\n    int count_nb(const vector<char>& sel, int v) const {\n        int x = v % W, y = v / W;\n        int c = 0;\n        if (x > 0 && sel[v - 1]) c++;\n        if (x + 1 < W && sel[v + 1]) c++;\n        if (y > 0 && sel[v - W]) c++;\n        if (y + 1 < H && sel[v + W]) c++;\n        return c;\n    }\n\n    pair<int, int> score_perim(const vector<char>& sel) const {\n        int sc = 0, per = 0;\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            sc += raw[v];\n            int x = v % W, y = v / W;\n            if (x == 0 || !sel[v - 1]) per++;\n            if (x + 1 == W || !sel[v + 1]) per++;\n            if (y == 0 || !sel[v - W]) per++;\n            if (y + 1 == H || !sel[v + W]) per++;\n        }\n        return {sc, per};\n    }\n\n    void enforce_single_component(vector<char>& sel) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n\n        int compCnt = 0;\n        int bestSc = INT_MIN;\n        vector<int> bestCells;\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n            compCnt++;\n\n            vector<int> cells;\n            int sc = 0;\n\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cells.push_back(v);\n                sc += raw[v];\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && !vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n                if (x + 1 < W && sel[v + 1] && !vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n                if (y > 0 && sel[v - W] && !vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n                if (y + 1 < H && sel[v + W] && !vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (sc > bestSc) {\n                bestSc = sc;\n                bestCells = move(cells);\n            }\n        }\n\n        if (compCnt <= 1) return;\n        fill(sel.begin(), sel.end(), 0);\n        for (int v : bestCells) sel[v] = 1;\n    }\n\n    void fill_holes(vector<char>& sel) const {\n        int minx = W, miny = H, maxx = -1, maxy = -1;\n        for (int v = 0; v < C; v++) if (sel[v]) {\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        if (maxx < minx) return;\n\n        int bw = maxx - minx + 1;\n        int bh = maxy - miny + 1;\n        int LW = bw + 2;\n        int LH = bh + 2;\n\n        vector<char> blocked(LW * LH, 0), vis(LW * LH, 0);\n\n        for (int y = miny; y <= maxy; y++) {\n            for (int x = minx; x <= maxx; x++) {\n                int gv = id(x, y);\n                if (sel[gv]) {\n                    int lx = (x - minx) + 1;\n                    int ly = (y - miny) + 1;\n                    blocked[ly * LW + lx] = 1;\n                }\n            }\n        }\n\n        queue<int> q;\n        auto push_if = [&](int lx, int ly) {\n            int t = ly * LW + lx;\n            if (!blocked[t] && !vis[t]) {\n                vis[t] = 1;\n                q.push(t);\n            }\n        };\n\n        for (int x = 0; x < LW; x++) {\n            push_if(x, 0);\n            push_if(x, LH - 1);\n        }\n        for (int y = 0; y < LH; y++) {\n            push_if(0, y);\n            push_if(LW - 1, y);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int x = v % LW, y = v / LW;\n            if (x > 0) push_if(x - 1, y);\n            if (x + 1 < LW) push_if(x + 1, y);\n            if (y > 0) push_if(x, y - 1);\n            if (y + 1 < LH) push_if(x, y + 1);\n        }\n\n        for (int ly = 1; ly <= bh; ly++) {\n            for (int lx = 1; lx <= bw; lx++) {\n                int t = ly * LW + lx;\n                if (!blocked[t] && !vis[t]) {\n                    int gx = minx + (lx - 1);\n                    int gy = miny + (ly - 1);\n                    sel[id(gx, gy)] = 1;\n                }\n            }\n        }\n    }\n\n    void resolve_diagonal_crosses(vector<char>& sel) const {\n        for (int it = 0; it < 2; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < H; y++) {\n                for (int x = 0; x + 1 < W; x++) {\n                    int a = id(x, y);\n                    int b = id(x + 1, y);\n                    int c = id(x, y + 1);\n                    int d = id(x + 1, y + 1);\n\n                    if (sel[a] && sel[d] && !sel[b] && !sel[c]) {\n                        sel[(raw[b] >= raw[c]) ? b : c] = 1;\n                        changed = true;\n                    } else if (!sel[a] && !sel[d] && sel[b] && sel[c]) {\n                        sel[(raw[a] >= raw[d]) ? a : d] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void refine(vector<char>& sel) const {\n        auto sp = score_perim(sel);\n        int perim = sp.second;\n\n        // remove non-positive leaves\n        queue<int> q;\n        for (int v = 0; v < C; v++) {\n            if (sel[v] && raw[v] <= 0 && count_nb(sel, v) <= 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (!sel[v]) continue;\n\n            int deg = count_nb(sel, v);\n            if (raw[v] <= 0 && deg <= 1) {\n                sel[v] = 0;\n                perim += (-4 + 2 * deg);\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && raw[v - 1] <= 0 && count_nb(sel, v - 1) <= 1) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1] && raw[v + 1] <= 0 && count_nb(sel, v + 1) <= 1) q.push(v + 1);\n                if (y > 0 && sel[v - W] && raw[v - W] <= 0 && count_nb(sel, v - W) <= 1) q.push(v - W);\n                if (y + 1 < H && sel[v + W] && raw[v + W] <= 0 && count_nb(sel, v + W) <= 1) q.push(v + W);\n            }\n        }\n\n        // if perimeter too high, remove leaves with least loss\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> leafPQ;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) {\n            leafPQ.push({raw[v], v});\n        }\n\n        while (perim > PmaxUnits && !leafPQ.empty()) {\n            auto [rw, v] = leafPQ.top();\n            leafPQ.pop();\n            (void)rw;\n\n            if (!sel[v]) continue;\n            int deg = count_nb(sel, v);\n            if (deg > 1) continue;\n\n            sel[v] = 0;\n            perim += (-4 + 2 * deg);\n\n            int x = v % W, y = v / W;\n            if (x > 0 && sel[v - 1] && count_nb(sel, v - 1) <= 1) leafPQ.push({raw[v - 1], v - 1});\n            if (x + 1 < W && sel[v + 1] && count_nb(sel, v + 1) <= 1) leafPQ.push({raw[v + 1], v + 1});\n            if (y > 0 && sel[v - W] && count_nb(sel, v - W) <= 1) leafPQ.push({raw[v - W], v - W});\n            if (y + 1 < H && sel[v + W] && count_nb(sel, v + W) <= 1) leafPQ.push({raw[v + W], v + W});\n        }\n\n        // frontier growth\n        priority_queue<pair<int, int>> pq;\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty()) {\n            int v = pq.top().second;\n            pq.pop();\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            bool take = false;\n            if (raw[v] > 0) take = true;\n            else if (raw[v] == 0 && dP <= 0) take = true;\n            else if (raw[v] >= -1 && dP <= -2) take = true;\n\n            if (!take) continue;\n\n            sel[v] = 1;\n            perim += dP;\n\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n    }\n\n    // ---------- exact diff on selected cells ----------\n    int exact_diff(const vector<char>& sel) const {\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            bool inside = false;\n            for (int c : pointCandCells[i]) {\n                if (sel[c]) { inside = true; break; }\n            }\n            if (inside) diff += wt[i];\n        }\n        return diff;\n    }\n\n    int delta_add_cell(int v, const vector<int>& cov) const {\n        int d = 0;\n        for (int pi : cellPoints[v]) if (cov[pi] == 0) d += wt[pi];\n        return d;\n    }\n\n    int delta_remove_cell(int v, const vector<int>& cov) const {\n        int d = 0;\n        for (int pi : cellPoints[v]) if (cov[pi] == 1) d -= wt[pi];\n        return d;\n    }\n\n    void apply_add_cell(int v, vector<int>& cov) const {\n        for (int pi : cellPoints[v]) cov[pi]++;\n    }\n\n    void apply_remove_cell(int v, vector<int>& cov) const {\n        for (int pi : cellPoints[v]) cov[pi]--;\n    }\n\n    // local exact polish (cheap point-based boundary refinement)\n    void exact_polish(vector<char>& sel) const {\n        if (remaining() < 0.055) return;\n\n        vector<int> cov(2 * N, 0);\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            for (int pi : cellPoints[v]) cov[pi]++;\n        }\n\n        auto sp = score_perim(sel);\n        int perim = sp.second;\n\n        int maxMoves = (STEP <= 500 ? 320 : 220);\n        if (remaining() > 0.30) maxMoves += 120;\n        if (remaining() < 0.12) maxMoves = max(120, maxMoves / 2);\n\n        int moves = 0;\n\n        queue<int> q;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) q.push(v);\n\n        auto try_remove = [&](int v) -> bool {\n            if (!sel[v]) return false;\n            int deg = count_nb(sel, v);\n            if (deg > 1) return false;\n\n            int dP = -4 + 2 * deg;\n            int d = delta_remove_cell(v, cov);\n\n            bool take = false;\n            if (d > 0) take = true;\n            else if (d == 0 && dP < 0) take = true;\n            else if (perim > PmaxUnits && d >= -1) take = true;\n\n            if (!take) return false;\n\n            sel[v] = 0;\n            perim += dP;\n            apply_remove_cell(v, cov);\n            moves++;\n            return true;\n        };\n\n        while (!q.empty() && moves < maxMoves && remaining() > 0.02) {\n            int v = q.front(); q.pop();\n            if (try_remove(v)) {\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1]) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1]) q.push(v + 1);\n                if (y > 0 && sel[v - W]) q.push(v - W);\n                if (y + 1 < H && sel[v + W]) q.push(v + W);\n            }\n        }\n\n        priority_queue<pair<int, int>> pq;\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty() && moves < maxMoves && remaining() > 0.02) {\n            int v = pq.top().second;\n            pq.pop();\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            int d = delta_add_cell(v, cov);\n\n            bool take = false;\n            if (d > 0) take = true;\n            else if (d == 0 && dP < 0) take = true;\n            else if (d >= -1 && dP <= -4 && remaining() > 0.12) take = true;\n\n            if (!take) continue;\n\n            sel[v] = 1;\n            perim += dP;\n            apply_add_cell(v, cov);\n            moves++;\n\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        // final tiny trim\n        queue<int> q2;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) q2.push(v);\n\n        while (!q2.empty() && moves < maxMoves && remaining() > 0.02) {\n            int v = q2.front(); q2.pop();\n            if (!sel[v]) continue;\n            int deg = count_nb(sel, v);\n            if (deg > 1) continue;\n\n            int dP = -4 + 2 * deg;\n            int d = delta_remove_cell(v, cov);\n\n            if (d > 0 || (d == 0 && dP < 0)) {\n                sel[v] = 0;\n                perim += dP;\n                apply_remove_cell(v, cov);\n                moves++;\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1]) q2.push(v - 1);\n                if (x + 1 < W && sel[v + 1]) q2.push(v + 1);\n                if (y > 0 && sel[v - W]) q2.push(v - W);\n                if (y + 1 < H && sel[v + W]) q2.push(v + W);\n            }\n        }\n    }\n\n    // ---------- Polygon ----------\n    static ll area2(const vector<Point>& poly) {\n        ll s = 0;\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            s += 1LL * poly[i].x * poly[j].y - 1LL * poly[i].y * poly[j].x;\n        }\n        return s;\n    }\n\n    vector<Point> cells_to_polygon(const vector<char>& sel) const {\n        const int SHIFT = 20;\n        auto key = [&](int x, int y) -> ll { return (ll(x) << SHIFT) | ll(y); };\n        auto decode = [&](ll k) -> Point {\n            return Point{int(k >> SHIFT), int(k & ((1LL << SHIFT) - 1))};\n        };\n\n        unordered_map<ll, ll> nxt;\n        unordered_map<ll, int> indeg;\n        nxt.reserve(10000);\n        indeg.reserve(10000);\n\n        bool bad = false;\n        auto add_edge = [&](ll a, ll b) {\n            auto it = nxt.find(a);\n            if (it != nxt.end() && it->second != b) {\n                bad = true;\n                return;\n            }\n            nxt[a] = b;\n            indeg[b]++;\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int cx = v % W, cy = v / W;\n            int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n            int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n\n            if (cy == 0 || !sel[v - W]) add_edge(key(x0, y0), key(x1, y0));\n            if (cx + 1 == W || !sel[v + 1]) add_edge(key(x1, y0), key(x1, y1));\n            if (cy + 1 == H || !sel[v + W]) add_edge(key(x1, y1), key(x0, y1));\n            if (cx == 0 || !sel[v - 1]) add_edge(key(x0, y1), key(x0, y0));\n\n            if (bad) return {};\n        }\n\n        if (nxt.empty()) return {};\n\n        for (auto &kv : nxt) {\n            ll a = kv.first;\n            if (indeg[a] != 1) return {};\n        }\n        for (auto &kv : indeg) {\n            if (kv.second != 1) return {};\n            if (!nxt.count(kv.first)) return {};\n        }\n\n        unordered_set<ll> used;\n        used.reserve(nxt.size() * 2 + 1);\n\n        vector<Point> best;\n        ll bestA = -1;\n\n        for (auto &kv : nxt) {\n            ll start = kv.first;\n            if (used.count(start)) continue;\n\n            unordered_set<ll> local;\n            local.reserve(nxt.size() * 2 + 1);\n\n            vector<Point> cyc;\n            ll cur = start;\n            bool ok = true;\n\n            while (true) {\n                if (local.count(cur)) {\n                    if (cur == start) break;\n                    ok = false;\n                    break;\n                }\n\n                local.insert(cur);\n                used.insert(cur);\n\n                auto it = nxt.find(cur);\n                if (it == nxt.end()) { ok = false; break; }\n\n                cyc.push_back(decode(cur));\n                cur = it->second;\n\n                if ((int)cyc.size() > (int)nxt.size() + 5) {\n                    ok = false;\n                    break;\n                }\n            }\n\n            if (!ok || (int)cyc.size() < 4) continue;\n\n            ll a = llabs(area2(cyc));\n            if (a > bestA) {\n                bestA = a;\n                best = move(cyc);\n            }\n        }\n\n        if (best.empty()) return {};\n\n        // remove collinear vertices\n        bool changed = true;\n        while (changed && best.size() > 4) {\n            changed = false;\n            int m = (int)best.size();\n            vector<Point> np;\n            np.reserve(m);\n\n            for (int i = 0; i < m; i++) {\n                Point a = best[(i - 1 + m) % m];\n                Point b = best[i];\n                Point c = best[(i + 1) % m];\n\n                if ((a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y)) {\n                    changed = true;\n                    continue;\n                }\n                np.push_back(b);\n            }\n\n            if (np.size() < 4) break;\n            best.swap(np);\n        }\n\n        return best;\n    }\n\n    bool basic_valid(const vector<Point>& poly) const {\n        int m = (int)poly.size();\n        if (m < 4 || m > 1000) return false;\n\n        const int SHIFT = 20;\n        unordered_set<ll> seen;\n        seen.reserve(m * 2);\n\n        ll per = 0;\n        for (int i = 0; i < m; i++) {\n            int x = poly[i].x, y = poly[i].y;\n            if (x < 0 || x > COORD_MAX || y < 0 || y > COORD_MAX) return false;\n\n            ll k = (ll(x) << SHIFT) | ll(y);\n            if (seen.count(k)) return false;\n            seen.insert(k);\n\n            int j = (i + 1) % m;\n            int x2 = poly[j].x, y2 = poly[j].y;\n            if (x != x2 && y != y2) return false;\n\n            ll len = llabs((ll)x - x2) + llabs((ll)y - y2);\n            if (len <= 0) return false;\n            per += len;\n        }\n\n        if (per > PERIM_LIMIT) return false;\n        if (area2(poly) == 0) return false;\n        return true;\n    }\n\n    struct Seg {\n        int x1, y1, x2, y2;\n        bool vert;\n    };\n\n    static bool overlap1d(int a, int b, int c, int d) {\n        if (a > b) swap(a, b);\n        if (c > d) swap(c, d);\n        return max(a, c) <= min(b, d);\n    }\n\n    static bool seg_intersect(const Seg& A, const Seg& B) {\n        if (A.vert && B.vert) {\n            if (A.x1 != B.x1) return false;\n            return overlap1d(A.y1, A.y2, B.y1, B.y2);\n        }\n        if (!A.vert && !B.vert) {\n            if (A.y1 != B.y1) return false;\n            return overlap1d(A.x1, A.x2, B.x1, B.x2);\n        }\n\n        const Seg& V = A.vert ? A : B;\n        const Seg& Hs = A.vert ? B : A;\n\n        int vx = V.x1;\n        int hy = Hs.y1;\n        int hxL = min(Hs.x1, Hs.x2), hxR = max(Hs.x1, Hs.x2);\n        int vyL = min(V.y1, V.y2), vyR = max(V.y1, V.y2);\n\n        return (hxL <= vx && vx <= hxR && vyL <= hy && hy <= vyR);\n    }\n\n    bool final_valid(const vector<Point>& poly) const {\n        if (!basic_valid(poly)) return false;\n        int m = (int)poly.size();\n\n        vector<Seg> edges(m);\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            edges[i] = Seg{\n                poly[i].x, poly[i].y,\n                poly[j].x, poly[j].y,\n                (poly[i].x == poly[j].x)\n            };\n        }\n\n        for (int i = 0; i < m; i++) {\n            for (int j = i + 1; j < m; j++) {\n                if ((i + 1) % m == j) continue;\n                if ((j + 1) % m == i) continue;\n                if (seg_intersect(edges[i], edges[j])) return false;\n            }\n        }\n        return true;\n    }\n\n    // ---------- Exact score on polygon ----------\n    bool point_in_poly_inclusive(int x, int y, const vector<Point>& poly) const {\n        bool inside = false;\n        int m = (int)poly.size();\n\n        for (int i = 0; i < m; i++) {\n            Point a = poly[i];\n            Point b = poly[(i + 1) % m];\n\n            if (a.y == b.y) { // horizontal\n                int lx = min(a.x, b.x), rx = max(a.x, b.x);\n                if (y == a.y && lx <= x && x <= rx) return true;\n            } else { // vertical\n                int xv = a.x;\n                int ly = min(a.y, b.y), ry = max(a.y, b.y);\n\n                if (x == xv && ly <= y && y <= ry) return true; // boundary\n                if (ly <= y && y < ry && x < xv) inside = !inside;\n            }\n        }\n        return inside;\n    }\n\n    int exact_diff_polygon(const vector<Point>& poly) const {\n        int minx = COORD_MAX, miny = COORD_MAX, maxx = 0, maxy = 0;\n        for (auto &p : poly) {\n            minx = min(minx, p.x);\n            maxx = max(maxx, p.x);\n            miny = min(miny, p.y);\n            maxy = max(maxy, p.y);\n        }\n\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x < minx || x > maxx || y < miny || y > maxy) continue;\n            if (point_in_poly_inclusive(x, y, poly)) diff += wt[i];\n        }\n        return diff;\n    }\n\n    // ---------- candidate management ----------\n    uint64_t hash_poly(const vector<Point>& poly) const {\n        uint64_t h1 = 0x123456789abcdefULL;\n        uint64_t h2 = 0xfedcba987654321ULL;\n\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            const Point& A = poly[i];\n            const Point& B = poly[(i + 1) % m];\n\n            uint64_t u = ((uint64_t)A.x << 17) | (uint64_t)A.y;\n            uint64_t v = ((uint64_t)B.x << 17) | (uint64_t)B.y;\n            if (u > v) swap(u, v);\n\n            uint64_t e = splitmix64(u * 0x9e3779b97f4a7c15ULL ^ v * 0xbf58476d1ce4e5b9ULL);\n            h1 ^= e;\n            h2 ^= splitmix64(e + 0x94d049bb133111ebULL + (h2 << 6) + (h2 >> 2));\n        }\n\n        uint64_t a = (uint64_t)llabs(area2(poly));\n        return splitmix64(h1 ^ (h2 << 1) ^ (uint64_t)m * 0x94d049bb133111ebULL ^ a);\n    }\n\n    int worst_kept_diff() const {\n        if ((int)cands.size() < KEEP_CANDS) return INT_MIN / 2;\n        return cands.back().estDiff;\n    }\n\n    void add_poly_candidate(int diff, vector<Point> poly) {\n        if (!basic_valid(poly)) return;\n        uint64_t h = hash_poly(poly);\n\n        for (auto &cd : cands) {\n            if (cd.h == h) {\n                if (cd.estDiff >= diff - 1) return;\n                cd.estDiff = diff;\n                cd.poly = move(poly);\n                sort(cands.begin(), cands.end(), [](const PolyCand& a, const PolyCand& b) {\n                    if (a.estDiff != b.estDiff) return a.estDiff > b.estDiff;\n                    return a.poly.size() < b.poly.size();\n                });\n                return;\n            }\n        }\n\n        cands.push_back({diff, h, move(poly)});\n        sort(cands.begin(), cands.end(), [](const PolyCand& a, const PolyCand& b) {\n            if (a.estDiff != b.estDiff) return a.estDiff > b.estDiff;\n            return a.poly.size() < b.poly.size();\n        });\n        if ((int)cands.size() > KEEP_CANDS) cands.resize(KEEP_CANDS);\n    }\n\n    // ---------- generators ----------\n    vector<int> top_seed_cells(int K) const {\n        vector<int> idx(C);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            return raw[a] > raw[b];\n        });\n\n        vector<int> seeds;\n        seeds.reserve(K);\n\n        for (int v : idx) {\n            if (raw[v] <= 0) break;\n            int x = v % W, y = v / W;\n            bool ok = true;\n            for (int s : seeds) {\n                int sx = s % W, sy = s / W;\n                if (abs(x - sx) + abs(y - sy) < 4) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) seeds.push_back(v);\n            if ((int)seeds.size() >= K) break;\n        }\n\n        if (seeds.empty()) {\n            int best = (int)(max_element(raw.begin(), raw.end()) - raw.begin());\n            seeds.push_back(best);\n        }\n        return seeds;\n    }\n\n    vector<char> grow_from_seed(int seed, int mode) const {\n        vector<char> sel(C, 0);\n        sel[seed] = 1;\n        int perim = 4;\n\n        priority_queue<pair<int, int>> pq;\n        auto push_if = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        int x = seed % W, y = seed / W;\n        if (x > 0) push_if(seed - 1);\n        if (x + 1 < W) push_if(seed + 1);\n        if (y > 0) push_if(seed - W);\n        if (y + 1 < H) push_if(seed + W);\n\n        while (!pq.empty()) {\n            int v = pq.top().second;\n            pq.pop();\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            bool take = false;\n            if (raw[v] > 0) take = true;\n            else if (raw[v] == 0 && dP <= 0) take = true;\n            else if (mode == 1 && raw[v] >= -1 && dP <= -2) take = true;\n\n            if (!take) continue;\n\n            sel[v] = 1;\n            perim += dP;\n\n            int cx = v % W, cy = v / W;\n            if (cx > 0) push_if(v - 1);\n            if (cx + 1 < W) push_if(v + 1);\n            if (cy > 0) push_if(v - W);\n            if (cy + 1 < H) push_if(v + W);\n        }\n\n        return sel;\n    }\n\n    vector<RectCand> best_rectangles(int K, double breakRemain) const {\n        struct CmpMin {\n            bool operator()(const RectCand& a, const RectCand& b) const {\n                return a.val > b.val;\n            }\n        };\n\n        priority_queue<RectCand, vector<RectCand>, CmpMin> pq;\n        vector<int> acc(H, 0), ps(H + 1, 0);\n\n        for (int x1 = 0; x1 < W; x1++) {\n            if ((x1 & 7) == 0 && remaining() < breakRemain) break;\n\n            fill(acc.begin(), acc.end(), 0);\n\n            for (int x2 = x1; x2 < W; x2++) {\n                for (int y = 0; y < H; y++) acc[y] += raw[id(x2, y)];\n\n                int wcell = x2 - x1 + 1;\n                int L = PmaxUnits / 2 - wcell;\n                if (L < 1) break;\n\n                ps[0] = 0;\n                for (int y = 0; y < H; y++) ps[y + 1] = ps[y] + acc[y];\n\n                deque<int> dq;\n                int best = INT_MIN;\n                int bl = 0, br = 0;\n\n                for (int j = 1; j <= H; j++) {\n                    int add = j - 1;\n                    while (!dq.empty() && ps[dq.back()] >= ps[add]) dq.pop_back();\n                    dq.push_back(add);\n\n                    int lim = j - L;\n                    while (!dq.empty() && dq.front() < lim) dq.pop_front();\n\n                    if (!dq.empty()) {\n                        int val = ps[j] - ps[dq.front()];\n                        if (val > best) {\n                            best = val;\n                            bl = dq.front();\n                            br = j;\n                        }\n                    }\n                }\n\n                if (best <= 0 || br <= bl) continue;\n                RectCand rc{best, x1, x2, bl, br - 1};\n\n                if ((int)pq.size() < K) pq.push(rc);\n                else if (rc.val > pq.top().val) {\n                    pq.pop();\n                    pq.push(rc);\n                }\n            }\n        }\n\n        vector<RectCand> out;\n        while (!pq.empty()) {\n            out.push_back(pq.top());\n            pq.pop();\n        }\n        sort(out.begin(), out.end(), [](const RectCand& a, const RectCand& b) {\n            return a.val > b.val;\n        });\n        return out;\n    }\n\n    // ---------- fallback ----------\n    int rect_diff(int x0, int x1, int y0, int y1) const {\n        int d = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x0 <= x && x <= x1 && y0 <= y && y <= y1) d += wt[i];\n        }\n        return d;\n    }\n\n    vector<Point> cell_rect_poly(int v) const {\n        int cx = v % W, cy = v / W;\n        int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n        int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    pair<vector<Point>, int> best_tiny_fallback() const {\n        const int SHIFT = 20;\n        auto key = [&](int x, int y) -> ll {\n            return (ll(x) << SHIFT) | ll(y);\n        };\n\n        unordered_map<ll, int> mp;\n        mp.reserve(30000);\n        for (int i = 0; i < 2 * N; i++) {\n            mp[key(pts[i].x, pts[i].y)] += wt[i];\n        }\n\n        auto getw = [&](int x, int y) -> int {\n            auto it = mp.find(key(x, y));\n            return (it == mp.end() ? 0 : it->second);\n        };\n\n        int best = -1e9;\n        vector<Point> poly;\n\n        for (int i = 0; i < N; i++) {\n            int x = pts[i].x;\n            int y = pts[i].y;\n\n            for (int x0 : {x - 1, x}) {\n                if (x0 < 0 || x0 + 1 > COORD_MAX) continue;\n                for (int y0 : {y - 1, y}) {\n                    if (y0 < 0 || y0 + 1 > COORD_MAX) continue;\n\n                    int d = 0;\n                    d += getw(x0, y0);\n                    d += getw(x0 + 1, y0);\n                    d += getw(x0, y0 + 1);\n                    d += getw(x0 + 1, y0 + 1);\n\n                    if (d > best) {\n                        best = d;\n                        poly = {\n                            {x0, y0},\n                            {x0 + 1, y0},\n                            {x0 + 1, y0 + 1},\n                            {x0, y0 + 1}\n                        };\n                    }\n                }\n            }\n        }\n\n        if (poly.empty()) {\n            poly = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n            best = 0;\n        }\n        return {poly, best};\n    }\n\n    // ---------- candidate pipeline ----------\n    void consider_candidate(vector<char> sel) {\n        if (time_over()) return;\n\n        bool any = false;\n        for (char b : sel) if (b) { any = true; break; }\n        if (!any) return;\n\n        enforce_single_component(sel);\n        resolve_diagonal_crosses(sel);\n        refine(sel);\n        fill_holes(sel);\n        resolve_diagonal_crosses(sel);\n        enforce_single_component(sel);\n\n        auto sp0 = score_perim(sel);\n        int sc0 = sp0.first, per0 = sp0.second;\n        if (per0 <= 0 || per0 > PmaxUnits) return;\n\n        if (remaining() > 0.060 && C <= 50000 &&\n            ((int)cands.size() < KEEP_CANDS || sc0 >= worst_kept_diff() - 80)) {\n            exact_polish(sel);\n            fill_holes(sel);\n            resolve_diagonal_crosses(sel);\n            enforce_single_component(sel);\n        }\n\n        auto sp = score_perim(sel);\n        int per = sp.second;\n        if (per <= 0 || per > PmaxUnits) return;\n        if (remaining() < 0.010) return;\n\n        int diff = exact_diff(sel);\n        if ((int)cands.size() >= KEEP_CANDS && diff < worst_kept_diff() - 3) return;\n\n        auto poly = cells_to_polygon(sel);\n        if (poly.empty()) return;\n        add_poly_candidate(diff, move(poly));\n    }\n\n    void run_search_on_current_grid(bool mainMode, bool allowCut, bool quickMode) {\n        if (time_over()) return;\n\n        vector<int> seeds;\n        if (remaining() > 0.05) seeds = top_seed_cells(mainMode ? 5 : 4);\n\n        int bestCell = 0;\n        for (int i = 1; i < C; i++) if (raw[i] > raw[bestCell]) bestCell = i;\n        if (raw[bestCell] > 0) {\n            vector<char> sel(C, 0);\n            sel[bestCell] = 1;\n            consider_candidate(move(sel));\n        }\n\n        // single-cell seeds\n        if (!seeds.empty()) {\n            int lim = min((int)seeds.size(), mainMode ? 3 : 2);\n            for (int i = 0; i < lim; i++) {\n                if (remaining() < 0.03) break;\n                if (raw[seeds[i]] <= 0) continue;\n                vector<char> sel(C, 0);\n                sel[seeds[i]] = 1;\n                consider_candidate(move(sel));\n            }\n        }\n\n        // raw-threshold dense components\n        {\n            vector<int> ths;\n            if (quickMode) ths = {2};\n            else ths = (mainMode ? vector<int>{3, 2} : vector<int>{2});\n\n            for (int th : ths) {\n                if (remaining() < 0.05) break;\n\n                vector<char> hi(C, 0);\n                bool any = false;\n                for (int v = 0; v < C; v++) {\n                    if (raw[v] >= th) {\n                        hi[v] = 1;\n                        any = true;\n                    }\n                }\n                if (!any) continue;\n\n                auto comps = top_components(hi, mainMode ? 3 : 2);\n                for (auto &cp : comps) {\n                    if (remaining() < 0.03) break;\n                    vector<char> sel(C, 0);\n                    for (int v : cp.cells) sel[v] = 1;\n                    consider_candidate(move(sel));\n                }\n\n                if ((int)comps.size() >= 2 && remaining() > 0.10) {\n                    int d = bbox_dist(comps[0], comps[1]);\n                    if (d <= max(3, PmaxUnits / 4)) {\n                        vector<char> merged;\n                        bool ok = false;\n                        if (remaining() > 0.14) ok = connect_components_weighted(comps[0], comps[1], merged);\n                        if (!ok) ok = connect_components_fast(comps[0], comps[1], merged);\n                        if (ok) consider_candidate(move(merged));\n                    }\n                }\n            }\n        }\n\n        // local blocks around seeds\n        if (!seeds.empty() && remaining() > 0.06) {\n            int lim = min((int)seeds.size(), mainMode ? 3 : 2);\n            for (int i = 0; i < lim; i++) {\n                if (remaining() < 0.03) break;\n                int s = seeds[i];\n                int cx = s % W, cy = s / W;\n\n                int rad = 1;\n                int x1 = max(0, cx - rad), x2 = min(W - 1, cx + rad);\n                int y1 = max(0, cy - rad), y2 = min(H - 1, cy + rad);\n\n                vector<char> sel(C, 0);\n                for (int y = y1; y <= y2; y++) {\n                    for (int x = x1; x <= x2; x++) sel[id(x, y)] = 1;\n                }\n                consider_candidate(move(sel));\n\n                if (mainMode && !quickMode && i == 0 && remaining() > 0.08) {\n                    int r2 = 2;\n                    int xx1 = max(0, cx - r2), xx2 = min(W - 1, cx + r2);\n                    int yy1 = max(0, cy - r2), yy2 = min(H - 1, cy + r2);\n\n                    vector<char> sel2(C, 0);\n                    for (int y = yy1; y <= yy2; y++) {\n                        for (int x = xx1; x <= xx2; x++) sel2[id(x, y)] = 1;\n                    }\n                    consider_candidate(move(sel2));\n                }\n            }\n        }\n\n        // seed growth\n        if (!seeds.empty() && remaining() > (mainMode ? 0.10 : 0.07)) {\n            int lim = min((int)seeds.size(), mainMode ? 4 : 3);\n            if (quickMode) lim = min(lim, 2);\n\n            for (int i = 0; i < lim; i++) {\n                if (remaining() < 0.04) break;\n                auto a = grow_from_seed(seeds[i], 0);\n                consider_candidate(move(a));\n\n                bool doMode1 = false;\n                if (!quickMode) {\n                    if (mainMode && remaining() > 0.13) doMode1 = true;\n                    if (!mainMode && i == 0 && remaining() > 0.10) doMode1 = true;\n                } else {\n                    if (i == 0 && remaining() > 0.11) doMode1 = true;\n                }\n\n                if (doMode1) {\n                    auto b = grow_from_seed(seeds[i], 1);\n                    consider_candidate(move(b));\n                }\n            }\n        }\n\n        if (quickMode) return;\n\n        // graph-cut family\n        if (allowCut && remaining() > 0.10) {\n            vector<pair<int, int>> params;\n            if (mainMode && STEP == 500) {\n                params = {\n                    {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0},\n                    {0, 4}, {1, 8}, {2, 12}, {0, 10}, {2, 16}\n                };\n                if (remaining() > 0.48) params.push_back({1, 14});\n            } else if (STEP == 625) {\n                params = {\n                    {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0},\n                    {0, 5}, {1, 9}\n                };\n                if (remaining() > 0.36) params.push_back({2, 12});\n            } else { // 1000\n                params = {\n                    {0, 0}, {1, 0}, {2, 0}, {3, 0},\n                    {0, 4}\n                };\n            }\n\n            int maxR = 0;\n            for (auto [r, _] : params) maxR = max(maxR, r);\n            vector<vector<int>> profits(maxR + 1);\n            vector<char> built(maxR + 1, 0);\n\n            for (auto [r, lam] : params) {\n                if (time_over()) break;\n                if (lam > 0) {\n                    double need = (STEP <= 500 ? 0.11 : (STEP <= 625 ? 0.08 : 0.06));\n                    if (remaining() < need) break;\n                } else {\n                    if (remaining() < 0.02) break;\n                }\n\n                if (!built[r]) {\n                    profits[r] = build_profit(r);\n                    built[r] = 1;\n                }\n\n                auto sel = segment_cut(profits[r], lam);\n                auto comps = top_components(sel, mainMode ? 4 : 3);\n\n                int take = min((mainMode ? 3 : 2), (int)comps.size());\n                for (int i = 0; i < take; i++) {\n                    if (remaining() < 0.03) break;\n                    vector<char> cs(C, 0);\n                    for (int v : comps[i].cells) cs[v] = 1;\n                    consider_candidate(move(cs));\n                }\n\n                // lam=0 thresholded selections\n                if (lam == 0 && mainMode && r >= 2 && remaining() > 0.05) {\n                    vector<int> ths = {20, 40};\n                    if (r >= 3) ths.push_back(60);\n\n                    for (int thr : ths) {\n                        vector<char> s2(C, 0);\n                        bool any = false;\n                        for (int v = 0; v < C; v++) {\n                            if (profits[r][v] > thr) {\n                                s2[v] = 1;\n                                any = true;\n                            }\n                        }\n                        if (!any) continue;\n\n                        auto c2 = top_components(s2, 2);\n                        for (auto &cp : c2) {\n                            if (remaining() < 0.03) break;\n                            vector<char> cs2(C, 0);\n                            for (int v : cp.cells) cs2[v] = 1;\n                            consider_candidate(move(cs2));\n                        }\n                    }\n                }\n\n                auto try_merge = [&](const Component& A, const Component& B) {\n                    vector<char> merged;\n                    bool ok = false;\n                    if (remaining() > (mainMode ? 0.16 : 0.12)) ok = connect_components_weighted(A, B, merged);\n                    if (!ok) ok = connect_components_fast(A, B, merged);\n                    if (ok) consider_candidate(move(merged));\n                };\n\n                if ((int)comps.size() >= 2 && remaining() > (mainMode ? 0.11 : 0.09)) {\n                    bool tryJoin = (lam == 0 || lam >= 8);\n                    if (tryJoin) {\n                        int d = bbox_dist(comps[0], comps[1]);\n                        int lim = max(3, PmaxUnits / (mainMode ? 3 : 4));\n                        if (d <= lim) try_merge(comps[0], comps[1]);\n                    }\n                }\n\n                if (mainMode && (int)comps.size() >= 3 && lam >= 12 && remaining() > 0.14) {\n                    int d = bbox_dist(comps[0], comps[2]);\n                    if (d <= max(4, PmaxUnits / 4)) try_merge(comps[0], comps[2]);\n                }\n            }\n        }\n\n        // rectangles\n        if (remaining() > (mainMode ? 0.11 : 0.08)) {\n            int K = mainMode ? (remaining() > 0.45 ? 7 : 6) : 3;\n            double br = mainMode ? 0.10 : 0.07;\n            auto rects = best_rectangles(K, br);\n\n            for (auto &rc : rects) {\n                if (remaining() < 0.035) break;\n\n                vector<char> sel(C, 0);\n                for (int y = rc.y1; y <= rc.y2; y++) {\n                    for (int x = rc.x1; x <= rc.x2; x++) sel[id(x, y)] = 1;\n                }\n                consider_candidate(move(sel));\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n\n        // main grid first\n        build_grid(500);\n\n        auto [tinyPoly, tinyDiff] = best_tiny_fallback();\n\n        int bestCell = (int)(max_element(raw.begin(), raw.end()) - raw.begin());\n        auto cellPoly = cell_rect_poly(bestCell);\n        int cellDiff = rect_diff(cellPoly[0].x, cellPoly[1].x, cellPoly[0].y, cellPoly[2].y);\n\n        add_poly_candidate(tinyDiff, tinyPoly);\n        add_poly_candidate(cellDiff, cellPoly);\n\n        run_search_on_current_grid(true, true, false);\n\n        if (remaining() > 0.30) {\n            build_grid(625);\n            run_search_on_current_grid(false, true, false);\n        }\n\n        if (remaining() > 0.22) {\n            build_grid(400); // fine quick pass (no maxflow)\n            run_search_on_current_grid(false, false, true);\n        }\n\n        if (remaining() > 0.14) {\n            build_grid(1000);\n            bool cut1000 = (remaining() > 0.22);\n            run_search_on_current_grid(false, cut1000, false);\n        }\n\n        // final choose by true polygon score\n        vector<Point> ans = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n        int bestTrue = -1e9;\n\n        auto try_poly = [&](const vector<Point>& poly) {\n            if (!basic_valid(poly)) return;\n            int td = exact_diff_polygon(poly);\n            if (td <= bestTrue) return;\n            if (!final_valid(poly)) return;\n            bestTrue = td;\n            ans = poly;\n        };\n\n        try_poly(tinyPoly);\n        try_poly(cellPoly);\n        for (auto &cd : cands) try_poly(cd.poly);\n\n        if (!final_valid(ans)) {\n            if (final_valid(tinyPoly)) ans = tinyPoly;\n            else ans = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n        }\n\n        cout << ans.size() << '\\n';\n        for (auto &p : ans) {\n            cout << p.x << ' ' << p.y << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconstexpr int MAXN = 105;\nconstexpr ll INF64 = (1LL << 60);\n\nconstexpr ll TRUE_MIN = 10000;\nconstexpr ll TRUE_MAX = 100000;\nconstexpr ll L_MAX = 50000;\n\nconstexpr double INV_SQRT2 = 0.70710678118654752440;\nconstexpr double INV_SQRT_2PI = 0.39894228040143267794;\n\nstatic inline uint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstruct FastRNG {\n    uint64_t x;\n    bool has_spare = false;\n    double spare = 0.0;\n\n    explicit FastRNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next_u64() {\n        return splitmix64(x += 0x9e3779b97f4a7c15ULL);\n    }\n\n    double uniform01() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next_u64() % (uint64_t)(r - l + 1));\n    }\n\n    double normal01() {\n        if (has_spare) {\n            has_spare = false;\n            return spare;\n        }\n        double u, v, s;\n        do {\n            u = uniform01() * 2.0 - 1.0;\n            v = uniform01() * 2.0 - 1.0;\n            s = u * u + v * v;\n        } while (s >= 1.0 || s == 0.0);\n        double m = sqrt(-2.0 * log(s) / s);\n        spare = v * m;\n        has_spare = true;\n        return u * m;\n    }\n};\n\ninline ll clamp_ll(ll v, ll lo, ll hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\ninline bool overlap(ll l1, ll r1, ll l2, ll r2) {\n    return (l1 < r2) && (l2 < r1);\n}\n\ninline double normal_pdf(double z) {\n    return INV_SQRT_2PI * exp(-0.5 * z * z);\n}\n\ninline double normal_cdf(double z) {\n    return 0.5 * erfc(-z * INV_SQRT2);\n}\n\n// mean of N(mu, sd^2) truncated into [a,b]\ndouble trunc_normal_mean(double mu, double sd, double a, double b) {\n    if (sd <= 1e-12) return min(max(mu, a), b);\n    double alpha = (a - mu) / sd;\n    double beta  = (b - mu) / sd;\n    double Za = normal_cdf(alpha);\n    double Zb = normal_cdf(beta);\n    double Z = Zb - Za;\n    if (Z < 1e-14) return min(max(mu, a), b);\n    double m = mu + sd * (normal_pdf(alpha) - normal_pdf(beta)) / Z;\n    if (m < a) m = a;\n    if (m > b) m = b;\n    return m;\n}\n\nstruct Operation {\n    uint8_t r = 0; // rotate\n    uint8_t d = 0; // 0:U, 1:L\n    int b = -1;\n};\n\nstruct GreedyParam {\n    double gap_w = 0.35;\n    double bal_w = 0.006;\n    double noise_w = 0.0;\n};\n\nstruct BeamParam {\n    int beam_width = 32;\n    int keep_leaves = 12;\n    double gap_w = 0.35;\n    double bal_w = 0.006;\n    double noise_w = 0.0;\n};\n\nstruct Scenario {\n    vector<ll> w, h;\n};\n\nstruct Candidate {\n    vector<Operation> ops;\n    vector<ll> predW, predH, predS; // per scenario\n    double avg = 1e100;\n    double spread = 0.0;\n    uint64_t hash = 0;\n};\n\ndouble lower_bound_wh(ll curW, ll curH, double totalA, double sqrtA) {\n    double w = (double)curW, h = (double)curH;\n    if (w * h >= totalA) return w + h;\n\n    double c1 = w + max(h, totalA / max(1.0, w));\n    double c2 = h + max(w, totalA / max(1.0, h));\n    double c3 = 1e100;\n    if (w <= sqrtA && h <= sqrtA) c3 = 2.0 * sqrtA;\n    return min(c1, min(c2, c3));\n}\n\npair<ll, ll> simulate_layout(\n    const vector<ll>& baseW, const vector<ll>& baseH, const vector<Operation>& ops\n) {\n    int N = (int)ops.size();\n    ll x[MAXN] = {}, y[MAXN] = {}, w[MAXN] = {}, h[MAXN] = {};\n    ll BW = 0, BH = 0;\n\n    for (int i = 0; i < N; i++) {\n        const auto& op = ops[i];\n        ll wi = op.r ? baseH[i] : baseW[i];\n        ll hi = op.r ? baseW[i] : baseH[i];\n\n        ll xi = 0, yi = 0;\n        if (op.d == 0) { // U\n            xi = (op.b == -1) ? 0 : (x[op.b] + w[op.b]);\n            ll xr = xi + wi;\n            yi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(xi, xr, x[j], x[j] + w[j])) yi = max(yi, y[j] + h[j]);\n            }\n        } else { // L\n            yi = (op.b == -1) ? 0 : (y[op.b] + h[op.b]);\n            ll yb = yi + hi;\n            xi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(yi, yb, y[j], y[j] + h[j])) xi = max(xi, x[j] + w[j]);\n            }\n        }\n\n        x[i] = xi; y[i] = yi; w[i] = wi; h[i] = hi;\n        BW = max(BW, xi + wi);\n        BH = max(BH, yi + hi);\n    }\n\n    return {BW, BH};\n}\n\ninline ll score_on_base(const vector<ll>& w, const vector<ll>& h, const vector<Operation>& ops) {\n    auto [W, H] = simulate_layout(w, h, ops);\n    return W + H;\n}\n\nvector<Operation> build_linear_chain(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal, bool minimize_cross\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (minimize_cross) {\n            if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n            else r = (h[i] < w[i]) ? 1 : 0;\n        }\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 0 : 1), (i == 0 ? -1 : i - 1)};\n    }\n    return ops;\n}\n\nvector<Operation> build_single_stack(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal\n) {\n    // horizontal row: all L,-1 ; vertical col: all U,-1\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n        else r = (h[i] < w[i]) ? 1 : 0;\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 1 : 0), -1};\n    }\n    return ops;\n}\n\nvector<Operation> build_greedy(\n    const vector<ll>& baseW, const vector<ll>& baseH, const GreedyParam& param, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n    vector<Operation> ops(N);\n\n    ll x[MAXN] = {}, y[MAXN] = {}, w[MAXN] = {}, h[MAXN] = {};\n    ll curW = 0, curH = 0;\n    double usedA = 0.0;\n\n    double totalA = 0.0;\n    for (int i = 0; i < N; i++) totalA += (double)baseW[i] * (double)baseH[i];\n    double sqrtA = sqrt(max(1.0, totalA));\n    double norm = sqrtA + 1.0;\n\n    for (int i = 0; i < N; i++) {\n        double bestScore = 1e300;\n        ll bestPerim = INF64;\n        Operation bestOp{};\n        ll bestX = 0, bestY = 0, bestWi = 0, bestHi = 0, nextW = 0, nextH = 0;\n\n        for (int rot = 0; rot < 2; rot++) {\n            ll wi = rot ? baseH[i] : baseW[i];\n            ll hi = rot ? baseW[i] : baseH[i];\n\n            for (int dir = 0; dir < 2; dir++) {\n                for (int b = -1; b < i; b++) {\n                    ll xi = 0, yi = 0;\n\n                    if (dir == 0) { // U\n                        xi = (b == -1) ? 0 : (x[b] + w[b]);\n                        ll xr = xi + wi;\n                        yi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(xi, xr, x[j], x[j] + w[j])) yi = max(yi, y[j] + h[j]);\n                        }\n                    } else { // L\n                        yi = (b == -1) ? 0 : (y[b] + h[b]);\n                        ll yb = yi + hi;\n                        xi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(yi, yb, y[j], y[j] + h[j])) xi = max(xi, x[j] + w[j]);\n                        }\n                    }\n\n                    ll nW = max(curW, xi + wi);\n                    ll nH = max(curH, yi + hi);\n\n                    double usedA2 = usedA + (double)wi * (double)hi;\n                    double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                    double gap = (double)nW * (double)nH - usedA2;\n                    if (gap < 0) gap = 0;\n\n                    double sc = lb\n                              + param.gap_w * (gap / norm)\n                              + param.bal_w * (double)llabs(nW - nH);\n                    if (param.noise_w > 0.0) sc += param.noise_w * rng.uniform01();\n\n                    ll perim = nW + nH;\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) <= 1e-12 && perim < bestPerim)) {\n                        bestScore = sc;\n                        bestPerim = perim;\n                        bestOp = Operation{(uint8_t)rot, (uint8_t)dir, b};\n                        bestX = xi; bestY = yi; bestWi = wi; bestHi = hi;\n                        nextW = nW; nextH = nH;\n                    }\n                }\n            }\n        }\n\n        ops[i] = bestOp;\n        x[i] = bestX; y[i] = bestY; w[i] = bestWi; h[i] = bestHi;\n        curW = nextW; curH = nextH;\n        usedA += (double)bestWi * (double)bestHi;\n    }\n\n    return ops;\n}\n\nuint64_t hash_ops(const vector<Operation>& ops) {\n    uint64_t h = 0xcbf29ce484222325ULL;\n    for (size_t i = 0; i < ops.size(); i++) {\n        uint64_t v = (uint64_t)(ops[i].r + 1);\n        v = v * 3ULL + (uint64_t)(ops[i].d + 1);\n        v = v * 1315423911ULL + (uint64_t)(ops[i].b + 3);\n        h ^= splitmix64(v + 0x9e3779b97f4a7c15ULL * (i + 1));\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvector<vector<Operation>> beam_generate(\n    const vector<ll>& baseW, const vector<ll>& baseH, const BeamParam& prm, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n\n    struct State {\n        array<ll, MAXN> x{}, y{}, w{}, h{};\n        array<Operation, MAXN> ops{};\n        ll W = 0, H = 0;\n        double usedA = 0.0;\n        double eval = 0.0;\n    };\n    struct Child {\n        double eval;\n        int parent;\n        Operation op;\n        ll x, y, w, h, W, H;\n        double usedA;\n    };\n\n    double totalA = 0.0;\n    for (int i = 0; i < N; i++) totalA += (double)baseW[i] * (double)baseH[i];\n    double sqrtA = sqrt(max(1.0, totalA));\n    double norm = sqrtA + 1.0;\n\n    vector<State> beam(1);\n\n    auto cmpChild = [](const Child& a, const Child& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        ll pa = a.W + a.H, pb = b.W + b.H;\n        return pa < pb;\n    };\n\n    for (int i = 0; i < N; i++) {\n        vector<Child> children;\n        children.reserve((int)beam.size() * 4 * (i + 1));\n\n        for (int si = 0; si < (int)beam.size(); si++) {\n            const State& st = beam[si];\n\n            for (int rot = 0; rot < 2; rot++) {\n                ll wi = rot ? baseH[i] : baseW[i];\n                ll hi = rot ? baseW[i] : baseH[i];\n\n                for (int dir = 0; dir < 2; dir++) {\n                    for (int b = -1; b < i; b++) {\n                        ll xi = 0, yi = 0;\n\n                        if (dir == 0) { // U\n                            xi = (b == -1) ? 0 : (st.x[b] + st.w[b]);\n                            ll xr = xi + wi;\n                            yi = 0;\n                            for (int j = 0; j < i; j++) {\n                                if (overlap(xi, xr, st.x[j], st.x[j] + st.w[j])) yi = max(yi, st.y[j] + st.h[j]);\n                            }\n                        } else { // L\n                            yi = (b == -1) ? 0 : (st.y[b] + st.h[b]);\n                            ll yb = yi + hi;\n                            xi = 0;\n                            for (int j = 0; j < i; j++) {\n                                if (overlap(yi, yb, st.y[j], st.y[j] + st.h[j])) xi = max(xi, st.x[j] + st.w[j]);\n                            }\n                        }\n\n                        ll nW = max(st.W, xi + wi);\n                        ll nH = max(st.H, yi + hi);\n\n                        double usedA2 = st.usedA + (double)wi * (double)hi;\n                        double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                        double gap = (double)nW * (double)nH - usedA2;\n                        if (gap < 0) gap = 0;\n\n                        double sc = lb\n                                  + prm.gap_w * (gap / norm)\n                                  + prm.bal_w * (double)llabs(nW - nH);\n                        if (prm.noise_w > 0.0) sc += prm.noise_w * rng.uniform01();\n\n                        children.push_back(Child{\n                            sc, si, Operation{(uint8_t)rot, (uint8_t)dir, b},\n                            xi, yi, wi, hi, nW, nH, usedA2\n                        });\n                    }\n                }\n            }\n        }\n\n        if (children.empty()) break;\n        int B = min(prm.beam_width, (int)children.size());\n        int limit = min((int)children.size(), max(B, B * 3));\n\n        if ((int)children.size() > limit) {\n            nth_element(children.begin(), children.begin() + limit, children.end(), cmpChild);\n        }\n        sort(children.begin(), children.begin() + limit, cmpChild);\n\n        vector<State> next;\n        next.reserve(B);\n\n        // parent diversity\n        vector<int> parentCnt(beam.size(), 0);\n        int parentCap = 3;\n        vector<char> used(limit, 0);\n\n        for (int k = 0; k < limit && (int)next.size() < B; k++) {\n            int p = children[k].parent;\n            if (parentCnt[p] >= parentCap) continue;\n            const Child& ch = children[k];\n            State ns = beam[ch.parent];\n            ns.ops[i] = ch.op;\n            ns.x[i] = ch.x; ns.y[i] = ch.y; ns.w[i] = ch.w; ns.h[i] = ch.h;\n            ns.W = ch.W; ns.H = ch.H; ns.usedA = ch.usedA; ns.eval = ch.eval;\n            next.push_back(std::move(ns));\n            parentCnt[p]++;\n            used[k] = 1;\n        }\n        for (int k = 0; k < limit && (int)next.size() < B; k++) {\n            if (used[k]) continue;\n            const Child& ch = children[k];\n            State ns = beam[ch.parent];\n            ns.ops[i] = ch.op;\n            ns.x[i] = ch.x; ns.y[i] = ch.y; ns.w[i] = ch.w; ns.h[i] = ch.h;\n            ns.W = ch.W; ns.H = ch.H; ns.usedA = ch.usedA; ns.eval = ch.eval;\n            next.push_back(std::move(ns));\n        }\n\n        beam.swap(next);\n        if (beam.empty()) break;\n    }\n\n    sort(beam.begin(), beam.end(), [](const State& a, const State& b) {\n        ll pa = a.W + a.H, pb = b.W + b.H;\n        if (pa != pb) return pa < pb;\n        return a.eval < b.eval;\n    });\n\n    int M = min(prm.keep_leaves, (int)beam.size());\n    vector<vector<Operation>> out;\n    out.reserve(M);\n    for (int k = 0; k < M; k++) {\n        vector<Operation> ops(N);\n        for (int i = 0; i < N; i++) ops[i] = beam[k].ops[i];\n        out.push_back(std::move(ops));\n    }\n    return out;\n}\n\nvoid oriented_dims(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot,\n    vector<ll>& ow, vector<ll>& oh\n) {\n    int N = (int)bw.size();\n    ow.resize(N);\n    oh.resize(N);\n    for (int i = 0; i < N; i++) {\n        if (!rot[i]) { ow[i] = bw[i]; oh[i] = bh[i]; }\n        else { ow[i] = bh[i]; oh[i] = bw[i]; }\n    }\n}\n\nvector<int> balanced_cuts_from_prefix(const vector<ll>& pref, int K) {\n    int N = (int)pref.size() - 1;\n    K = max(1, min(K, N));\n\n    vector<int> cuts;\n    cuts.reserve(K + 1);\n    cuts.push_back(0);\n    int prev = 0;\n\n    for (int t = 1; t < K; t++) {\n        int remain = K - t;\n        int lo = prev + 1;\n        int hi = N - remain;\n        if (lo > hi) lo = hi;\n\n        long double target = (long double)pref[N] * (long double)t / (long double)K;\n        int best = lo;\n        long double bestd = fabsl((long double)pref[lo] - target);\n\n        for (int c = lo + 1; c <= hi; c++) {\n            long double d = fabsl((long double)pref[c] - target);\n            if (d < bestd) {\n                bestd = d;\n                best = c;\n            }\n        }\n        cuts.push_back(best);\n        prev = best;\n    }\n    cuts.push_back(N);\n    return cuts;\n}\n\nvector<Operation> build_row_ops_from_cuts(\n    const vector<uint8_t>& rot, const vector<ll>& oh, const vector<int>& cuts\n) {\n    int N = (int)rot.size();\n    vector<Operation> ops(N);\n\n    int prevRef = -1;\n    for (int s = 0; s + 1 < (int)cuts.size(); s++) {\n        int l = cuts[s], r = cuts[s + 1];\n        int b = (s == 0 ? -1 : prevRef);\n\n        int ref = l;\n        ll mxh = oh[l];\n        for (int i = l; i < r; i++) {\n            ops[i] = Operation{rot[i], (uint8_t)1, b}; // all L at same row base\n            if (oh[i] > mxh) {\n                mxh = oh[i];\n                ref = i;\n            }\n        }\n        prevRef = ref;\n    }\n    return ops;\n}\n\nvector<Operation> build_col_ops_from_cuts(\n    const vector<uint8_t>& rot, const vector<ll>& ow, const vector<int>& cuts\n) {\n    int N = (int)rot.size();\n    vector<Operation> ops(N);\n\n    int prevRef = -1;\n    for (int s = 0; s + 1 < (int)cuts.size(); s++) {\n        int l = cuts[s], r = cuts[s + 1];\n        int b = (s == 0 ? -1 : prevRef);\n\n        int ref = l;\n        ll mxw = ow[l];\n        for (int i = l; i < r; i++) {\n            ops[i] = Operation{rot[i], (uint8_t)0, b}; // all U at same col base\n            if (ow[i] > mxw) {\n                mxw = ow[i];\n                ref = i;\n            }\n        }\n        prevRef = ref;\n    }\n    return ops;\n}\n\n// Exact contiguous-row shelf optimization for fixed rotations.\nvector<Operation> build_row_shelf_opt(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot\n) {\n    int N = (int)bw.size();\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    static ll segW[MAXN][MAXN], segH[MAXN][MAXN];\n    vector<ll> prefW(N + 1, 0);\n    for (int i = 0; i < N; i++) prefW[i + 1] = prefW[i] + ow[i];\n\n    vector<ll> cand;\n    cand.reserve(N * (N + 1) / 2);\n\n    for (int l = 0; l < N; l++) {\n        ll mxh = 0;\n        for (int r = l + 1; r <= N; r++) {\n            mxh = max(mxh, oh[r - 1]);\n            segW[l][r] = prefW[r] - prefW[l];\n            segH[l][r] = mxh;\n            cand.push_back(segW[l][r]);\n        }\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    ll bestObj = INF64;\n    vector<int> bestPrev(N + 1, -1), prev(N + 1, -1);\n    ll dp[MAXN];\n\n    for (ll Wlim : cand) {\n        for (int i = 0; i <= N; i++) dp[i] = INF64, prev[i] = -1;\n        dp[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            ll best = INF64;\n            int bi = -1;\n            for (int i = j - 1; i >= 0; i--) {\n                if (segW[i][j] > Wlim) break;\n                if (dp[i] == INF64) continue;\n                ll val = dp[i] + segH[i][j];\n                if (val < best) {\n                    best = val;\n                    bi = i;\n                }\n            }\n            dp[j] = best;\n            prev[j] = bi;\n        }\n\n        if (dp[N] == INF64) continue;\n        ll obj = Wlim + dp[N];\n        if (obj < bestObj) {\n            bestObj = obj;\n            bestPrev = prev;\n        }\n    }\n\n    if (bestObj >= INF64 / 2) return {};\n\n    vector<int> cuts_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = bestPrev[cur];\n        if (p < 0) return {};\n        cuts_rev.push_back(cur);\n        cur = p;\n    }\n    cuts_rev.push_back(0);\n    reverse(cuts_rev.begin(), cuts_rev.end());\n\n    return build_row_ops_from_cuts(rot, oh, cuts_rev);\n}\n\n// Exact contiguous-column shelf optimization for fixed rotations.\nvector<Operation> build_col_shelf_opt(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot\n) {\n    int N = (int)bw.size();\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    static ll segH[MAXN][MAXN], segW[MAXN][MAXN];\n    vector<ll> prefH(N + 1, 0);\n    for (int i = 0; i < N; i++) prefH[i + 1] = prefH[i] + oh[i];\n\n    vector<ll> cand;\n    cand.reserve(N * (N + 1) / 2);\n\n    for (int l = 0; l < N; l++) {\n        ll mxw = 0;\n        for (int r = l + 1; r <= N; r++) {\n            mxw = max(mxw, ow[r - 1]);\n            segH[l][r] = prefH[r] - prefH[l];\n            segW[l][r] = mxw;\n            cand.push_back(segH[l][r]);\n        }\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    ll bestObj = INF64;\n    vector<int> bestPrev(N + 1, -1), prev(N + 1, -1);\n    ll dp[MAXN];\n\n    for (ll Hlim : cand) {\n        for (int i = 0; i <= N; i++) dp[i] = INF64, prev[i] = -1;\n        dp[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            ll best = INF64;\n            int bi = -1;\n            for (int i = j - 1; i >= 0; i--) {\n                if (segH[i][j] > Hlim) break;\n                if (dp[i] == INF64) continue;\n                ll val = dp[i] + segW[i][j];\n                if (val < best) {\n                    best = val;\n                    bi = i;\n                }\n            }\n            dp[j] = best;\n            prev[j] = bi;\n        }\n\n        if (dp[N] == INF64) continue;\n        ll obj = Hlim + dp[N];\n        if (obj < bestObj) {\n            bestObj = obj;\n            bestPrev = prev;\n        }\n    }\n\n    if (bestObj >= INF64 / 2) return {};\n\n    vector<int> cuts_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = bestPrev[cur];\n        if (p < 0) return {};\n        cuts_rev.push_back(cur);\n        cur = p;\n    }\n    cuts_rev.push_back(0);\n    reverse(cuts_rev.begin(), cuts_rev.end());\n\n    return build_col_ops_from_cuts(rot, ow, cuts_rev);\n}\n\nvector<Operation> build_row_shelf_greedyK(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot, int K\n) {\n    int N = (int)bw.size();\n    K = max(1, min(K, N));\n\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    vector<ll> prefW(N + 1, 0);\n    for (int i = 0; i < N; i++) prefW[i + 1] = prefW[i] + ow[i];\n\n    auto cuts = balanced_cuts_from_prefix(prefW, K);\n    return build_row_ops_from_cuts(rot, oh, cuts);\n}\n\nvector<Operation> build_col_shelf_greedyK(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot, int K\n) {\n    int N = (int)bw.size();\n    K = max(1, min(K, N));\n\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    vector<ll> prefH(N + 1, 0);\n    for (int i = 0; i < N; i++) prefH[i + 1] = prefH[i] + oh[i];\n\n    auto cuts = balanced_cuts_from_prefix(prefH, K);\n    return build_col_ops_from_cuts(rot, ow, cuts);\n}\n\nOperation mutate_op(\n    const Operation& old, int i,\n    const vector<ll>& bw, const vector<ll>& bh, FastRNG& rng\n) {\n    Operation nw = old;\n    int mode = rng.randint(0, 7);\n\n    if (mode == 0) nw.r ^= 1;\n    else if (mode == 1) nw.d ^= 1;\n    else if (mode == 2) nw.b = (i == 0 ? -1 : rng.randint(-1, i - 1));\n    else if (mode == 3) { nw.r ^= 1; nw.d ^= 1; }\n    else if (mode == 4) {\n        nw.r = rng.randint(0, 1);\n        nw.d = rng.randint(0, 1);\n        nw.b = (i == 0 ? -1 : rng.randint(-1, i - 1));\n    } else if (mode == 5) {\n        nw.b = (i == 0 ? -1 : (rng.uniform01() < 0.5 ? -1 : i - 1));\n    } else if (mode == 6) {\n        if (nw.d == 0) nw.r = (bh[i] < bw[i]) ? 1 : 0; // U: narrow width\n        else nw.r = (bw[i] < bh[i]) ? 1 : 0;           // L: narrow height\n    } else {\n        if (i > 0) {\n            int nb = old.b + rng.randint(-3, 3);\n            nw.b = max(-1, min(i - 1, nb));\n        } else nw.b = -1;\n        if (rng.uniform01() < 0.35) nw.r ^= 1;\n    }\n\n    if (i == 0) nw.b = -1;\n    else {\n        nw.b = max(-1, min(i - 1, nw.b));\n    }\n    return nw;\n}\n\nvector<Operation> hill_climb(\n    const vector<ll>& bw, const vector<ll>& bh, vector<Operation> ops, int iterations, FastRNG& rng\n) {\n    int N = (int)ops.size();\n    ll cur = score_on_base(bw, bh, ops);\n\n    for (int it = 0; it < iterations; it++) {\n        int i = rng.randint(0, N - 1);\n        Operation old = ops[i];\n        Operation nw = mutate_op(old, i, bw, bh, rng);\n        ops[i] = nw;\n        ll nxt = score_on_base(bw, bh, ops);\n        if (nxt <= cur) cur = nxt;\n        else ops[i] = old;\n    }\n\n    return ops;\n}\n\nvector<Operation> anneal_optimize(\n    const vector<ll>& bw, const vector<ll>& bh, vector<Operation> ops, int iterations, FastRNG& rng\n) {\n    int N = (int)ops.size();\n    ll cur = score_on_base(bw, bh, ops);\n    ll best = cur;\n    vector<Operation> bestOps = ops;\n\n    double T0 = max(1000.0, 0.014 * (double)cur);\n    double T1 = 20.0;\n\n    for (int it = 0; it < iterations; it++) {\n        int i = rng.randint(0, N - 1);\n        Operation old = ops[i];\n        Operation nw = mutate_op(old, i, bw, bh, rng);\n        ops[i] = nw;\n\n        ll nxt = score_on_base(bw, bh, ops);\n        ll diff = nxt - cur;\n\n        double t = (double)it / max(1, iterations - 1);\n        double temp = exp(log(T0) * (1.0 - t) + log(T1) * t);\n\n        bool accept = false;\n        if (diff <= 0) accept = true;\n        else if (rng.uniform01() < exp(-(double)diff / temp)) accept = true;\n\n        if (accept) {\n            cur = nxt;\n            if (cur < best) {\n                best = cur;\n                bestOps = ops;\n            }\n        } else {\n            ops[i] = old;\n        }\n    }\n\n    return bestOps;\n}\n\nvoid compute_predictions(Candidate& c, const vector<Scenario>& scenarios) {\n    int S = (int)scenarios.size();\n    c.predW.resize(S);\n    c.predH.resize(S);\n    c.predS.resize(S);\n\n    long double sum = 0.0L;\n    for (int s = 0; s < S; s++) {\n        auto [W, H] = simulate_layout(scenarios[s].w, scenarios[s].h, c.ops);\n        c.predW[s] = W;\n        c.predH[s] = H;\n        c.predS[s] = W + H;\n        sum += (long double)(W + H);\n    }\n    c.avg = (double)(sum / (long double)S);\n\n    long double sq = 0.0L;\n    for (int s = 0; s < S; s++) {\n        long double d = (long double)c.predS[s] - (long double)c.avg;\n        sq += d * d;\n    }\n    c.spread = sqrt((double)(sq / (long double)max(1, S)));\n}\n\nvoid prune_dominated(vector<Candidate>& pool) {\n    if (pool.empty()) return;\n    int P = (int)pool.size();\n    int S = (int)pool[0].predS.size();\n\n    vector<char> dom(P, 0);\n    for (int i = 0; i < P; i++) {\n        if (dom[i]) continue;\n        for (int j = 0; j < P; j++) {\n            if (i == j) continue;\n\n            bool le = true, lt = false;\n            for (int s = 0; s < S; s++) {\n                if (pool[j].predS[s] > pool[i].predS[s]) {\n                    le = false;\n                    break;\n                }\n                if (pool[j].predS[s] < pool[i].predS[s]) lt = true;\n            }\n            if (le && lt) {\n                dom[i] = 1;\n                break;\n            }\n        }\n    }\n\n    vector<Candidate> keep;\n    keep.reserve(P);\n    for (int i = 0; i < P; i++) if (!dom[i]) keep.push_back(move(pool[i]));\n    pool.swap(keep);\n}\n\nint sample_index(const vector<double>& w, FastRNG& rng) {\n    double r = rng.uniform01();\n    double acc = 0.0;\n    for (int i = 0; i < (int)w.size(); i++) {\n        acc += w[i];\n        if (r <= acc) return i;\n    }\n    return (int)w.size() - 1;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    ll sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n\n    vector<ll> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    seed ^= splitmix64((uint64_t)N * 1000003ULL + (uint64_t)T * 10007ULL + (uint64_t)sigma * 911382323ULL);\n    for (int i = 0; i < N; i++) {\n        seed ^= splitmix64((uint64_t)obsW[i] * 1000003ULL + (uint64_t)obsH[i] + (uint64_t)(i + 1) * 19260817ULL);\n    }\n    FastRNG rng(seed);\n\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    // ===== Denoising: tight and wide models =====\n    long double sumObs = 0.0L;\n    for (int i = 0; i < N; i++) sumObs += (long double)obsW[i] + (long double)obsH[i];\n    double meanObs = (double)(sumObs / (long double)(2 * N));\n\n    ll Lhat = clamp_ll((ll)llround(2.0 * meanObs - (double)TRUE_MAX), TRUE_MIN, L_MAX);\n    ll Ltight = clamp_ll(Lhat - (ll)llround(0.55 * (double)sigma), TRUE_MIN, L_MAX);\n\n    vector<ll> obsCW(N), obsCH(N), baseTW(N), baseTH(N), baseUW(N), baseUH(N);\n    for (int i = 0; i < N; i++) {\n        obsCW[i] = clamp_ll(obsW[i], TRUE_MIN, TRUE_MAX);\n        obsCH[i] = clamp_ll(obsH[i], TRUE_MIN, TRUE_MAX);\n\n        baseTW[i] = (ll)llround(trunc_normal_mean((double)obsW[i], (double)sigma, (double)Ltight, (double)TRUE_MAX));\n        baseTH[i] = (ll)llround(trunc_normal_mean((double)obsH[i], (double)sigma, (double)Ltight, (double)TRUE_MAX));\n        baseTW[i] = clamp_ll(baseTW[i], Ltight, TRUE_MAX);\n        baseTH[i] = clamp_ll(baseTH[i], Ltight, TRUE_MAX);\n\n        baseUW[i] = (ll)llround(trunc_normal_mean((double)obsW[i], (double)sigma, (double)TRUE_MIN, (double)TRUE_MAX));\n        baseUH[i] = (ll)llround(trunc_normal_mean((double)obsH[i], (double)sigma, (double)TRUE_MIN, (double)TRUE_MAX));\n        baseUW[i] = clamp_ll(baseUW[i], TRUE_MIN, TRUE_MAX);\n        baseUH[i] = clamp_ll(baseUH[i], TRUE_MIN, TRUE_MAX);\n    }\n\n    // ===== Scenarios =====\n    int S;\n    if (sigma <= 2500) S = 12;\n    else if (sigma <= 5000) S = 16;\n    else if (sigma <= 8000) S = 20;\n    else S = 24;\n\n    vector<Scenario> scenarios(S);\n    for (int s = 0; s < S; s++) {\n        scenarios[s].w.resize(N);\n        scenarios[s].h.resize(N);\n    }\n\n    int sid = 0;\n    auto add_scenario = [&](const vector<ll>& w, const vector<ll>& h) {\n        if (sid < S) {\n            scenarios[sid].w = w;\n            scenarios[sid].h = h;\n            sid++;\n        }\n    };\n\n    add_scenario(baseTW, baseTH);\n    add_scenario(baseUW, baseUH);\n    add_scenario(obsCW, obsCH);\n\n    ll gshift = (ll)llround(0.35 * (double)sigma);\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseTW[i] + gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseTH[i] + gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseTW[i] - gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseTH[i] - gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseUW[i] + gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseUH[i] + gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseUW[i] - gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseUH[i] - gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n\n    for (int s = sid; s < S; s += 2) {\n        for (int i = 0; i < N; i++) {\n            double zw = rng.normal01();\n            double zh = rng.normal01();\n            ll w1 = clamp_ll((ll)llround((double)obsW[i] + (double)sigma * zw), TRUE_MIN, TRUE_MAX);\n            ll h1 = clamp_ll((ll)llround((double)obsH[i] + (double)sigma * zh), TRUE_MIN, TRUE_MAX);\n            scenarios[s].w[i] = w1;\n            scenarios[s].h[i] = h1;\n\n            if (s + 1 < S) {\n                ll w2 = clamp_ll((ll)llround((double)obsW[i] - (double)sigma * zw), TRUE_MIN, TRUE_MAX);\n                ll h2 = clamp_ll((ll)llround((double)obsH[i] - (double)sigma * zh), TRUE_MIN, TRUE_MAX);\n                scenarios[s + 1].w[i] = w2;\n                scenarios[s + 1].h[i] = h2;\n            }\n        }\n    }\n\n    // ===== Candidate generation =====\n    const int Pcap = 320;\n    int Ptarget = min(240, max(100, T + 80));\n\n    vector<Candidate> pool;\n    pool.reserve(Pcap + 16);\n    unordered_set<uint64_t> seen;\n    seen.reserve((Pcap + 16) * 4);\n\n    auto add_candidate = [&](vector<Operation>&& ops) -> bool {\n        if ((int)ops.size() != N) return false;\n        if ((int)pool.size() >= Pcap) return false;\n        uint64_t h = hash_ops(ops);\n        if (!seen.insert(h).second) return false;\n        Candidate c;\n        c.ops = move(ops);\n        c.hash = h;\n        pool.push_back(move(c));\n        return true;\n    };\n\n    // baseline\n    add_candidate(build_linear_chain(baseTW, baseTH, true, true));\n    add_candidate(build_linear_chain(baseTW, baseTH, false, true));\n    add_candidate(build_single_stack(baseTW, baseTH, true));\n    add_candidate(build_single_stack(baseTW, baseTH, false));\n    add_candidate(build_linear_chain(baseTW, baseTH, true, false));\n    add_candidate(build_linear_chain(baseTW, baseTH, false, false));\n    add_candidate(build_linear_chain(baseUW, baseUH, true, true));\n    add_candidate(build_linear_chain(baseUW, baseUH, false, true));\n\n    // shelf candidates\n    vector<uint8_t> rotMinH(N), rotMinW(N);\n    for (int i = 0; i < N; i++) {\n        rotMinH[i] = (baseTW[i] < baseTH[i]) ? 1 : 0;\n        rotMinW[i] = (baseTH[i] < baseTW[i]) ? 1 : 0;\n    }\n\n    {\n        auto op = build_row_shelf_opt(baseTW, baseTH, rotMinH);\n        if (!op.empty()) add_candidate(move(op));\n    }\n    {\n        auto op = build_col_shelf_opt(baseTW, baseTH, rotMinW);\n        if (!op.empty()) add_candidate(move(op));\n    }\n    for (int K : {3, 5, 7}) {\n        if (K <= N) {\n            add_candidate(build_row_shelf_greedyK(baseTW, baseTH, rotMinH, K));\n            add_candidate(build_col_shelf_greedyK(baseTW, baseTH, rotMinW, K));\n        }\n    }\n\n    // deterministic greedy seeds\n    vector<GreedyParam> det = {\n        {0.30, 0.006, 0.0},\n        {0.55, 0.010, 0.0},\n        {0.80, 0.016, 0.0},\n        {0.12, 0.000, 0.0}\n    };\n    for (auto gp : det) add_candidate(build_greedy(baseTW, baseTH, gp, rng));\n    add_candidate(build_greedy(baseUW, baseUH, GreedyParam{0.45, 0.008, 0.0}, rng));\n    if (S >= 3) add_candidate(build_greedy(scenarios[2].w, scenarios[2].h, GreedyParam{0.45, 0.008, 0.0}, rng));\n\n    // beams\n    int Bmain = (N <= 40 ? 50 : (N <= 70 ? 42 : (N <= 90 ? 36 : 30)));\n    int Bsub = max(16, Bmain - 12);\n\n    BeamParam bp1{Bmain, min(16, Bmain), 0.35, 0.006, 0.0};\n    BeamParam bp2{Bmain, min(14, Bmain), 0.65, 0.012, 0.0};\n    BeamParam bp3{Bsub, min(9, Bsub), 0.42, 0.010, 70.0 + 0.020 * (double)sigma};\n\n    auto run_beam = [&](const vector<ll>& bw, const vector<ll>& bh, const BeamParam& bp) {\n        if ((int)pool.size() >= Ptarget) return;\n        auto sols = beam_generate(bw, bh, bp, rng);\n        for (auto& ops : sols) {\n            add_candidate(move(ops));\n            if ((int)pool.size() >= Ptarget) break;\n        }\n    };\n\n    double genBudget = (N <= 60 ? 1.15 : 1.00);\n    if (sigma >= 8000) genBudget += 0.10;\n\n    if (elapsed() < genBudget) run_beam(baseTW, baseTH, bp1);\n    if ((int)pool.size() < Ptarget && elapsed() < genBudget) run_beam(baseTW, baseTH, bp2);\n    if ((int)pool.size() < Ptarget && elapsed() < genBudget) run_beam(baseUW, baseUH, bp3);\n    if ((int)pool.size() < Ptarget && sigma >= 5000 && S >= 4 && elapsed() < genBudget) {\n        run_beam(scenarios[3].w, scenarios[3].h, bp3);\n    }\n\n    // random greedy fill\n    int attempts = 0;\n    while ((int)pool.size() < Ptarget && elapsed() < genBudget && attempts < Ptarget * 55) {\n        int rs = rng.randint(0, S - 1);\n        GreedyParam gp;\n        gp.gap_w = 0.03 + 1.10 * rng.uniform01();\n        gp.bal_w = 0.03 * rng.uniform01();\n        gp.noise_w = (40.0 + 0.07 * (double)sigma) * rng.uniform01();\n        add_candidate(build_greedy(scenarios[rs].w, scenarios[rs].h, gp, rng));\n        attempts++;\n    }\n\n    // local refine top seeds\n    if (!pool.empty() && elapsed() < genBudget + 0.45) {\n        vector<pair<ll, int>> ord;\n        ord.reserve(pool.size());\n        for (int i = 0; i < (int)pool.size(); i++) {\n            ord.emplace_back(score_on_base(baseTW, baseTH, pool[i].ops), i);\n        }\n        sort(ord.begin(), ord.end());\n\n        int topK = min(4, (int)ord.size());\n        for (int k = 0; k < topK && elapsed() < genBudget + 0.45; k++) {\n            int idx = ord[k].second;\n            auto sa = anneal_optimize(baseTW, baseTH, pool[idx].ops, 70 + N, rng);\n            add_candidate(move(sa));\n            if (elapsed() > genBudget + 0.50) break;\n            auto hc = hill_climb(baseTW, baseTH, pool[idx].ops, 55 + N / 2, rng);\n            add_candidate(move(hc));\n        }\n    }\n\n    if (pool.empty()) {\n        add_candidate(build_greedy(baseTW, baseTH, GreedyParam{0.40, 0.008, 0.0}, rng));\n    }\n\n    for (auto& c : pool) compute_predictions(c, scenarios);\n\n    prune_dominated(pool);\n    if (pool.empty()) {\n        Candidate c;\n        c.ops = build_greedy(baseTW, baseTH, GreedyParam{0.40, 0.008, 0.0}, rng);\n        compute_predictions(c, scenarios);\n        c.hash = hash_ops(c.ops);\n        pool.push_back(move(c));\n    }\n\n    // specialists for early turns\n    vector<int> specialists;\n    {\n        int P = (int)pool.size();\n        vector<char> usedSpec(P, 0);\n\n        for (int s = 0; s < S; s++) {\n            ll bestV = INF64;\n            int bestI = -1;\n            for (int i = 0; i < P; i++) {\n                if (pool[i].predS[s] < bestV) {\n                    bestV = pool[i].predS[s];\n                    bestI = i;\n                }\n            }\n            if (bestI >= 0 && !usedSpec[bestI]) {\n                specialists.push_back(bestI);\n                usedSpec[bestI] = 1;\n            }\n        }\n\n        if (sigma >= 7000) {\n            for (int s = 0; s < min(S, 6); s++) {\n                ll v1 = INF64, v2 = INF64;\n                int i1 = -1, i2 = -1;\n                for (int i = 0; i < P; i++) {\n                    ll v = pool[i].predS[s];\n                    if (v < v1) {\n                        v2 = v1; i2 = i1;\n                        v1 = v;  i1 = i;\n                    } else if (v < v2) {\n                        v2 = v;  i2 = i;\n                    }\n                }\n                if (i2 >= 0 && !usedSpec[i2]) {\n                    specialists.push_back(i2);\n                    usedSpec[i2] = 1;\n                }\n            }\n        }\n    }\n\n    int exploreK = 0;\n    if (T >= 2) {\n        if (sigma <= 2500) exploreK = 1;\n        else if (sigma <= 6000) exploreK = 2;\n        else exploreK = 3;\n        exploreK = min(exploreK, T / 5);\n        exploreK = min(exploreK, (int)specialists.size());\n    }\n    int specPtr = 0;\n\n    // ===== online phase =====\n    vector<ll> bestScenario(S, INF64);\n    vector<double> logWeight(S, 0.0), post(S, 1.0 / S), weights(S, 1.0 / S);\n\n    vector<char> used(pool.size(), 0);\n    int usedCnt = 0;\n\n    double likeScale = max(800.0, (double)sigma * 1.45);\n    double invScale2 = 1.0 / (likeScale * likeScale);\n    double forget = 0.993;\n\n    int warmup = min(T - 1, max(3, T / 6));\n    int regen1 = min(T - 1, warmup + 1);\n    int regen2 = (T >= 28 ? min(T - 1, (2 * T) / 3) : -1);\n    bool regenDone1 = false, regenDone2 = false;\n\n    auto add_and_predict = [&](vector<Operation>&& ops) {\n        if ((int)ops.size() != N) return;\n        if ((int)pool.size() >= Pcap) return;\n        uint64_t h = hash_ops(ops);\n        if (!seen.insert(h).second) return;\n\n        Candidate c;\n        c.ops = move(ops);\n        c.hash = h;\n        compute_predictions(c, scenarios);\n        pool.push_back(move(c));\n        used.push_back(0);\n    };\n\n    auto regenerate_from_posterior = [&](const vector<double>& posterior) {\n        if (elapsed() > 2.55) return;\n        if ((int)pool.size() >= Pcap) return;\n\n        vector<ll> mw(N), mh(N);\n        for (int i = 0; i < N; i++) {\n            long double sw = 0.0L, sh = 0.0L;\n            for (int s = 0; s < S; s++) {\n                sw += (long double)posterior[s] * (long double)scenarios[s].w[i];\n                sh += (long double)posterior[s] * (long double)scenarios[s].h[i];\n            }\n            mw[i] = clamp_ll((ll)llround(sw), TRUE_MIN, TRUE_MAX);\n            mh[i] = clamp_ll((ll)llround(sh), TRUE_MIN, TRUE_MAX);\n        }\n\n        add_and_predict(build_greedy(mw, mh, GreedyParam{0.32, 0.006, 0.0}, rng));\n        add_and_predict(build_greedy(mw, mh, GreedyParam{0.60, 0.011, 0.0}, rng));\n        add_and_predict(build_greedy(mw, mh, GreedyParam{0.42, 0.009, 30.0 + 0.02 * (double)sigma}, rng));\n\n        vector<uint8_t> rH(N), rW(N);\n        for (int i = 0; i < N; i++) {\n            rH[i] = (mw[i] < mh[i]) ? 1 : 0;\n            rW[i] = (mh[i] < mw[i]) ? 1 : 0;\n        }\n        add_and_predict(build_row_shelf_greedyK(mw, mh, rH, min(4, N)));\n        add_and_predict(build_col_shelf_greedyK(mw, mh, rW, min(4, N)));\n\n        int bestIdx = -1;\n        long double bestEv = 1e300L;\n        for (int i = 0; i < (int)pool.size(); i++) {\n            long double ev = 0.0L;\n            for (int s = 0; s < S; s++) ev += (long double)posterior[s] * (long double)pool[i].predS[s];\n            if (ev < bestEv) {\n                bestEv = ev;\n                bestIdx = i;\n            }\n        }\n        if (bestIdx >= 0) {\n            add_and_predict(hill_climb(mw, mh, pool[bestIdx].ops, 45 + N / 2, rng));\n        }\n\n        if (elapsed() < 2.45 && (int)pool.size() < Pcap) {\n            int Br = max(14, Bmain - 16);\n            BeamParam rb{Br, min(6, Br), 0.40, 0.009, 0.0};\n            auto sols = beam_generate(mw, mh, rb, rng);\n            for (auto& ops : sols) {\n                add_and_predict(move(ops));\n                if ((int)pool.size() >= Pcap) break;\n            }\n        }\n    };\n\n    for (int turn = 0; turn < T; turn++) {\n        double frac = (double)turn / max(1, T - 1);\n\n        // posterior from log-weights\n        double gamma = 0.35 + 0.55 * frac;\n        double mx = *max_element(logWeight.begin(), logWeight.end());\n        double sp = 0.0;\n        for (int s = 0; s < S; s++) {\n            post[s] = exp((logWeight[s] - mx) * gamma);\n            sp += post[s];\n        }\n        if (sp <= 0.0) {\n            for (int s = 0; s < S; s++) post[s] = 1.0 / S;\n        } else {\n            for (int s = 0; s < S; s++) post[s] /= sp;\n        }\n\n        double beta = 0.0;\n        if (turn >= warmup) {\n            beta = 0.70 * (double)(turn - warmup + 1) / max(1, T - warmup);\n            if (beta > 0.70) beta = 0.70;\n        }\n        for (int s = 0; s < S; s++) {\n            weights[s] = (1.0 - beta) * (1.0 / S) + beta * post[s];\n        }\n\n        if (!regenDone1 && turn == regen1) {\n            regenerate_from_posterior(post);\n            regenDone1 = true;\n        }\n        if (!regenDone2 && regen2 >= 0 && turn == regen2) {\n            regenerate_from_posterior(post);\n            regenDone2 = true;\n        }\n\n        bool hasUnused = (usedCnt < (int)used.size());\n        int chosen = -1;\n\n        // early deterministic specialist exploration\n        if (turn < exploreK) {\n            while (specPtr < (int)specialists.size() && used[specialists[specPtr]]) specPtr++;\n            if (specPtr < (int)specialists.size()) {\n                chosen = specialists[specPtr++];\n            }\n        }\n\n        if (chosen == -1) {\n            long double bestVal = 1e300L;\n            double lambda_wc = 0.06 * (1.0 - frac);\n\n            double eta_spread = 0.0;\n            if (turn <= warmup + 2) {\n                double f = (double)(warmup + 2 - turn) / (double)(warmup + 3);\n                eta_spread = (sigma >= 5000 ? 0.04 : 0.02) * f;\n            }\n\n            for (int ci = 0; ci < (int)pool.size(); ci++) {\n                if (hasUnused && used[ci]) continue;\n\n                long double ev = 0.0L;\n                ll worst = 0;\n                for (int s = 0; s < S; s++) {\n                    ll cur = min(bestScenario[s], pool[ci].predS[s]);\n                    ev += (long double)weights[s] * (long double)cur;\n                    worst = max(worst, cur);\n                }\n\n                long double val = ev + lambda_wc * (long double)worst - eta_spread * (long double)pool[ci].spread;\n\n                if (chosen == -1 || val < bestVal - 1e-12L ||\n                    (fabsl(val - bestVal) <= 1e-12L && pool[ci].avg < pool[chosen].avg)) {\n                    bestVal = val;\n                    chosen = ci;\n                }\n            }\n        }\n\n        if (chosen == -1) chosen = 0;\n\n        if (!used[chosen]) {\n            used[chosen] = 1;\n            usedCnt++;\n        }\n\n        // output all rectangles\n        cout << N << '\\n';\n        for (int i = 0; i < N; i++) {\n            const auto& op = pool[chosen].ops[i];\n            cout << i << ' ' << int(op.r) << ' ' << (op.d == 0 ? 'U' : 'L') << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        if (Wm == -1 && Hm == -1) return 0;\n\n        // best-of-turns update (model-side)\n        for (int s = 0; s < S; s++) {\n            bestScenario[s] = min(bestScenario[s], pool[chosen].predS[s]);\n        }\n\n        // robust posterior update\n        for (int s = 0; s < S; s++) logWeight[s] *= forget;\n\n        double updCoef = 0.70 + 0.55 * frac;\n        for (int s = 0; s < S; s++) {\n            double dw = (double)Wm - (double)pool[chosen].predW[s];\n            double dh = (double)Hm - (double)pool[chosen].predH[s];\n            double d2 = (dw * dw + dh * dh) * invScale2;\n            logWeight[s] += -updCoef * log1p(d2);\n        }\n\n        double mx2 = *max_element(logWeight.begin(), logWeight.end());\n        for (int s = 0; s < S; s++) logWeight[s] -= mx2;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nclass Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<vector<int>> g;\n    vector<int> ordDesc, ordAsc;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point t0;\n\n    struct DState {\n        vector<int> d;\n        vector<int> cnt;\n        long long extra = 0; // sum d[v] * A[v]\n    };\n\n    struct Forest {\n        vector<int> p;             // parent (-1 = root)\n        vector<int> d;             // depth\n        vector<int> idx;           // index in parent's child list (or -1)\n        vector<vector<int>> ch;    // children\n        long long extra = 0;       // sum d[v] * A[v]\n    };\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void solve() {\n        read_input();\n        prepare_orders();\n        t0 = chrono::steady_clock::now();\n\n        const double TOTAL  = 1.88;\n        const double D1_END = 0.84;\n        const double T1_END = 1.34;\n        const double D2_END = 1.52;\n\n        vector<int> d0;\n        if (elapsed() < D1_END) d0 = optimize_depths_scratch(D1_END);\n        else d0.assign(N, 0);\n        repair_depth(d0);\n\n        Forest globalBest = build_forest_from_depth(d0, 0);\n\n        if (elapsed() < T1_END) {\n            Forest f1 = tree_optimize(d0, T1_END);\n            if (f1.extra > globalBest.extra) globalBest = move(f1);\n        }\n\n        vector<int> dSeed = globalBest.d;\n        if (elapsed() < D2_END) {\n            dSeed = polish_depth_seed(dSeed, D2_END);\n            Forest f2 = build_forest_from_depth(dSeed, 0);\n            if (f2.extra > globalBest.extra) globalBest = move(f2);\n        }\n\n        vector<int> finalSeed = (depth_extra_value(dSeed) >= globalBest.extra ? dSeed : globalBest.d);\n\n        if (elapsed() < TOTAL - 1e-4) {\n            Forest f3 = tree_optimize(finalSeed, TOTAL);\n            if (f3.extra > globalBest.extra) globalBest = move(f3);\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << globalBest.p[i];\n        }\n        cout << '\\n';\n    }\n\nprivate:\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        for (int i = 0; i < N; i++) {\n            int x, y;\n            cin >> x >> y;\n        }\n    }\n\n    void prepare_orders() {\n        ordDesc.resize(N);\n        iota(ordDesc.begin(), ordDesc.end(), 0);\n        sort(ordDesc.begin(), ordDesc.end(), [&](int a, int b) {\n            if (A[a] != A[b]) return A[a] > A[b];\n            if (g[a].size() != g[b].size()) return g[a].size() < g[b].size();\n            return a < b;\n        });\n        ordAsc = ordDesc;\n        reverse(ordAsc.begin(), ordAsc.end());\n    }\n\n    void shuffle_vec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i >= 1; --i) {\n            int j = rng.next_int(0, i);\n            swap(v[i], v[j]);\n        }\n    }\n\n    long long depth_extra_value(const vector<int>& d) const {\n        long long s = 0;\n        for (int v = 0; v < N; v++) s += 1LL * d[v] * A[v];\n        return s;\n    }\n\n    // =========================\n    // Depth-label optimization\n    // =========================\n    void rebuild(DState& st) const {\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n        for (int v = 0; v < N; v++) st.extra += 1LL * st.d[v] * A[v];\n\n        for (int v = 0; v < N; v++) {\n            if (st.d[v] == 0) continue;\n            int need = st.d[v] - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n    }\n\n    void repair_depth(vector<int>& d) const {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int v = 0; v < N; v++) {\n                while (d[v] > 0) {\n                    int need = d[v] - 1;\n                    bool ok = false;\n                    for (int u : g[v]) {\n                        if (d[u] == need) {\n                            ok = true;\n                            break;\n                        }\n                    }\n                    if (ok) break;\n                    --d[v];\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    inline bool feasible_change(const DState& st, int v, int nd) const {\n        int od = st.d[v];\n        if (nd == od) return false;\n        if (nd < 0 || nd > H) return false;\n\n        if (nd > 0) {\n            bool ok = false;\n            for (int u : g[v]) {\n                if (st.d[u] == nd - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            int c = st.cnt[u];\n            if (od == need) --c;\n            if (nd == need) ++c;\n            if (c <= 0) return false;\n        }\n\n        return true;\n    }\n\n    inline void apply_change(DState& st, int v, int nd) const {\n        int od = st.d[v];\n        if (od == nd) return;\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            if (od == need) --st.cnt[u];\n            if (nd == need) ++st.cnt[u];\n        }\n\n        st.d[v] = nd;\n        if (nd == 0) st.cnt[v] = 0;\n        else {\n            int need = nd - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n\n        st.extra += 1LL * (nd - od) * A[v];\n    }\n\n    bool greedy_up_pass(DState& st, const vector<int>& order, bool stepwise) const {\n        bool changed = false;\n        for (int v : order) {\n            int cur = st.d[v];\n            if (stepwise) {\n                int nd = cur + 1;\n                if (nd <= H && feasible_change(st, v, nd)) {\n                    apply_change(st, v, nd);\n                    changed = true;\n                }\n            } else {\n                for (int nd = H; nd > cur; --nd) {\n                    if (feasible_change(st, v, nd)) {\n                        apply_change(st, v, nd);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n        return changed;\n    }\n\n    DState construct_initial_variant(int variant) {\n        DState st;\n        st.d.assign(N, 0);\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) key[v] = A[v] * 2048 + rng.next_int(0, 2047);\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 1) {\n            order = ordDesc;\n            int sw = N / 4;\n            for (int i = 0; i < sw; i++) {\n                int x = rng.next_int(0, N - 1), y = rng.next_int(0, N - 1);\n                swap(order[x], order[y]);\n            }\n        } else if (variant == 2) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) {\n                int deg = (int)g[v].size();\n                key[v] = (A[v] * 1200) / (deg + 1) + rng.next_int(0, 255);\n            }\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 3) {\n            order = ordDesc;\n            shuffle_vec(order);\n        } else {\n            order = ordDesc;\n        }\n\n        for (int pass = 0; pass < 24; pass++) {\n            bool step = (pass < 4);\n            bool changed = greedy_up_pass(st, order, step);\n\n            if (pass == 1 || pass == 4 || pass == 8) {\n                if (variant == 1 || variant == 3) shuffle_vec(order);\n            }\n            if (!changed && pass > 7) break;\n        }\n\n        for (int rep = 0; rep < 4; rep++) {\n            if (!greedy_up_pass(st, ordDesc, false)) break;\n        }\n\n        return st;\n    }\n\n    void short_sa_polish(DState& st, int iters, double T0, double T1, double timeLimit) {\n        int topK = min(N, 240);\n        vector<int> bestD = st.d;\n        long long bestE = st.extra;\n\n        for (int it = 0; it < iters; it++) {\n            if ((it & 127) == 0 && elapsed() >= timeLimit) break;\n\n            int v = (rng.next_double() < 0.70)\n                ? ordDesc[rng.next_int(0, topK - 1)]\n                : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = st.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != st.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.45) nd = cand[clen - 1];\n            else if (r < 0.57) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(st, v, nd)) continue;\n\n            int delta = (nd - st.d[v]) * A[v];\n            double p = (double)it / max(1, iters - 1);\n            double temp = T0 * pow(T1 / T0, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n            apply_change(st, v, nd);\n\n            if (st.extra > bestE) {\n                bestE = st.extra;\n                bestD = st.d;\n            }\n        }\n\n        if (bestE > st.extra) {\n            st.d = move(bestD);\n            rebuild(st);\n        }\n    }\n\n    void run_feasible_sa(DState& cur, DState& best, double timeLimit) {\n        double saStart = elapsed();\n        if (saStart >= timeLimit) return;\n\n        const double T0 = 55.0;\n        const double T1 = 0.18;\n        const double ratio = T1 / T0;\n        int topK = min(N, 300);\n\n        long long iter = 0;\n        while (true) {\n            if ((iter & 255LL) == 0 && elapsed() >= timeLimit) break;\n            ++iter;\n\n            int v = (rng.next_double() < 0.62)\n                ? ordDesc[rng.next_int(0, topK - 1)]\n                : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = cur.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != cur.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.48) nd = cand[clen - 1];\n            else if (r < 0.62) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(cur, v, nd)) continue;\n\n            int delta = (nd - cur.d[v]) * A[v];\n\n            double now = elapsed();\n            double p = (now - saStart) / max(1e-9, timeLimit - saStart);\n            p = max(0.0, min(1.0, p));\n            double temp = T0 * pow(ratio, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n            apply_change(cur, v, nd);\n\n            if (cur.extra > best.extra) best = cur;\n            if ((iter & 65535LL) == 0 && cur.extra + 5000 < best.extra) cur = best;\n        }\n    }\n\n    void macro_perturb_search(DState& best, double timeLimit) {\n        int topHigh = min(N, 300);\n        int topLow = min(N, 420);\n        vector<int> order = ordDesc;\n\n        while (elapsed() < timeLimit) {\n            DState tmp = best;\n            int mode = rng.next_int(0, 4);\n\n            if (mode == 0) {\n                int k = rng.next_int(1, 4);\n                for (int i = 0; i < k; i++) {\n                    int v = ordDesc[rng.next_int(0, topHigh - 1)];\n                    tmp.d[v] = H;\n                }\n            } else if (mode == 1) {\n                int k = rng.next_int(2, 7);\n                for (int i = 0; i < k; i++) {\n                    int v = ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = 0;\n                }\n            } else if (mode == 2) {\n                int k = rng.next_int(18, 80);\n                for (int i = 0; i < k; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    tmp.d[v] = rng.next_int(0, H);\n                }\n            } else if (mode == 3) {\n                int k = rng.next_int(15, 50);\n                for (int i = 0; i < k; i++) {\n                    bool hi = (rng.next_double() < 0.62);\n                    int v = hi ? ordDesc[rng.next_int(0, topHigh - 1)]\n                               : ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = hi ? H : 0;\n                }\n            } else {\n                int c = rng.next_int(0, N - 1);\n                tmp.d[c] = (rng.next_double() < 0.5 ? 0 : H);\n                for (int u : g[c]) if (rng.next_double() < 0.75) tmp.d[u] = rng.next_int(0, H);\n                int ex = rng.next_int(5, 20);\n                for (int i = 0; i < ex; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    if (rng.next_double() < 0.55) tmp.d[v] = 0;\n                }\n            }\n\n            repair_depth(tmp.d);\n            rebuild(tmp);\n\n            order = ordDesc;\n            for (int pass = 0; pass < 7; pass++) {\n                if (pass == 1 || pass == 4) shuffle_vec(order);\n                else if (pass == 2 || pass == 5) order = ordDesc;\n\n                bool step = (pass < 2);\n                bool changed = greedy_up_pass(tmp, order, step);\n\n                if (!changed && pass >= 4) break;\n                if (elapsed() >= timeLimit) break;\n            }\n\n            if (elapsed() + 0.008 < timeLimit && rng.next_double() < 0.50) {\n                short_sa_polish(tmp, 520, 2.1, 0.4, timeLimit);\n            }\n\n            if (tmp.extra > best.extra) best = move(tmp);\n        }\n    }\n\n    vector<int> optimize_depths_scratch(double endTime) {\n        DState best;\n        best.extra = LLONG_MIN;\n\n        double initEnd = min(endTime, 0.24);\n        int restart = 0;\n        while (elapsed() < initEnd) {\n            DState st = construct_initial_variant(restart % 5);\n\n            if ((restart & 1) == 0 && elapsed() + 0.008 < initEnd) {\n                short_sa_polish(st, 420, 4.5, 0.9, initEnd);\n            }\n\n            if (st.extra > best.extra) best = move(st);\n            ++restart;\n        }\n\n        if (best.extra == LLONG_MIN) {\n            best.d.assign(N, 0);\n            best.cnt.assign(N, 0);\n            best.extra = 0;\n        }\n\n        DState cur = best;\n\n        double saEnd = min(endTime, initEnd + (endTime - initEnd) * 0.58);\n        if (elapsed() < saEnd) run_feasible_sa(cur, best, saEnd);\n        if (elapsed() < endTime) macro_perturb_search(best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 5; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    vector<int> polish_depth_seed(const vector<int>& seed, double endTime) {\n        DState best;\n        best.d = seed;\n        repair_depth(best.d);\n        rebuild(best);\n\n        for (int i = 0; i < 4; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        DState cur = best;\n        double rem = max(0.0, endTime - elapsed());\n        double saEnd = min(endTime, elapsed() + rem * 0.62);\n        if (elapsed() < saEnd) run_feasible_sa(cur, best, saEnd);\n        if (elapsed() < endTime) macro_perturb_search(best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 3; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    // =========================\n    // Tree / subtree optimization\n    // =========================\n    void build_children_idx(Forest& f) const {\n        f.ch.assign(N, {});\n        f.idx.assign(N, -1);\n        for (int v = 0; v < N; v++) {\n            int p = f.p[v];\n            if (p != -1) {\n                f.idx[v] = (int)f.ch[p].size();\n                f.ch[p].push_back(v);\n            }\n        }\n    }\n\n    inline void cut(Forest& f, int v) const {\n        int p = f.p[v];\n        if (p == -1) return;\n        int i = f.idx[v];\n        int last = f.ch[p].back();\n        f.ch[p][i] = last;\n        f.idx[last] = i;\n        f.ch[p].pop_back();\n        f.p[v] = -1;\n        f.idx[v] = -1;\n    }\n\n    inline void link(Forest& f, int v, int p) const {\n        f.p[v] = p;\n        f.idx[v] = (int)f.ch[p].size();\n        f.ch[p].push_back(v);\n    }\n\n    inline void move_parent(Forest& f, int v, int np) const {\n        int op = f.p[v];\n        if (op == np) return;\n        if (op != -1) cut(f, v);\n        if (np != -1) link(f, v, np);\n    }\n\n    void recompute_depth_from_parent(Forest& f) const {\n        vector<int> nd(N, -1);\n        deque<int> dq;\n        for (int v = 0; v < N; v++) {\n            if (f.p[v] == -1) {\n                nd[v] = 0;\n                dq.push_back(v);\n            }\n        }\n\n        while (!dq.empty()) {\n            int x = dq.front();\n            dq.pop_front();\n            for (int y : f.ch[x]) {\n                if (nd[y] != -1) continue;\n                nd[y] = nd[x] + 1;\n                dq.push_back(y);\n            }\n        }\n\n        bool bad = false;\n        for (int v = 0; v < N; v++) {\n            if (nd[v] == -1) {\n                f.p[v] = -1;\n                bad = true;\n            }\n        }\n\n        if (bad) {\n            build_children_idx(f);\n            fill(nd.begin(), nd.end(), -1);\n            for (int v = 0; v < N; v++) {\n                if (f.p[v] == -1) {\n                    nd[v] = 0;\n                    dq.push_back(v);\n                }\n            }\n            while (!dq.empty()) {\n                int x = dq.front();\n                dq.pop_front();\n                for (int y : f.ch[x]) {\n                    if (nd[y] != -1) continue;\n                    nd[y] = nd[x] + 1;\n                    dq.push_back(y);\n                }\n            }\n        }\n\n        for (int v = 0; v < N; v++) {\n            if (nd[v] < 0) nd[v] = 0;\n            if (nd[v] > H) nd[v] = H; // safety\n        }\n\n        f.d.swap(nd);\n        f.extra = 0;\n        for (int v = 0; v < N; v++) f.extra += 1LL * f.d[v] * A[v];\n    }\n\n    Forest build_forest_from_depth(const vector<int>& depth, int mode) {\n        Forest f;\n        f.d = depth;\n        f.p.assign(N, -1);\n\n        for (int v = 0; v < N; v++) {\n            if (f.d[v] == 0) {\n                f.p[v] = -1;\n                continue;\n            }\n\n            int need = f.d[v] - 1;\n            vector<int> cand;\n            cand.reserve(g[v].size());\n            for (int u : g[v]) if (f.d[u] == need) cand.push_back(u);\n\n            int par = -1;\n            if (!cand.empty()) {\n                if ((int)cand.size() == 1) {\n                    par = cand[0];\n                } else if (mode == 1) { // random\n                    par = cand[rng.next_int(0, (int)cand.size() - 1)];\n                } else if (mode == 2) { // high-degree support\n                    int bestDeg = -1;\n                    for (int u : cand) {\n                        int du = (int)g[u].size();\n                        if (du > bestDeg || (du == bestDeg && (par == -1 || A[u] < A[par]))) {\n                            bestDeg = du;\n                            par = u;\n                        }\n                    }\n                } else { // low-A support\n                    long long bestKey = (1LL << 60);\n                    for (int u : cand) {\n                        long long key = 1LL * A[u] * 512 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            par = u;\n                        }\n                    }\n                }\n            } else {\n                par = -1; // safety\n            }\n\n            f.p[v] = par;\n        }\n\n        build_children_idx(f);\n        recompute_depth_from_parent(f);\n        return f;\n    }\n\n    void normalize_parents(Forest& f, int rounds, bool highFirst) {\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        for (int r = 0; r < rounds; r++) {\n            if (highFirst) order = ordDesc;\n            else shuffle_vec(order);\n\n            for (int v : order) {\n                if (f.d[v] == 0) continue;\n                int need = f.d[v] - 1;\n                int curp = f.p[v];\n\n                int best = curp;\n                long long bestKey = (1LL << 60);\n                if (curp != -1) {\n                    bestKey = 1LL * A[curp] * 256 + (int)f.ch[curp].size() * 8 + (int)g[curp].size();\n                }\n\n                for (int u : g[v]) {\n                    if (f.d[u] != need) continue;\n                    long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                    if (key < bestKey) {\n                        bestKey = key;\n                        best = u;\n                    }\n                }\n\n                if (best != -1 && best != curp) move_parent(f, v, best);\n            }\n        }\n    }\n\n    void leafify_highA(Forest& f, int topK, int rounds) {\n        topK = min(topK, N);\n        for (int r = 0; r < rounds; r++) {\n            for (int i = 0; i < topK; i++) {\n                int v = ordDesc[i];\n                if (f.ch[v].empty()) continue;\n\n                vector<int> children = f.ch[v];\n                for (int x : children) {\n                    if (f.p[x] != v) continue;\n                    int need = f.d[x] - 1;\n                    if (need < 0) continue;\n\n                    int best = -1;\n                    long long bestKey = (1LL << 60);\n\n                    for (int u : g[x]) {\n                        if (u == v) continue;\n                        if (f.d[u] != need) continue;\n                        long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            best = u;\n                        }\n                    }\n\n                    if (best != -1) move_parent(f, x, best);\n                }\n            }\n        }\n    }\n\n    void compute_submax_static(const Forest& f, vector<int>& subMax) const {\n        subMax = f.d;\n        vector<vector<int>> bucket(H + 1);\n        for (int v = 0; v < N; v++) {\n            int dep = max(0, min(H, f.d[v]));\n            bucket[dep].push_back(v);\n        }\n        for (int dep = H; dep >= 0; dep--) {\n            for (int v : bucket[dep]) {\n                int p = f.p[v];\n                if (p != -1 && subMax[v] > subMax[p]) subMax[p] = subMax[v];\n            }\n        }\n    }\n\n    void trim_deep_branches(Forest& f, int topK, int rounds) {\n        topK = min(topK, N);\n        vector<int> subMax;\n\n        for (int r = 0; r < rounds; r++) {\n            compute_submax_static(f, subMax);\n            bool changed = false;\n\n            for (int i = 0; i < topK; i++) {\n                int v = ordDesc[i];\n                if (f.d[v] >= H) continue;\n                if (subMax[v] < H) continue;\n\n                vector<int> children = f.ch[v];\n                for (int c : children) {\n                    if (f.p[c] != v) continue;\n                    if (subMax[c] < H) continue;\n\n                    int need = f.d[c] - 1;\n                    int best = -1;\n                    long long bestKey = (1LL << 60);\n\n                    for (int u : g[c]) {\n                        if (u == v) continue;\n                        if (f.d[u] != need) continue;\n                        long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            best = u;\n                        }\n                    }\n\n                    if (best != -1) {\n                        move_parent(f, c, best);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void random_neutral_rewire(Forest& f, int tries) {\n        if (tries <= 0) return;\n        int topK = min(N, 260);\n\n        for (int t = 0; t < tries; t++) {\n            int v = (rng.next_double() < 0.65)\n                ? ordDesc[rng.next_int(0, topK - 1)]\n                : rng.next_int(0, N - 1);\n\n            if (f.d[v] == 0) continue;\n            int need = f.d[v] - 1;\n            int curp = f.p[v];\n\n            int best = -1;\n            if (rng.next_double() < 0.55) {\n                int cnt = 0;\n                for (int u : g[v]) {\n                    if (u == curp) continue;\n                    if (f.d[u] != need) continue;\n                    ++cnt;\n                    if (rng.next_int(1, cnt) == 1) best = u;\n                }\n            } else {\n                long long bestKey = (1LL << 60);\n                for (int u : g[v]) {\n                    if (u == curp) continue;\n                    if (f.d[u] != need) continue;\n                    long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                    if (key < bestKey) {\n                        bestKey = key;\n                        best = u;\n                    }\n                }\n            }\n\n            if (best != -1) move_parent(f, v, best);\n        }\n    }\n\n    void init_subinfo(const Forest& f, vector<long long>& subA, vector<int>& subMax) const {\n        subA.assign(N, 0);\n        subMax.assign(N, 0);\n\n        vector<vector<int>> bucket(H + 1);\n        for (int v = 0; v < N; v++) {\n            subA[v] = A[v];\n            subMax[v] = f.d[v];\n            int dep = max(0, min(H, f.d[v]));\n            bucket[dep].push_back(v);\n        }\n\n        for (int dep = H; dep >= 0; dep--) {\n            for (int v : bucket[dep]) {\n                int p = f.p[v];\n                if (p != -1) {\n                    subA[p] += subA[v];\n                    if (subMax[v] > subMax[p]) subMax[p] = subMax[v];\n                }\n            }\n        }\n    }\n\n    inline bool is_descendant(const Forest& f, int u, int anc) const {\n        while (u != -1 && f.d[u] > f.d[anc]) u = f.p[u];\n        return u == anc;\n    }\n\n    void run_tree_sa_fast(Forest& cur, Forest& best, double timeLimit) {\n        if (elapsed() >= timeLimit) return;\n\n        vector<long long> subA;\n        vector<int> subMax;\n        init_subinfo(cur, subA, subMax);\n\n        vector<int> nodes, stk;\n        nodes.reserve(N);\n        stk.reserve(N);\n\n        auto gather_nodes = [&](int root) {\n            nodes.clear();\n            stk.clear();\n            stk.push_back(root);\n            while (!stk.empty()) {\n                int x = stk.back();\n                stk.pop_back();\n                nodes.push_back(x);\n                for (int y : cur.ch[x]) stk.push_back(y);\n            }\n        };\n\n        auto recompute_up = [&](int a) {\n            while (a != -1) {\n                int mx = cur.d[a];\n                for (int c : cur.ch[a]) if (subMax[c] > mx) mx = subMax[c];\n                subMax[a] = mx;\n                a = cur.p[a];\n            }\n        };\n\n        auto apply_move = [&](int v, int np, int delta, long long gain) {\n            int oldp = cur.p[v];\n            if (delta == 0) {\n                if (oldp == np) return;\n                if (oldp != -1) cut(cur, v);\n                if (np != -1) link(cur, v, np);\n\n                cur.extra += gain; // usually 0\n                long long sv = subA[v];\n\n                if (oldp != -1) {\n                    int a = oldp;\n                    while (a != -1) {\n                        subA[a] -= sv;\n                        a = cur.p[a];\n                    }\n                }\n                if (np != -1) {\n                    int a = np;\n                    while (a != -1) {\n                        subA[a] += sv;\n                        a = cur.p[a];\n                    }\n                }\n\n                if (oldp != -1) recompute_up(oldp);\n                if (np != -1) recompute_up(np);\n\n                if (cur.extra > best.extra) best = cur;\n                return;\n            }\n\n            gather_nodes(v);\n\n            if (oldp != -1) cut(cur, v);\n            if (np != -1) link(cur, v, np);\n\n            for (int x : nodes) {\n                cur.d[x] += delta;\n                subMax[x] += delta;\n            }\n\n            cur.extra += gain;\n            long long sv = subA[v];\n\n            if (oldp != -1) {\n                int a = oldp;\n                while (a != -1) {\n                    subA[a] -= sv;\n                    a = cur.p[a];\n                }\n            }\n            if (np != -1) {\n                int a = np;\n                while (a != -1) {\n                    subA[a] += sv;\n                    a = cur.p[a];\n                }\n            }\n\n            if (oldp != -1) recompute_up(oldp);\n            if (np != -1) recompute_up(np);\n\n            if (cur.extra > best.extra) best = cur;\n        };\n\n        auto choose_parent_at_depth = [&](int x, int depthNeed, int ban) -> int {\n            int bestPar = -1;\n            long long bestKey = (1LL << 60);\n            for (int u : g[x]) {\n                if (u == ban) continue;\n                if (cur.d[u] != depthNeed) continue;\n                if (is_descendant(cur, u, x)) continue;\n                long long key = 1LL * A[u] * 256 + (int)cur.ch[u].size() * 8 + (int)g[u].size();\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestPar = u;\n                }\n            }\n            return bestPar;\n        };\n\n        vector<int> ordSub(N);\n        auto refresh_ordSub = [&]() {\n            iota(ordSub.begin(), ordSub.end(), 0);\n            sort(ordSub.begin(), ordSub.end(), [&](int a, int b) {\n                if (subA[a] != subA[b]) return subA[a] > subA[b];\n                if (A[a] != A[b]) return A[a] > A[b];\n                return a < b;\n            });\n        };\n\n        auto greedy_positive = [&](int passes) {\n            for (int ps = 0; ps < passes; ps++) {\n                if (elapsed() >= timeLimit) return;\n                refresh_ordSub();\n                bool changed = false;\n\n                for (int ii = 0; ii < N; ii++) {\n                    if ((ii & 31) == 0 && elapsed() >= timeLimit) return;\n                    int v = ordSub[ii];\n                    long long sv = subA[v];\n                    int sm = subMax[v];\n\n                    long long bestG = 0;\n                    int bestPar = -2;\n                    int bestDelta = 0;\n\n                    for (int u : g[v]) {\n                        if (is_descendant(cur, u, v)) continue;\n\n                        int ndv = cur.d[u] + 1;\n                        if (ndv > H) continue;\n\n                        int delta = ndv - cur.d[v];\n                        if (delta <= 0) continue;\n                        if (sm + delta > H) continue;\n\n                        long long gain = 1LL * delta * sv;\n                        if (gain > bestG ||\n                            (gain == bestG && bestPar != -2 && A[u] < A[bestPar])) {\n                            bestG = gain;\n                            bestPar = u;\n                            bestDelta = delta;\n                        }\n                    }\n\n                    if (bestPar != -2) {\n                        apply_move(v, bestPar, bestDelta, bestG);\n                        changed = true;\n                    }\n                }\n\n                if (!changed) break;\n            }\n        };\n\n        // Composite positive move:\n        // detach H-blocking child subtrees (sideways or -1 if cheap), then raise parent +1\n        auto composite_unblock = [&](int passes) {\n            struct Act {\n                int c;\n                int np;\n                int delta;\n            };\n\n            int topK = min(N, 260);\n            for (int ps = 0; ps < passes; ps++) {\n                if (elapsed() >= timeLimit) return;\n                bool changed = false;\n\n                for (int i = 0; i < topK; i++) {\n                    if ((i & 31) == 0 && elapsed() >= timeLimit) return;\n                    int v = ordDesc[i];\n                    if (cur.d[v] <= 0 || cur.d[v] >= H) continue;\n\n                    int up0 = choose_parent_at_depth(v, cur.d[v], -1);\n                    if (up0 == -1) continue;\n\n                    vector<int> blockers;\n                    blockers.reserve(cur.ch[v].size());\n                    for (int c : cur.ch[v]) {\n                        if (subMax[c] == H) blockers.push_back(c);\n                    }\n\n                    if (blockers.empty()) continue;\n                    if ((int)blockers.size() > 4) continue; // keep stable/cheap\n\n                    vector<Act> acts;\n                    acts.reserve(blockers.size());\n\n                    long long removed = 0;\n                    long long downCost = 0;\n                    bool ok = true;\n\n                    for (int c : blockers) {\n                        removed += subA[c];\n\n                        int p0 = choose_parent_at_depth(c, cur.d[v], v); // sideways\n                        if (p0 != -1) {\n                            acts.push_back({c, p0, 0});\n                            continue;\n                        }\n\n                        int p1 = -1;\n                        if (cur.d[v] - 1 >= 0) {\n                            p1 = choose_parent_at_depth(c, cur.d[v] - 1, -1); // down by 1\n                        }\n                        if (p1 != -1) {\n                            acts.push_back({c, p1, -1});\n                            downCost += subA[c];\n                        } else {\n                            ok = false;\n                            break;\n                        }\n                    }\n\n                    if (!ok) continue;\n\n                    // Estimated immediate net gain:\n                    // raise gain on remaining subtree = subA[v] - removed\n                    // plus blocker move losses = -downCost\n                    long long estGain = (subA[v] - removed) - downCost;\n                    if (estGain <= 0) continue;\n\n                    for (auto &ac : acts) {\n                        long long gain = 1LL * ac.delta * subA[ac.c];\n                        apply_move(ac.c, ac.np, ac.delta, gain);\n                    }\n\n                    if (subMax[v] <= H - 1) {\n                        int up = choose_parent_at_depth(v, cur.d[v], -1);\n                        if (up != -1) {\n                            apply_move(v, up, +1, subA[v]);\n                            changed = true;\n                        }\n                    }\n                }\n\n                if (!changed) break;\n            }\n        };\n\n        greedy_positive(1);\n        composite_unblock(2);\n        greedy_positive(1);\n\n        struct Cand {\n            int par;\n            int delta;\n            long long gain;\n        };\n        vector<Cand> cands;\n        cands.reserve(24);\n\n        refresh_ordSub();\n        const int topA = min(N, 300);\n        const int topS = min(N, 320);\n\n        double phaseStart = elapsed();\n        const double T0 = 3200.0;\n        const double T1 = 1.65;\n        const double ratio = T1 / T0;\n\n        long long iter = 0;\n        while (true) {\n            if ((iter & 127LL) == 0 && elapsed() >= timeLimit) break;\n            ++iter;\n\n            if ((iter & 1023LL) == 0) refresh_ordSub();\n\n            int v;\n            double rr = rng.next_double();\n            if (rr < 0.44) v = ordDesc[rng.next_int(0, topA - 1)];\n            else if (rr < 0.80) v = ordSub[rng.next_int(0, topS - 1)];\n            else v = rng.next_int(0, N - 1);\n\n            long long sv = subA[v];\n            int sm = subMax[v];\n\n            cands.clear();\n            long long bestGain = LLONG_MIN;\n            int bestIdx = -1;\n\n            for (int u : g[v]) {\n                if (is_descendant(cur, u, v)) continue;\n\n                int ndv = cur.d[u] + 1;\n                if (ndv > H) continue;\n\n                int delta = ndv - cur.d[v];\n                if (delta == 0 && cur.p[v] == u) continue;\n                if (sm + delta > H) continue;\n\n                long long gain = 1LL * delta * sv;\n                cands.push_back({u, delta, gain});\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestIdx = (int)cands.size() - 1;\n                }\n            }\n\n            if (cur.p[v] != -1) {\n                int delta = -cur.d[v];\n                if (sm + delta <= H) {\n                    long long gain = 1LL * delta * sv;\n                    cands.push_back({-1, delta, gain});\n                    if (gain > bestGain) {\n                        bestGain = gain;\n                        bestIdx = (int)cands.size() - 1;\n                    }\n                }\n            }\n\n            if (cands.empty()) continue;\n\n            int chosen;\n            if (bestIdx != -1 && bestGain > 0 && rng.next_double() < 0.78) {\n                chosen = bestIdx;\n            } else {\n                chosen = rng.next_int(0, (int)cands.size() - 1);\n            }\n\n            Cand c = cands[chosen];\n            if (c.par == cur.p[v] && c.delta == 0) continue;\n\n            bool accept = false;\n            if (c.gain > 0) {\n                accept = true;\n            } else if (c.gain == 0) {\n                double pr = (c.par == cur.p[v]) ? 0.03 : 0.30;\n                if (c.par != -1 && cur.p[v] != -1) {\n                    if (A[c.par] + 2 < A[cur.p[v]]) pr += 0.18;\n                    if ((int)cur.ch[c.par].size() + 1 < (int)cur.ch[cur.p[v]].size()) pr += 0.08;\n                }\n                if (rng.next_double() < pr) accept = true;\n            } else {\n                double p = (elapsed() - phaseStart) / max(1e-9, timeLimit - phaseStart);\n                p = max(0.0, min(1.0, p));\n                double temp = T0 * pow(ratio, p);\n\n                double x = (double)c.gain / temp;\n                if (x > -25.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n            apply_move(v, c.par, c.delta, c.gain);\n\n            if ((iter & 8191LL) == 0) {\n                if (cur.extra + 12000 < best.extra) {\n                    cur = best;\n                    init_subinfo(cur, subA, subMax);\n                    refresh_ordSub();\n                }\n            }\n            if ((iter & 32767LL) == 0 && elapsed() + 0.01 < timeLimit) {\n                composite_unblock(1);\n            }\n        }\n\n        composite_unblock(1);\n        greedy_positive(2);\n    }\n\n    Forest tree_optimize(const vector<int>& baseDepth, double endTime) {\n        vector<int> d = baseDepth;\n        repair_depth(d);\n\n        auto make_init = [&](int mode, bool noisy) {\n            Forest f = build_forest_from_depth(d, mode);\n            normalize_parents(f, 1, mode == 0);\n            leafify_highA(f, (mode == 1 ? 280 : 240), 1);\n            trim_deep_branches(f, (mode == 1 ? 320 : 280), 1);\n            if (noisy) random_neutral_rewire(f, (mode == 2 ? 120 : 90));\n            return f;\n        };\n\n        Forest best = make_init(0, false);\n        if (elapsed() >= endTime) return best;\n\n        Forest cur = best;\n        double now = elapsed();\n        double seg1 = now + (endTime - now) * 0.45;\n        run_tree_sa_fast(cur, best, seg1);\n\n        if (elapsed() < endTime - 0.05) {\n            Forest alt1 = make_init(1, true);\n            double now2 = elapsed();\n            double seg2 = now2 + (endTime - now2) * 0.56;\n            run_tree_sa_fast(alt1, best, seg2);\n        }\n\n        if (elapsed() < endTime - 0.03) {\n            Forest alt2 = make_init(2, true);\n            run_tree_sa_fast(alt2, best, endTime - 0.01);\n        }\n\n        if (elapsed() < endTime - 0.005) {\n            Forest fin = best;\n            random_neutral_rewire(fin, 40);\n            run_tree_sa_fast(fin, best, endTime);\n        }\n\n        return best;\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}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 20;\nconstexpr int MAXC = 80;\nconstexpr int MAXD = 20;\nconstexpr int MAXM = 64;\n\nstruct Chain {\n    char dir, rev;\n    int idx;\n};\nstruct Option {\n    int chain, req;\n};\nstruct State {\n    array<uint8_t, MAXC> d{};\n    array<uint8_t, MAXM> sat{};\n    uint64_t unsatMask = 0;\n    int cost = 0; // 2 * sum(depth)\n};\nstruct UPlan {\n    array<uint8_t, MAXC> in{};\n    vector<int> ord;\n    int save = 0; // sum depth on ord\n};\n\nclass Solver {\n    using Grid = array<array<char, MAXN>, MAXN>;\n    using Op = pair<char,int>;\n\n    int N, Cn, M;\n    vector<string> board;\n    Grid initGrid{};\n    int initialFuku = 0;\n\n    array<Chain, MAXC> chains{};\n    vector<vector<Option>> opts;\n    vector<pair<int,int>> oniPos;\n\n    array<int, MAXC> cap{};\n    array<array<uint64_t, MAXD + 1>, MAXC> eqMask{};\n    array<array<uint64_t, MAXD + 1>, MAXC> leMask{};\n    array<vector<int>, MAXC> usefulDepths{};\n\n    uint64_t fullMask = 0;\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver(int n, vector<string> b) : N(n), Cn(4*n), board(move(b)) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        build();\n    }\n\n    vector<Op> solve() {\n        st = chrono::steady_clock::now();\n\n        // Rebalanced timings (seconds)\n        const double depthEnd   = 1.48;\n        const double unpair1End = 1.66;\n        const double shrinkEnd  = 1.78;\n        const double unpair2End = 1.86;\n        const double pruneEnd   = 1.97;\n\n        State s = optimizeDepth(depthEnd);\n        State guaranteed = s; // fallback-safe base\n\n        UPlan plan = optimizeUnpair(s, unpair1End, nullptr);\n\n        if (now() < shrinkEnd) {\n            exactDepthShrink(s, plan, shrinkEnd);\n        }\n\n        if (now() < unpair2End) {\n            plan = optimizeUnpair(s, unpair2End, &plan);\n        }\n\n        sanitizePlan(plan, s);\n        vector<Op> ans = buildOps(s, plan);\n\n        if (now() < pruneEnd) {\n            pruneOps(ans, pruneEnd);\n        }\n\n        if (!checkOpsValid(ans)) {\n            UPlan empty = emptyPlan();\n            vector<Op> safe = buildOps(guaranteed, empty);\n            if (checkOpsValid(safe)) {\n                ans.swap(safe);\n            } else {\n                vector<Op> fb = fallbackPerOni();\n                if (checkOpsValid(fb)) ans.swap(fb);\n                else ans = fb;\n            }\n        }\n\n        if ((int)ans.size() > 4 * N * N) {\n            vector<Op> fb = fallbackPerOni();\n            if (checkOpsValid(fb)) ans.swap(fb);\n        }\n\n        return ans;\n    }\n\nprivate:\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline double rand01() {\n        return (double)(rng() & ((1u << 24) - 1)) / (double)(1u << 24);\n    }\n\n    inline int idUp(int j) const { return j; }\n    inline int idDown(int j) const { return N + j; }\n    inline int idLeft(int i) const { return 2 * N + i; }\n    inline int idRight(int i) const { return 3 * N + i; }\n\n    void build() {\n        for (int i = 0; i < MAXN; i++) for (int j = 0; j < MAXN; j++) initGrid[i][j] = '.';\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            initGrid[i][j] = board[i][j];\n            if (board[i][j] == 'x') oniPos.push_back({i, j});\n            if (board[i][j] == 'o') initialFuku++;\n        }\n        M = (int)oniPos.size();\n        opts.assign(M, {});\n\n        vector<int> upSafe(N, N), downSafe(N, N), leftSafe(N, N), rightSafe(N, N);\n\n        for (int j = 0; j < N; j++) {\n            for (int i = 0; i < N; i++) if (board[i][j] == 'o') { upSafe[j] = i; break; }\n            for (int i = N - 1; i >= 0; i--) if (board[i][j] == 'o') { downSafe[j] = N - 1 - i; break; }\n        }\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) if (board[i][j] == 'o') { leftSafe[i] = j; break; }\n            for (int j = N - 1; j >= 0; j--) if (board[i][j] == 'o') { rightSafe[i] = N - 1 - j; break; }\n        }\n\n        for (int j = 0; j < N; j++) {\n            chains[idUp(j)] = {'U', 'D', j};\n            chains[idDown(j)] = {'D', 'U', j};\n        }\n        for (int i = 0; i < N; i++) {\n            chains[idLeft(i)] = {'L', 'R', i};\n            chains[idRight(i)] = {'R', 'L', i};\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto [r, c] = oniPos[m];\n            int reqU = r + 1, reqD = N - r, reqL = c + 1, reqR = N - c;\n            if (reqU <= upSafe[c]) opts[m].push_back({idUp(c), reqU});\n            if (reqD <= downSafe[c]) opts[m].push_back({idDown(c), reqD});\n            if (reqL <= leftSafe[r]) opts[m].push_back({idLeft(r), reqL});\n            if (reqR <= rightSafe[r]) opts[m].push_back({idRight(r), reqR});\n            if (opts[m].empty()) opts[m].push_back({idUp(c), min(reqU, N)}); // safety\n        }\n\n        for (int c = 0; c < MAXC; c++) {\n            cap[c] = 0;\n            usefulDepths[c].clear();\n            for (int d = 0; d <= MAXD; d++) {\n                eqMask[c][d] = 0;\n                leMask[c][d] = 0;\n            }\n        }\n\n        for (int m = 0; m < M; m++) {\n            for (auto &op : opts[m]) eqMask[op.chain][op.req] |= (1ULL << m);\n        }\n\n        for (int c = 0; c < Cn; c++) {\n            leMask[c][0] = 0;\n            for (int d = 1; d <= N; d++) {\n                leMask[c][d] = leMask[c][d - 1] | eqMask[c][d];\n                if (eqMask[c][d]) {\n                    usefulDepths[c].push_back(d);\n                    cap[c] = d;\n                }\n            }\n        }\n\n        fullMask = (M == 64 ? ~0ULL : ((1ULL << M) - 1ULL));\n    }\n\n    // ---------- State ----------\n    State makeZeroState() const {\n        State s;\n        s.d.fill(0);\n        s.sat.fill(0);\n        s.unsatMask = fullMask;\n        s.cost = 0;\n        return s;\n    }\n\n    inline void incChain(State &s, int c) {\n        int nd = (int)s.d[c] + 1;\n        uint64_t bits = eqMask[c][nd];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            if (s.sat[m]++ == 0) s.unsatMask &= ~(1ULL << m);\n        }\n        s.d[c] = (uint8_t)nd;\n        s.cost += 2;\n    }\n\n    inline void decChain(State &s, int c) {\n        int t = (int)s.d[c];\n        uint64_t bits = eqMask[c][t];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            uint8_t v = --s.sat[m];\n            if (v == 0) s.unsatMask |= (1ULL << m);\n        }\n        s.d[c] = (uint8_t)(t - 1);\n        s.cost -= 2;\n    }\n\n    inline void setChain(State &s, int c, int nd) {\n        while ((int)s.d[c] < nd) incChain(s, c);\n        while ((int)s.d[c] > nd) decChain(s, c);\n    }\n\n    State fromDepth(const array<uint8_t, MAXC>& depth) {\n        State s = makeZeroState();\n        for (int c = 0; c < Cn; c++) {\n            for (int t = 0; t < (int)depth[c]; t++) incChain(s, c);\n        }\n        return s;\n    }\n\n    void reduceDepth(State &s, bool randomOrder) {\n        array<int, MAXC> ord{};\n        for (int i = 0; i < Cn; i++) ord[i] = i;\n        if (randomOrder) shuffle(ord.begin(), ord.begin() + Cn, rng);\n\n        for (int ii = 0; ii < Cn; ii++) {\n            int c = ord[ii];\n            while ((int)s.d[c] > 0) {\n                int t = (int)s.d[c];\n                uint64_t bits = eqMask[c][t];\n                bool ok = true;\n                while (bits) {\n                    int m = __builtin_ctzll(bits);\n                    bits &= bits - 1;\n                    if (s.sat[m] == 1) { ok = false; break; }\n                }\n                if (!ok) break;\n                decChain(s, c);\n            }\n        }\n    }\n\n    bool exactRepairSmall(State &s) {\n        int k = __builtin_popcountll(s.unsatMask);\n        if (k == 0) return true;\n        if (k > 10) return false;\n\n        vector<int> uns;\n        uns.reserve(k);\n        int loc[MAXM];\n        for (int i = 0; i < MAXM; i++) loc[i] = -1;\n\n        uint64_t bits = s.unsatMask;\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            loc[m] = (int)uns.size();\n            uns.push_back(m);\n        }\n\n        int S = 1 << k;\n        const int INF = 1e9;\n\n        static int dp[1 << 10], ndp[1 << 10];\n        struct Parent { uint16_t prev; uint8_t dep; uint8_t used; };\n        static Parent par[MAXC + 1][1 << 10];\n\n        for (int mask = 0; mask < S; mask++) dp[mask] = INF;\n        dp[0] = 0;\n\n        for (int c = 0; c < Cn; c++) {\n            for (int mask = 0; mask < S; mask++) ndp[mask] = INF;\n\n            for (int mask = 0; mask < S; mask++) {\n                if (dp[mask] < ndp[mask]) {\n                    ndp[mask] = dp[mask];\n                    par[c + 1][mask] = {(uint16_t)mask, 0, 0};\n                }\n            }\n\n            if ((int)s.d[c] < cap[c]) {\n                static int bestCost[1 << 10];\n                static uint8_t bestDep[1 << 10];\n                for (int i = 0; i < S; i++) { bestCost[i] = INF; bestDep[i] = 0; }\n\n                for (int r = (int)s.d[c] + 1; r <= cap[c]; r++) {\n                    uint64_t gm = leMask[c][r] & s.unsatMask;\n                    if (!gm) continue;\n                    int lm = 0;\n                    uint64_t t = gm;\n                    while (t) {\n                        int m = __builtin_ctzll(t);\n                        t &= t - 1;\n                        lm |= (1 << loc[m]);\n                    }\n                    int add = r - (int)s.d[c];\n                    if (add < bestCost[lm]) {\n                        bestCost[lm] = add;\n                        bestDep[lm] = (uint8_t)r;\n                    }\n                }\n\n                vector<tuple<int,int,uint8_t>> cand;\n                cand.reserve(S);\n                for (int lm = 1; lm < S; lm++) if (bestCost[lm] < INF) {\n                    cand.emplace_back(lm, bestCost[lm], bestDep[lm]);\n                }\n\n                for (int mask = 0; mask < S; mask++) {\n                    if (dp[mask] >= INF) continue;\n                    for (auto [lm, add, dep] : cand) {\n                        int nm = mask | lm;\n                        int val = dp[mask] + add;\n                        if (val < ndp[nm]) {\n                            ndp[nm] = val;\n                            par[c + 1][nm] = {(uint16_t)mask, dep, 1};\n                        }\n                    }\n                }\n            }\n\n            for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n        }\n\n        int target = S - 1;\n        if (dp[target] >= INF) return false;\n\n        array<uint8_t, MAXC> tgt = s.d;\n        int mask = target;\n        for (int c = Cn; c >= 1; c--) {\n            auto p = par[c][mask];\n            if (p.used) {\n                int chain = c - 1;\n                tgt[chain] = max<int>(tgt[chain], p.dep);\n            }\n            mask = p.prev;\n        }\n\n        for (int c = 0; c < Cn; c++) setChain(s, c, tgt[c]);\n        return (s.unsatMask == 0);\n    }\n\n    void greedyRepair(State &s, bool randomized) {\n        while (s.unsatMask) {\n            int unsCnt = __builtin_popcountll(s.unsatMask);\n            if (unsCnt <= 10) {\n                if (exactRepairSmall(s)) return;\n            }\n\n            double bestScore = -1e100;\n            int bc = -1, br = -1;\n            int bg = -1, bdelta = 1e9;\n\n            for (int c = 0; c < Cn; c++) {\n                int dc = (int)s.d[c];\n                if (dc >= cap[c]) continue;\n                for (int r : usefulDepths[c]) {\n                    if (r <= dc) continue;\n                    uint64_t gainMask = leMask[c][r] & s.unsatMask;\n                    int g = __builtin_popcountll(gainMask);\n                    if (g == 0) continue;\n                    int delta = r - dc;\n                    double score = (double)g / (double)delta;\n                    if (randomized) score += (double)(rng() & 1023) * 1e-6;\n\n                    if (score > bestScore + 1e-12 ||\n                        (fabs(score - bestScore) <= 1e-12 &&\n                         (g > bg || (g == bg && delta < bdelta)))) {\n                        bestScore = score;\n                        bc = c; br = r; bg = g; bdelta = delta;\n                    }\n                }\n            }\n\n            if (bc == -1) {\n                int m = __builtin_ctzll(s.unsatMask);\n                int bestDelta = 1e9;\n                for (auto &op : opts[m]) {\n                    int delta = max(0, op.req - (int)s.d[op.chain]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bc = op.chain;\n                        br = op.req;\n                    }\n                }\n                if (bc == -1) break;\n            }\n\n            setChain(s, bc, br);\n        }\n    }\n\n    // ---------- objective proxy ----------\n    int rowSave(const State &s) const {\n        int sv = 0;\n        for (int i = 0; i < N; i++) {\n            int l = s.d[idLeft(i)], r = s.d[idRight(i)];\n            if (l == 0 || r == 0) sv += l + r;\n            else sv += max(l, r);\n        }\n        return sv;\n    }\n    int colSave(const State &s) const {\n        int sv = 0;\n        for (int j = 0; j < N; j++) {\n            int u = s.d[idUp(j)], d = s.d[idDown(j)];\n            if (u == 0 || d == 0) sv += u + d;\n            else sv += max(u, d);\n        }\n        return sv;\n    }\n    int estimateMoves(const State &s) const {\n        return s.cost - max(rowSave(s), colSave(s));\n    }\n\n    State baselineMinReq() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            depth[op.chain] = max<int>(depth[op.chain], op.req);\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, false);\n        return s;\n    }\n\n    State trialAssign() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n        stable_sort(ord.begin(), ord.end(),\n                    [&](int a, int b) { return opts[a].size() < opts[b].size(); });\n\n        for (int m : ord) {\n            int choose = 0;\n            if ((int)(rng() % 100) < 8) {\n                choose = (int)(rng() % opts[m].size());\n            } else {\n                int bestKey = 1e9;\n                vector<int> cand;\n                for (int i = 0; i < (int)opts[m].size(); i++) {\n                    auto op = opts[m][i];\n                    int delta = max(0, op.req - (int)depth[op.chain]);\n                    int key = delta * 64 + op.req;\n                    if (key < bestKey) {\n                        bestKey = key;\n                        cand.clear();\n                        cand.push_back(i);\n                    } else if (key == bestKey) {\n                        cand.push_back(i);\n                    }\n                }\n                choose = cand[(int)(rng() % cand.size())];\n            }\n\n            auto op = opts[m][choose];\n            if (op.req > depth[op.chain]) depth[op.chain] = op.req;\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, true);\n        if ((rng() % 100) < 30) reduceDepth(s, true);\n        return s;\n    }\n\n    State trialCover(bool randomized) {\n        State s = makeZeroState();\n        greedyRepair(s, randomized);\n        if (s.unsatMask == 0) {\n            reduceDepth(s, true);\n            if (randomized && (rng() % 100) < 30) reduceDepth(s, true);\n        }\n        return s;\n    }\n\n    int pickNonZeroChain(const State &s) {\n        for (int t = 0; t < 24; t++) {\n            int c = (int)(rng() % Cn);\n            if (s.d[c] > 0) return c;\n        }\n        int cnt = 0;\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) cnt++;\n        if (cnt == 0) return -1;\n        int k = (int)(rng() % cnt);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) if (k-- == 0) return c;\n        return -1;\n    }\n\n    State optimizeDepth(double endTime) {\n        State best = baselineMinReq();\n        int bestObj = estimateMoves(best);\n\n        State c0 = trialCover(false);\n        if (c0.unsatMask == 0) {\n            int c0Obj = estimateMoves(c0);\n            if (c0Obj < bestObj || (c0Obj == bestObj && c0.cost < best.cost)) {\n                best = c0;\n                bestObj = c0Obj;\n            }\n        }\n\n        int itInit = 0;\n        while (now() < 0.30) {\n            State cand = (itInit % 2 == 0 ? trialAssign() : trialCover(true));\n            itInit++;\n            if (cand.unsatMask) continue;\n            int obj = estimateMoves(cand);\n            if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = obj;\n            }\n        }\n\n        State cur = best;\n        int curObj = bestObj;\n        int iter = 0;\n\n        while (now() < endTime) {\n            iter++;\n            State cand = cur;\n\n            int k = 1 + (int)(rng() % 4);\n            if ((rng() % 100) < 20) k++;\n\n            for (int t = 0; t < k; t++) {\n                int c = pickNonZeroChain(cand);\n                if (c < 0) break;\n                int old = cand.d[c];\n                int nd;\n                int r = (int)(rng() % 100);\n                if (r < 55) nd = old - 1;\n                else if (r < 85) {\n                    int dec = 1 + (int)(rng() % max(1, min(4, old)));\n                    nd = max(0, old - dec);\n                } else {\n                    nd = (int)(rng() % (old + 1));\n                }\n                setChain(cand, c, nd);\n            }\n\n            if ((rng() % 100) < 10) {\n                int c = (int)(rng() % Cn);\n                if ((int)cand.d[c] < cap[c] && cap[c] > 0) {\n                    int nd = min(cap[c], (int)cand.d[c] + 1 + (int)(rng() % 3));\n                    setChain(cand, c, nd);\n                }\n            }\n\n            greedyRepair(cand, true);\n            if (cand.unsatMask) continue;\n\n            reduceDepth(cand, true);\n            if ((rng() % 100) < 35) reduceDepth(cand, true);\n\n            int candObj = estimateMoves(cand);\n            double prog = min(1.0, now() / endTime);\n            double temp = 5.0 * pow(0.03 / 5.0, prog);\n            int delta = candObj - curObj;\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-delta / temp);\n                if (rand01() < prob) accept = true;\n            }\n\n            if (accept) {\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if (candObj < bestObj || (candObj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = candObj;\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if ((iter % 300) == 0 && (rng() % 100) < 40) {\n                cur = best;\n                curObj = bestObj;\n            }\n        }\n\n        vector<int> ord(Cn);\n        iota(ord.begin(), ord.end(), 0);\n        auto sortOrd = [&]() {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return best.d[a] > best.d[b];\n            });\n        };\n        sortOrd();\n\n        bool improved = true;\n        while (improved && now() < endTime) {\n            improved = false;\n            for (int c : ord) {\n                if (now() >= endTime) break;\n                if (best.d[c] == 0) continue;\n                State cand = best;\n                setChain(cand, c, 0);\n                greedyRepair(cand, false);\n                if (cand.unsatMask) continue;\n                reduceDepth(cand, true);\n                int obj = estimateMoves(cand);\n                if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                    best = cand;\n                    bestObj = obj;\n                    improved = true;\n                    sortOrd();\n                    break;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    // ---------- simulation ----------\n    inline bool applyShift(Grid &g, char d, int p, int &oniLeft) const {\n        char out = '.';\n        if (d == 'L') {\n            out = g[p][0];\n            for (int j = 0; j + 1 < N; j++) g[p][j] = g[p][j + 1];\n            g[p][N - 1] = '.';\n        } else if (d == 'R') {\n            out = g[p][N - 1];\n            for (int j = N - 1; j >= 1; j--) g[p][j] = g[p][j - 1];\n            g[p][0] = '.';\n        } else if (d == 'U') {\n            out = g[0][p];\n            for (int i = 0; i + 1 < N; i++) g[i][p] = g[i + 1][p];\n            g[N - 1][p] = '.';\n        } else { // D\n            out = g[N - 1][p];\n            for (int i = N - 1; i >= 1; i--) g[i][p] = g[i - 1][p];\n            g[0][p] = '.';\n        }\n\n        if (out == 'o') return false;\n        if (out == 'x') oniLeft--;\n        return true;\n    }\n\n    bool checkOpsValid(const vector<Op> &ops) const {\n        if ((int)ops.size() > 4 * N * N) return false;\n        Grid g = initGrid;\n        int oniLeft = M;\n        for (auto [d, p] : ops) {\n            if (!applyShift(g, d, p, oniLeft)) return false;\n        }\n        return oniLeft == 0;\n    }\n\n    // ---------- unpair plan ----------\n    UPlan emptyPlan() const {\n        UPlan p;\n        p.in.fill(0);\n        p.ord.clear();\n        p.save = 0;\n        return p;\n    }\n\n    int computeSave(const State &s, const UPlan &p) const {\n        int sv = 0;\n        for (int c : p.ord) sv += s.d[c];\n        return sv;\n    }\n\n    void sanitizePlan(UPlan &p, const State &s) const {\n        array<uint8_t, MAXC> used{};\n        used.fill(0);\n\n        vector<int> v;\n        v.reserve(p.ord.size());\n\n        for (int c : p.ord) {\n            if (c < 0 || c >= Cn) continue;\n            if (used[c]) continue;\n            if (!p.in[c]) continue;\n            if (s.d[c] == 0) continue;\n            used[c] = 1;\n            v.push_back(c);\n        }\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c] && s.d[c] > 0 && !used[c]) {\n                used[c] = 1;\n                v.push_back(c);\n            }\n        }\n\n        p.ord.swap(v);\n        p.in.fill(0);\n        for (int c : p.ord) p.in[c] = 1;\n        p.save = computeSave(s, p);\n    }\n\n    UPlan makeRowPlan(const State &s, bool tieRight) const {\n        UPlan p = emptyPlan();\n        for (int i = 0; i < N; i++) {\n            int lc = idLeft(i), rc = idRight(i);\n            int l = s.d[lc], r = s.d[rc];\n            if (l == 0 && r == 0) continue;\n            int ch;\n            if (l > r) ch = lc;\n            else if (r > l) ch = rc;\n            else ch = tieRight ? rc : lc;\n            if (s.d[ch] > 0) {\n                p.ord.push_back(ch);\n                p.in[ch] = 1;\n            }\n        }\n        p.save = computeSave(s, p);\n        return p;\n    }\n\n    UPlan makeColPlan(const State &s, bool tieDown) const {\n        UPlan p = emptyPlan();\n        for (int j = 0; j < N; j++) {\n            int uc = idUp(j), dc = idDown(j);\n            int u = s.d[uc], d = s.d[dc];\n            if (u == 0 && d == 0) continue;\n            int ch;\n            if (u > d) ch = uc;\n            else if (d > u) ch = dc;\n            else ch = tieDown ? dc : uc;\n            if (s.d[ch] > 0) {\n                p.ord.push_back(ch);\n                p.in[ch] = 1;\n            }\n        }\n        p.save = computeSave(s, p);\n        return p;\n    }\n\n    int pickNotIn(const UPlan &p, const vector<int> &active) {\n        if ((int)p.ord.size() >= (int)active.size()) return -1;\n        for (int t = 0; t < 24; t++) {\n            int c = active[(int)(rng() % active.size())];\n            if (!p.in[c]) return c;\n        }\n        for (int c : active) if (!p.in[c]) return c;\n        return -1;\n    }\n\n    bool checkPlanValid(const State &s, const UPlan &p) const {\n        if (s.cost - p.save > 4 * N * N) return false;\n        Grid g = initGrid;\n        int oniLeft = M;\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c]) continue;\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].dir, chains[c].idx, oniLeft)) return false;\n            }\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].rev, chains[c].idx, oniLeft)) return false;\n            }\n        }\n\n        for (int c : p.ord) {\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].dir, chains[c].idx, oniLeft)) return false;\n            }\n        }\n\n        return oniLeft == 0;\n    }\n\n    UPlan optimizeUnpair(const State &s, double endTime, const UPlan *seed) {\n        vector<UPlan> seeds;\n        seeds.reserve(8);\n        seeds.push_back(emptyPlan());\n        seeds.push_back(makeRowPlan(s, false));\n        seeds.push_back(makeRowPlan(s, true));\n        seeds.push_back(makeColPlan(s, false));\n        seeds.push_back(makeColPlan(s, true));\n        if (seed) seeds.push_back(*seed);\n\n        UPlan best = emptyPlan();\n        bool hasBest = false;\n\n        for (auto &p : seeds) {\n            if (now() >= endTime) break;\n            sanitizePlan(p, s);\n            if (checkPlanValid(s, p)) {\n                if (!hasBest || p.save > best.save) {\n                    best = p;\n                    hasBest = true;\n                }\n            }\n        }\n        if (!hasBest) return emptyPlan();\n\n        vector<int> active;\n        active.reserve(Cn);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) active.push_back(c);\n        if (active.empty()) return best;\n\n        UPlan cur = best;\n        double greedyEnd = min(endTime, now() + (endTime - now()) * 0.40);\n\n        while (now() < greedyEnd) {\n            bool improved = false;\n            vector<int> cand;\n            cand.reserve(active.size());\n            for (int c : active) if (!cur.in[c]) cand.push_back(c);\n            if (cand.empty()) break;\n\n            shuffle(cand.begin(), cand.end(), rng);\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (s.d[a] != s.d[b]) return s.d[a] > s.d[b];\n                return a < b;\n            });\n\n            for (int c : cand) {\n                if (now() >= greedyEnd) break;\n                int sz = (int)cur.ord.size();\n\n                vector<int> pos;\n                pos.reserve(sz + 1);\n                pos.push_back(sz);\n                if (sz > 0) pos.push_back(0);\n                for (int i = 1; i < sz; i++) pos.push_back(i);\n                if ((int)pos.size() > 2) shuffle(pos.begin() + 2, pos.end(), rng);\n\n                bool ok = false;\n                for (int pidx : pos) {\n                    UPlan q = cur;\n                    q.ord.insert(q.ord.begin() + pidx, c);\n                    q.in[c] = 1;\n                    q.save = computeSave(s, q);\n                    if (checkPlanValid(s, q)) {\n                        cur = move(q);\n                        if (cur.save > best.save) best = cur;\n                        improved = true;\n                        ok = true;\n                        break;\n                    }\n                }\n                if (ok) break;\n            }\n\n            if (!improved) break;\n        }\n\n        cur = best;\n        double saStart = now();\n\n        while (now() < endTime) {\n            UPlan cand = cur;\n            bool moved = false;\n            int typ = (int)(rng() % 100);\n            int sz = (int)cand.ord.size();\n\n            if (typ < 35) { // add\n                int c = pickNotIn(cand, active);\n                if (c != -1) {\n                    int pos = (int)(rng() % (sz + 1));\n                    cand.ord.insert(cand.ord.begin() + pos, c);\n                    cand.in[c] = 1;\n                    moved = true;\n                }\n            } else if (typ < 55) { // remove\n                if (sz > 0) {\n                    int idx = (int)(rng() % sz);\n                    int c = cand.ord[idx];\n                    cand.ord.erase(cand.ord.begin() + idx);\n                    cand.in[c] = 0;\n                    moved = true;\n                }\n            } else if (typ < 75) { // swap\n                if (sz >= 2) {\n                    int i = (int)(rng() % sz), j = (int)(rng() % sz);\n                    if (i != j) {\n                        swap(cand.ord[i], cand.ord[j]);\n                        moved = true;\n                    }\n                }\n            } else if (typ < 90) { // move\n                if (sz >= 2) {\n                    int i = (int)(rng() % sz);\n                    int c = cand.ord[i];\n                    cand.ord.erase(cand.ord.begin() + i);\n                    int pos = (int)(rng() % sz); // after erase size is sz-1\n                    cand.ord.insert(cand.ord.begin() + pos, c);\n                    moved = true;\n                }\n            } else { // replace\n                if (sz > 0) {\n                    int idx = (int)(rng() % sz);\n                    int oldc = cand.ord[idx];\n                    cand.ord.erase(cand.ord.begin() + idx);\n                    cand.in[oldc] = 0;\n                    int nc = pickNotIn(cand, active);\n                    if (nc != -1) {\n                        int pos = (int)(rng() % ((int)cand.ord.size() + 1));\n                        cand.ord.insert(cand.ord.begin() + pos, nc);\n                        cand.in[nc] = 1;\n                        moved = true;\n                    } else {\n                        cand.ord.insert(cand.ord.begin() + idx, oldc);\n                        cand.in[oldc] = 1;\n                    }\n                }\n            }\n\n            if (!moved) continue;\n\n            cand.save = computeSave(s, cand);\n            if (!checkPlanValid(s, cand)) continue;\n\n            int delta = cand.save - cur.save;\n            double denom = max(1e-9, endTime - saStart);\n            double rem = (endTime - now()) / denom;\n            rem = max(0.0, min(1.0, rem));\n            double temp = 1.5 * rem + 0.03;\n\n            if (delta >= 0 || rand01() < exp((double)delta / temp)) {\n                cur = cand;\n            }\n            if (cand.save > best.save) best = cand;\n        }\n\n        sanitizePlan(best, s);\n        return best;\n    }\n\n    void exactDepthShrink(State &s, UPlan &p, double endTime) {\n        sanitizePlan(p, s);\n        if (!checkPlanValid(s, p)) return;\n\n        bool improved = true;\n        while (improved && now() < endTime) {\n            improved = false;\n            vector<int> ord(Cn);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b){ return s.d[a] > s.d[b]; });\n\n            for (int c : ord) {\n                if (now() >= endTime) break;\n                while (s.d[c] > 0 && now() < endTime) {\n                    State cand = s;\n                    setChain(cand, c, (int)s.d[c] - 1);\n\n                    UPlan q = p;\n                    if (q.in[c] && cand.d[c] == 0) {\n                        q.in[c] = 0;\n                        for (int i = 0; i < (int)q.ord.size(); i++) {\n                            if (q.ord[i] == c) {\n                                q.ord.erase(q.ord.begin() + i);\n                                break;\n                            }\n                        }\n                    }\n                    sanitizePlan(q, cand);\n\n                    if (checkPlanValid(cand, q)) {\n                        s = move(cand);\n                        p = move(q);\n                        improved = true;\n                    } else break;\n                }\n            }\n        }\n\n        sanitizePlan(p, s);\n    }\n\n    vector<Op> buildOps(const State &s, const UPlan &p) const {\n        vector<Op> ops;\n        ops.reserve(max(0, s.cost - p.save) + 16);\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c]) continue;\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].rev, chains[c].idx});\n        }\n        for (int c : p.ord) {\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n        }\n        return ops;\n    }\n\n    bool tryEraseRange(vector<Op> &ops, int l, int r) {\n        if (l < 0 || r > (int)ops.size() || l >= r) return false;\n        vector<Op> cand;\n        cand.reserve((int)ops.size() - (r - l));\n        cand.insert(cand.end(), ops.begin(), ops.begin() + l);\n        cand.insert(cand.end(), ops.begin() + r, ops.end());\n        if (checkOpsValid(cand)) {\n            ops.swap(cand);\n            return true;\n        }\n        return false;\n    }\n\n    bool tryEraseIndices(vector<Op> &ops, vector<int> idx) {\n        if (idx.empty()) return false;\n        sort(idx.begin(), idx.end());\n        idx.erase(unique(idx.begin(), idx.end()), idx.end());\n        if (idx.front() < 0 || idx.back() >= (int)ops.size()) return false;\n\n        vector<Op> cand;\n        cand.reserve((int)ops.size() - (int)idx.size());\n        int p = 0;\n        for (int i = 0; i < (int)ops.size(); i++) {\n            if (p < (int)idx.size() && idx[p] == i) { p++; continue; }\n            cand.push_back(ops[i]);\n        }\n\n        if (checkOpsValid(cand)) {\n            ops.swap(cand);\n            return true;\n        }\n        return false;\n    }\n\n    void pruneOps(vector<Op> &ops, double endTime) {\n        if (!checkOpsValid(ops)) return;\n\n        // Deterministic phase: single / pair / full-run deletions\n        while (now() < endTime) {\n            bool changed = false;\n\n            // backward single deletion\n            for (int i = (int)ops.size() - 1; i >= 0 && now() < endTime; --i) {\n                if (tryEraseRange(ops, i, i + 1)) changed = true;\n            }\n\n            // backward pair deletion\n            for (int i = (int)ops.size() - 2; i >= 0 && now() < endTime; --i) {\n                if (tryEraseRange(ops, i, i + 2)) changed = true;\n            }\n\n            // delete whole contiguous runs (same op)\n            bool runChanged = true;\n            while (runChanged && now() < endTime) {\n                runChanged = false;\n                int n = (int)ops.size();\n                vector<tuple<int,int,int>> runs; // (len,l,r)\n                runs.reserve(n);\n\n                for (int l = 0; l < n; ) {\n                    int r = l + 1;\n                    while (r < n && ops[r] == ops[l]) r++;\n                    runs.emplace_back(r - l, l, r);\n                    l = r;\n                }\n\n                sort(runs.begin(), runs.end(),\n                     [](const auto &a, const auto &b) {\n                         if (get<0>(a) != get<0>(b)) return get<0>(a) > get<0>(b);\n                         return get<1>(a) > get<1>(b);\n                     });\n\n                for (auto [len, l, r] : runs) {\n                    if (now() >= endTime) break;\n                    if (len < 3) break;\n                    if (tryEraseRange(ops, l, r)) {\n                        runChanged = true;\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        // Random block/index deletion phase (captures multi-op dependencies)\n        int fail = 0;\n        while (now() < endTime) {\n            int n = (int)ops.size();\n            if (n == 0) break;\n\n            bool ok = false;\n            int typ = (int)(rng() % 100);\n\n            if (typ < 70) {\n                int maxLen = min(20, n);\n                int rr = (int)(rng() % 100);\n                int len;\n                if (rr < 60) {\n                    int lim = min(6, maxLen);\n                    len = 1 + (int)(rng() % lim);\n                } else if (rr < 90) {\n                    int lim = min(10, maxLen);\n                    len = 1 + (int)(rng() % lim);\n                } else {\n                    len = 1 + (int)(rng() % maxLen);\n                }\n                int l = (int)(rng() % (n - len + 1));\n                ok = tryEraseRange(ops, l, l + len);\n\n            } else if (typ < 90) {\n                int i = (int)(rng() % n);\n                int l = i, r = i + 1;\n                while (l > 0 && ops[l - 1] == ops[i]) l--;\n                while (r < n && ops[r] == ops[i]) r++;\n                if (r - l >= 2) {\n                    ok = tryEraseRange(ops, l, r);\n                } else {\n                    int len = min(2 + (int)(rng() % 5), n);\n                    int ll = (int)(rng() % (n - len + 1));\n                    ok = tryEraseRange(ops, ll, ll + len);\n                }\n\n            } else {\n                int k = min(n, 2 + (int)(rng() % 3)); // 2..4\n                vector<int> idx(n);\n                iota(idx.begin(), idx.end(), 0);\n                shuffle(idx.begin(), idx.end(), rng);\n                idx.resize(k);\n                ok = tryEraseIndices(ops, idx);\n            }\n\n            if (ok) {\n                fail = 0;\n                // quick local single cleanup\n                for (int t = 0; t < 6 && now() < endTime; t++) {\n                    if (ops.empty()) break;\n                    int i = (int)(rng() % ops.size());\n                    tryEraseRange(ops, i, i + 1);\n                }\n            } else {\n                fail++;\n                if (fail > 4000 && now() > endTime - 0.02) break;\n            }\n        }\n\n        // final quick single pass\n        for (int rep = 0; rep < 2 && now() < endTime; rep++) {\n            bool any = false;\n            for (int i = (int)ops.size() - 1; i >= 0 && now() < endTime; --i) {\n                if (tryEraseRange(ops, i, i + 1)) any = true;\n            }\n            if (!any) break;\n        }\n    }\n\n    vector<Op> fallbackPerOni() const {\n        vector<Op> ops;\n        ops.reserve(1600);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            const auto& ch = chains[op.chain];\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.dir, ch.idx});\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.rev, ch.idx});\n        }\n        return ops;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    Solver solver(N, C);\n    auto ans = solver.solve();\n\n    for (auto [d, p] : ans) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\nstatic inline long long absl(long long x) { return x < 0 ? -x : x; }\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct State {\n    array<int, MAXN> a{}, b{};\n    array<int, MAXN> cnt{}, useA{}, useB{};\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstatic int g_cost[MAXN][MAXN];\n\nstatic inline int sample_weighted(const uint64_t* w, int n, RNG& rng) {\n    uint64_t sum = 0;\n    for (int i = 0; i < n; i++) sum += w[i];\n    if (sum == 0) return rng.nextInt(n);\n    uint64_t r = rng.nextU64() % sum;\n    uint64_t acc = 0;\n    for (int i = 0; i < n; i++) {\n        acc += w[i];\n        if (r < acc) return i;\n    }\n    return n - 1;\n}\n\nstatic inline void shuffle_order(array<int, MAXN>& ord, int N, RNG& rng) {\n    for (int i = N - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nstatic inline void set_cycle_from_order(const array<int, MAXN>& ord, int N, array<int, MAXN>& a) {\n    for (int i = 0; i < N; i++) a[ord[i]] = ord[(i + 1) % N];\n}\n\nstatic long long simulate(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N, int L,\n    const array<int, MAXN>& T,\n    array<int, MAXN>& cnt,\n    array<int, MAXN>& useA,\n    array<int, MAXN>& useB,\n    int& last\n) {\n    for (int i = 0; i < N; i++) cnt[i] = 0;\n\n    int cur = 0;\n    cnt[0] = 1; // week 1\n\n    for (int step = 1; step < L; step++) {\n        int s = cur;\n        if (cnt[s] & 1) cur = a[s];\n        else cur = b[s];\n        cnt[cur]++;\n    }\n    last = cur;\n\n    for (int i = 0; i < N; i++) {\n        int dep = cnt[i] - (i == last ? 1 : 0);\n        if (dep < 0) dep = 0;\n        useA[i] = (dep + 1) >> 1;\n        useB[i] = dep >> 1;\n    }\n\n    long long e = 0;\n    for (int i = 0; i < N; i++) e += absl((long long)cnt[i] - T[i]);\n    return e;\n}\n\n// Hungarian min-cost perfect matching: source i -> destination assignment[i]\nstatic long long hungarian(int n, int cost[MAXN][MAXN], array<int, MAXN>& assignment) {\n    const long long INF = (1LL << 60);\n    static long long u[MAXN + 1], v[MAXN + 1], minv[MAXN + 1];\n    static int p[MAXN + 1], way[MAXN + 1];\n    static unsigned char used[MAXN + 1];\n\n    for (int i = 0; i <= n; i++) {\n        u[i] = v[i] = 0;\n        p[i] = way[i] = 0;\n    }\n\n    for (int i = 1; i <= n; i++) {\n        p[0] = i;\n        for (int j = 0; j <= n; j++) {\n            minv[j] = INF;\n            used[j] = 0;\n        }\n\n        int j0 = 0;\n        do {\n            used[j0] = 1;\n            int i0 = p[j0], j1 = 0;\n            long long delta = INF;\n\n            for (int j = 1; j <= n; j++) if (!used[j]) {\n                long long cur = (long long)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\n            for (int j = 0; j <= n; j++) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            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    for (int j = 1; j <= n; j++) assignment[p[j] - 1] = j - 1;\n    return -v[0];\n}\n\nstatic inline int diff_cost(long long diff, int mode) {\n    diff = diff < 0 ? -diff : diff;\n    if (mode == 0) { // L1\n        return (int)diff;\n    } else if (mode == 1) { // L2\n        long long v = diff * diff;\n        if (v > 1000000000LL) v = 1000000000LL;\n        return (int)v;\n    } else { // hybrid\n        long long v = diff + (diff * diff) / 4;\n        if (v > 1000000000LL) v = 1000000000LL;\n        return (int)v;\n    }\n}\n\n// rem is defined as \"target residual\" style for equation: incoming should consume rem by subtracting w\n// move edge s from old->d changes: rem[old]+=w, rem[d]-=w\nstatic void local_improve_edge(\n    array<int, MAXN>& edge,\n    array<long long, MAXN>& rem,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    int passes\n) {\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool improved = false;\n        shuffle_order(ord, N, rng);\n\n        for (int zi = 0; zi < N; zi++) {\n            int s = ord[zi];\n            long long w = T[s];\n            if (w == 0) continue;\n\n            int old = edge[s];\n            int best = old;\n            long long bestDelta = 0;\n            long long absOld = absl(rem[old]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == old) continue;\n                long long delta =\n                    absl(rem[old] + w) + absl(rem[d] - w) - absOld - absl(rem[d]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = d;\n                }\n            }\n\n            if (best != old) {\n                rem[old] += w;\n                rem[best] -= w;\n                edge[s] = best;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nstatic void optimize_b_greedy_given_a(\n    const array<int, MAXN>& a,\n    int N,\n    const array<int, MAXN>& T,\n    const array<int, MAXN>& srcDesc,\n    RNG& rng,\n    array<int, MAXN>& b,\n    double random_rate,\n    int local_passes\n) {\n    array<long long, MAXN> rem{};\n    for (int j = 0; j < N; j++) rem[j] = 2LL * T[j];\n    for (int s = 0; s < N; s++) rem[a[s]] -= T[s];\n\n    for (int k = 0; k < N; k++) {\n        int s = srcDesc[k];\n        long long w = T[s];\n\n        int best = 0, second = 0;\n        long long vb = absl(rem[0] - w), vs = (1LL << 60);\n\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] - w);\n            if (v < vb) {\n                second = best;\n                vs = vb;\n                best = d;\n                vb = v;\n            } else if (v < vs) {\n                second = d;\n                vs = v;\n            }\n        }\n\n        int dst = best;\n        if (random_rate > 0.0 && second != best && rng.nextDouble() < 0.14 * random_rate) {\n            dst = second;\n        }\n\n        b[s] = dst;\n        rem[dst] -= w;\n    }\n\n    local_improve_edge(b, rem, N, T, rng, local_passes);\n}\n\nstatic void optimize_b_hung_given_a(\n    const array<int, MAXN>& a,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& b,\n    int cost_mode,\n    bool relax,\n    int relax_passes\n) {\n    array<long long, MAXN> inA{}, D{}, rem{};\n    for (int s = 0; s < N; s++) inA[a[s]] += T[s];\n    for (int j = 0; j < N; j++) D[j] = 2LL * T[j] - inA[j];\n\n    for (int s = 0; s < N; s++) {\n        for (int d = 0; d < N; d++) {\n            g_cost[s][d] = diff_cost(D[d] - T[s], cost_mode);\n        }\n    }\n\n    array<int, MAXN> asg{};\n    hungarian(N, g_cost, asg);\n    for (int s = 0; s < N; s++) b[s] = asg[s];\n\n    if (relax) {\n        for (int j = 0; j < N; j++) rem[j] = D[j];\n        for (int s = 0; s < N; s++) rem[b[s]] -= T[s];\n        local_improve_edge(b, rem, N, T, rng, relax_passes);\n    }\n}\n\nstatic void optimize_a_hung_given_b(\n    const array<int, MAXN>& b,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& a,\n    int cost_mode,\n    bool relax,\n    int relax_passes\n) {\n    array<long long, MAXN> inB{}, D{}, rem{};\n    for (int s = 0; s < N; s++) inB[b[s]] += T[s];\n    for (int j = 0; j < N; j++) D[j] = 2LL * T[j] - inB[j];\n\n    for (int s = 0; s < N; s++) {\n        for (int d = 0; d < N; d++) {\n            g_cost[s][d] = diff_cost(D[d] - T[s], cost_mode);\n        }\n    }\n\n    array<int, MAXN> asg{};\n    hungarian(N, g_cost, asg);\n    for (int s = 0; s < N; s++) a[s] = asg[s];\n\n    if (relax) {\n        for (int j = 0; j < N; j++) rem[j] = 2LL * T[j];\n        for (int s = 0; s < N; s++) rem[a[s]] -= T[s];\n        for (int s = 0; s < N; s++) rem[b[s]] -= T[s];\n        local_improve_edge(a, rem, N, T, rng, relax_passes);\n    }\n}\n\n// rem is actual residual cnt - T.\n// moving edge s old->d with usage u changes: rem[old]-=u, rem[d]+=u\nstatic void local_improve_usage_edge(\n    array<int, MAXN>& edge,\n    const array<int, MAXN>& use,\n    array<long long, MAXN>& rem,\n    int N,\n    RNG& rng,\n    int passes\n) {\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool improved = false;\n        shuffle_order(ord, N, rng);\n\n        for (int zi = 0; zi < N; zi++) {\n            int s = ord[zi];\n            int u = use[s];\n            if (u == 0) continue;\n\n            int old = edge[s];\n            int best = old;\n            long long bestDelta = 0;\n            long long absOld = absl(rem[old]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == old) continue;\n                long long delta =\n                    absl(rem[old] - u) + absl(rem[d] + u) - absOld - absl(rem[d]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = d;\n                }\n            }\n\n            if (best != old) {\n                rem[old] -= u;\n                rem[best] += u;\n                edge[s] = best;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nstatic void rebuild_edge_by_usage(\n    const array<int, MAXN>& curEdge,\n    const array<int, MAXN>& use,\n    const array<int, MAXN>& cnt,\n    const array<int, MAXN>& T,\n    int N,\n    RNG& rng,\n    array<int, MAXN>& outEdge,\n    int local_passes,\n    double second_rate\n) {\n    outEdge = curEdge;\n\n    array<long long, MAXN> rem{};\n    for (int j = 0; j < N; j++) rem[j] = (long long)cnt[j] - T[j];\n\n    // remove current contributions first\n    for (int s = 0; s < N; s++) rem[outEdge[s]] -= use[s];\n\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n    sort(ord.begin(), ord.begin() + N, [&](int x, int y) {\n        if (use[x] != use[y]) return use[x] > use[y];\n        return x < y;\n    });\n\n    for (int zi = 0; zi < N; zi++) {\n        int s = ord[zi];\n        int u = use[s];\n        if (u == 0) continue;\n\n        int best = 0, second = 0;\n        long long vb = absl(rem[0] + u), vs = (1LL << 60);\n\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] + u);\n            if (v < vb) {\n                second = best;\n                vs = vb;\n                best = d;\n                vb = v;\n            } else if (v < vs) {\n                second = d;\n                vs = v;\n            }\n        }\n\n        int dst = best;\n        if (second != best && second_rate > 0.0 && rng.nextDouble() < second_rate) {\n            dst = second;\n        }\n\n        outEdge[s] = dst;\n        rem[dst] += u;\n    }\n\n    local_improve_usage_edge(outEdge, use, rem, N, rng, local_passes);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    array<int, MAXN> T{};\n    for (int i = 0; i < N; i++) cin >> T[i];\n    if (N <= 0 || N > MAXN) return 0;\n\n    // deterministic seed from input\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        seed ^= (uint64_t)(T[i] + 0x9e3779b97f4a7c15ULL + ((uint64_t)i << 16));\n        seed *= 1099511628211ULL;\n    }\n    seed ^= ((uint64_t)N << 32) ^ (uint64_t)L;\n    RNG rng(seed);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    const double T_INIT_END = 0.45;\n    const double T_SA_END   = 1.78;\n    const double T_END      = 1.92;\n\n    // Base orders\n    array<int, MAXN> ordNatural{}, ordAsc{}, ordDesc{}, ordMountain{}, ordMountainRev{};\n    for (int i = 0; i < N; i++) ordNatural[i] = i;\n\n    vector<int> idx(N);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        if (T[x] != T[y]) return T[x] < T[y];\n        return x < y;\n    });\n\n    for (int i = 0; i < N; i++) ordAsc[i] = idx[i];\n    for (int i = 0; i < N; i++) ordDesc[i] = idx[N - 1 - i];\n\n    {\n        int l = 0, r = N - 1, p = 0;\n        while (l <= r) {\n            ordMountain[p++] = ordAsc[l++];\n            if (l <= r) ordMountain[p++] = ordAsc[r--];\n        }\n    }\n    for (int i = 0; i < N; i++) ordMountainRev[i] = ordMountain[N - 1 - i];\n\n    array<int, MAXN> srcDesc = ordDesc;\n\n    vector<array<int, MAXN>> baseOrders;\n    baseOrders.push_back(ordNatural);\n    baseOrders.push_back(ordAsc);\n    baseOrders.push_back(ordDesc);\n    baseOrders.push_back(ordMountain);\n    baseOrders.push_back(ordMountainRev);\n\n    State best;\n    best.err = (1LL << 60);\n\n    vector<State> pool;\n    pool.reserve(12);\n\n    auto add_pool = [&](const State& s) {\n        pool.push_back(s);\n        sort(pool.begin(), pool.end(), [](const State& x, const State& y) {\n            return x.err < y.err;\n        });\n        if ((int)pool.size() > 10) pool.resize(10);\n    };\n\n    auto evaluate_candidate = [&](const array<int, MAXN>& a, const array<int, MAXN>& b) -> long long {\n        State s;\n        s.a = a;\n        s.b = b;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) best = s;\n        if ((int)pool.size() < 10 || s.err <= pool.back().err + 1200) add_pool(s);\n        return s.err;\n    };\n\n    array<int, MAXN> candA{}, candB{};\n\n    auto build_by_order = [&](const array<int, MAXN>& ord, int strategy, bool rnd) {\n        set_cycle_from_order(ord, N, candA);\n\n        switch (strategy) {\n            case 0:\n                optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, rnd ? 1.0 : 0.0, 5);\n                break;\n            case 1:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, true, 4); // L1\n                break;\n            case 2:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 1, true, 4); // L2\n                break;\n            case 3:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 2, true, 4); // Hybrid\n                break;\n            case 4:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, false, 0);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 0, false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, true, 3);\n                break;\n            case 5:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 1, false, 0);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 2, false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 2, true, 3);\n                break;\n            case 6:\n                optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, rnd ? 0.9 : 0.0, 4);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 2, false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 2, true, 3);\n                break;\n            default:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, false, 0);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 1, false, 0);\n                if (rnd && rng.nextDouble() < 0.5) {\n                    optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, 0.6, 4);\n                } else {\n                    optimize_b_hung_given_a(candA, N, T, rng, candB, 1, true, 3);\n                }\n                break;\n        }\n    };\n\n    array<int, MAXN> bestOrder = ordAsc;\n    long long bestOrderErr = (1LL << 60);\n\n    // Deterministic init\n    for (const auto& ord : baseOrders) {\n        for (int st = 0; st < 8; st++) {\n            build_by_order(ord, st, false);\n            long long e = evaluate_candidate(candA, candB);\n            if (e < bestOrderErr) {\n                bestOrderErr = e;\n                bestOrder = ord;\n            }\n        }\n    }\n\n    // Randomized init\n    while (elapsed() < T_INIT_END) {\n        if (!pool.empty() && rng.nextDouble() < 0.12) {\n            State base = pool[rng.nextInt((int)pool.size())];\n            candA = base.a;\n            candB = base.b;\n\n            int mode = rng.nextInt(5);\n            if (mode == 0) {\n                optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, 0.9, 4);\n            } else if (mode == 1) {\n                optimize_b_hung_given_a(candA, N, T, rng, candB, rng.nextInt(3), true, 3);\n            } else if (mode == 2) {\n                optimize_a_hung_given_b(candB, N, T, rng, candA, rng.nextInt(3), false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, rng.nextInt(3), true, 3);\n            } else if (mode == 3) {\n                rebuild_edge_by_usage(candB, base.useB, base.cnt, T, N, rng, candB, 3, 0.03);\n            } else {\n                rebuild_edge_by_usage(candA, base.useA, base.cnt, T, N, rng, candA, 2, 0.02);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, rng.nextInt(3), true, 2);\n            }\n            evaluate_candidate(candA, candB);\n            continue;\n        }\n\n        array<int, MAXN> ord{};\n        if (rng.nextDouble() < 0.45) ord = bestOrder;\n        else ord = baseOrders[rng.nextInt((int)baseOrders.size())];\n\n        int swaps = 1 + rng.nextInt(24);\n        for (int s = 0; s < swaps; s++) {\n            int i = rng.nextInt(N), j = rng.nextInt(N);\n            swap(ord[i], ord[j]);\n        }\n\n        if (rng.nextDouble() < 0.25) {\n            int l = rng.nextInt(N), r = rng.nextInt(N);\n            if (l > r) swap(l, r);\n            reverse(ord.begin() + l, ord.begin() + r + 1);\n        }\n        if (rng.nextDouble() < 0.08) shuffle_order(ord, N, rng);\n\n        int st = rng.nextInt(8);\n        build_by_order(ord, st, true);\n        long long e = evaluate_candidate(candA, candB);\n        if (e < bestOrderErr) {\n            bestOrderErr = e;\n            bestOrder = ord;\n        }\n    }\n\n    if (pool.empty()) add_pool(best);\n    State cur = best;\n\n    array<int, MAXN> trialA{}, trialB{}, tmpCnt{}, tmpUseA{}, tmpUseB{};\n    int tmpLast = 0;\n    array<uint64_t, MAXN> w1{}, w2{};\n\n    auto differs = [&](const array<int, MAXN>& x, const array<int, MAXN>& y) -> bool {\n        for (int i = 0; i < N; i++) if (x[i] != y[i]) return true;\n        return false;\n    };\n\n    double saStart = elapsed();\n    double saSpan = max(1e-9, T_SA_END - saStart);\n\n    long long iter = 0;\n    long long lastImprove = 0;\n\n    while (elapsed() < T_SA_END) {\n        iter++;\n\n        if ((iter & 255LL) == 0 && !pool.empty()) {\n            if (cur.err > best.err + 1800 ||\n                ((iter - lastImprove > 900) && rng.nextDouble() < 0.40)) {\n                cur = pool[rng.nextInt((int)pool.size())];\n            }\n        }\n\n        double prog = (elapsed() - saStart) / saSpan;\n        if (prog < 0.0) prog = 0.0;\n        if (prog > 1.0) prog = 1.0;\n        double temp = 1300.0 * (1.0 - prog) + 2.2;\n\n        trialA = cur.a;\n        trialB = cur.b;\n        bool changed = false;\n\n        double rr = rng.nextDouble();\n\n        if (rr < 0.28) {\n            // guided single move on b\n            for (int s = 0; s < N; s++) {\n                int dst = cur.b[s];\n                int over = cur.cnt[dst] - T[dst];\n                if (over < 0) over = 0;\n                w1[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(over + 1);\n            }\n\n            int s = sample_weighted(w1.data(), N, rng);\n            int old = cur.b[s];\n            int u = cur.useB[s];\n            if (u <= 0 && rng.nextDouble() < 0.90) continue;\n\n            int bestDst = old;\n            long long bestPred = (1LL << 60);\n            long long xOld = (long long)cur.cnt[old] - T[old];\n            long long absOld = absl(xOld);\n\n            for (int d = 0; d < N; d++) if (d != old) {\n                long long x = (long long)cur.cnt[d] - T[d];\n                long long pred = absl(xOld - u) + absl(x + u) - absOld - absl(x);\n                if (pred < bestPred) {\n                    bestPred = pred;\n                    bestDst = d;\n                }\n            }\n\n            if (bestDst == old) continue;\n            if (bestPred > 0 && rng.nextDouble() < (0.68 + 0.22 * prog)) continue;\n            if (bestPred == 0 && rng.nextDouble() < 0.45) continue;\n\n            if (rng.nextDouble() < 0.10) {\n                for (int d = 0; d < N; d++) {\n                    int under = T[d] - cur.cnt[d];\n                    if (under < 0) under = 0;\n                    w2[d] = (uint64_t)(under + 1);\n                }\n                int rndDst = sample_weighted(w2.data(), N, rng);\n                if (rndDst != old) bestDst = rndDst;\n            }\n\n            trialB[s] = bestDst;\n            changed = true;\n\n        } else if (rr < 0.42) {\n            // swap two b edges\n            for (int s = 0; s < N; s++) {\n                int d = cur.b[s];\n                int over = cur.cnt[d] - T[d];\n                if (over < 0) over = 0;\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w1[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(over + 1);\n                w2[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(under + 1);\n            }\n\n            int s1 = sample_weighted(w1.data(), N, rng);\n            int s2 = sample_weighted(w2.data(), N, rng);\n            if (s1 == s2) {\n                s2 = rng.nextInt(N - 1);\n                if (s2 >= s1) s2++;\n            }\n\n            int d1 = cur.b[s1], d2 = cur.b[s2];\n            if (d1 == d2) continue;\n\n            int u1 = cur.useB[s1], u2 = cur.useB[s2];\n            long long x1 = (long long)cur.cnt[d1] - T[d1];\n            long long x2 = (long long)cur.cnt[d2] - T[d2];\n            long long pred = absl(x1 - u1 + u2) + absl(x2 - u2 + u1) - absl(x1) - absl(x2);\n            if (pred > 0 && rng.nextDouble() < (0.72 + 0.18 * prog)) continue;\n\n            swap(trialB[s1], trialB[s2]);\n            changed = true;\n\n        } else if (rr < 0.53) {\n            // guided single move on a\n            for (int s = 0; s < N; s++) {\n                int dst = cur.a[s];\n                int over = cur.cnt[dst] - T[dst];\n                if (over < 0) over = 0;\n                w1[s] = (uint64_t)(cur.useA[s] + 1) * (uint64_t)(over + 1);\n            }\n\n            int s = sample_weighted(w1.data(), N, rng);\n            int old = cur.a[s];\n            int u = cur.useA[s];\n            if (u <= 0 && rng.nextDouble() < 0.90) continue;\n\n            int bestDst = old;\n            long long bestPred = (1LL << 60);\n            long long xOld = (long long)cur.cnt[old] - T[old];\n            long long absOld = absl(xOld);\n\n            for (int d = 0; d < N; d++) if (d != old) {\n                long long x = (long long)cur.cnt[d] - T[d];\n                long long pred = absl(xOld - u) + absl(x + u) - absOld - absl(x);\n                if (pred < bestPred) {\n                    bestPred = pred;\n                    bestDst = d;\n                }\n            }\n\n            if (bestDst == old) continue;\n            if (bestPred > 0 && rng.nextDouble() < (0.74 + 0.18 * prog)) continue;\n            if (bestPred == 0 && rng.nextDouble() < 0.52) continue;\n\n            trialA[s] = bestDst;\n            changed = true;\n\n        } else if (rr < 0.63) {\n            // swap two a edges\n            for (int s = 0; s < N; s++) {\n                int d = cur.a[s];\n                int over = cur.cnt[d] - T[d];\n                if (over < 0) over = 0;\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w1[s] = (uint64_t)(cur.useA[s] + 1) * (uint64_t)(over + 1);\n                w2[s] = (uint64_t)(cur.useA[s] + 1) * (uint64_t)(under + 1);\n            }\n\n            int s1 = sample_weighted(w1.data(), N, rng);\n            int s2 = sample_weighted(w2.data(), N, rng);\n            if (s1 == s2) {\n                s2 = rng.nextInt(N - 1);\n                if (s2 >= s1) s2++;\n            }\n\n            int d1 = cur.a[s1], d2 = cur.a[s2];\n            if (d1 == d2) continue;\n\n            int u1 = cur.useA[s1], u2 = cur.useA[s2];\n            long long x1 = (long long)cur.cnt[d1] - T[d1];\n            long long x2 = (long long)cur.cnt[d2] - T[d2];\n            long long pred = absl(x1 - u1 + u2) + absl(x2 - u2 + u1) - absl(x1) - absl(x2);\n            if (pred > 0 && rng.nextDouble() < (0.76 + 0.16 * prog)) continue;\n\n            swap(trialA[s1], trialA[s2]);\n            changed = true;\n\n        } else if (rr < 0.74) {\n            // rebuild b with current a\n            if (rng.nextDouble() < 0.45) {\n                optimize_b_greedy_given_a(trialA, N, T, srcDesc, rng, trialB, 0.9, 4);\n            } else {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 3);\n            }\n            changed = differs(trialB, cur.b);\n\n        } else if (rr < 0.84) {\n            // rebuild a (and maybe b)\n            optimize_a_hung_given_b(trialB, N, T, rng, trialA, rng.nextInt(3), false, 0);\n\n            double r2 = rng.nextDouble();\n            if (r2 < 0.45) {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 3);\n            } else if (r2 < 0.75) {\n                optimize_b_greedy_given_a(trialA, N, T, srcDesc, rng, trialB, 0.7, 4);\n            }\n\n            changed = differs(trialA, cur.a) || differs(trialB, cur.b);\n\n        } else if (rr < 0.92) {\n            // usage-based rebuild of b\n            rebuild_edge_by_usage(cur.b, cur.useB, cur.cnt, T, N, rng, trialB, 3, 0.03);\n            if (rng.nextDouble() < 0.20) {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 2);\n            }\n            changed = differs(trialB, cur.b);\n\n        } else {\n            // usage-based rebuild of both / global nudge\n            rebuild_edge_by_usage(cur.a, cur.useA, cur.cnt, T, N, rng, trialA, 2, 0.02);\n            if (rng.nextDouble() < 0.65) {\n                rebuild_edge_by_usage(cur.b, cur.useB, cur.cnt, T, N, rng, trialB, 3, 0.03);\n            } else {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 3);\n            }\n            if (rng.nextDouble() < 0.18) {\n                optimize_a_hung_given_b(trialB, N, T, rng, trialA, rng.nextInt(3), false, 0);\n            }\n            changed = differs(trialA, cur.a) || differs(trialB, cur.b);\n        }\n\n        if (!changed) continue;\n\n        long long newErr = simulate(trialA, trialB, N, L, T, tmpCnt, tmpUseA, tmpUseB, tmpLast);\n\n        bool accept = false;\n        if (newErr <= cur.err) accept = true;\n        else {\n            double prob = exp((double)(cur.err - newErr) / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.a = trialA;\n            cur.b = trialB;\n            cur.err = newErr;\n            cur.cnt = tmpCnt;\n            cur.useA = tmpUseA;\n            cur.useB = tmpUseB;\n            cur.last = tmpLast;\n\n            if (cur.err < best.err) {\n                best = cur;\n                add_pool(best);\n                lastImprove = iter;\n            } else if (cur.err <= best.err + 900 && rng.nextDouble() < 0.12) {\n                add_pool(cur);\n            }\n        }\n    }\n\n    auto try_update = [&](const array<int, MAXN>& aa, const array<int, MAXN>& bb) -> bool {\n        State s;\n        s.a = aa;\n        s.b = bb;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        if (s.err < best.err) {\n            best = s;\n            add_pool(best);\n            return true;\n        }\n        return false;\n    };\n\n    array<int, MAXN> trialA2{}, trialB2{};\n\n    // Deterministic polish rebuilds\n    if (elapsed() < T_END - 0.06) {\n        trialA2 = best.a;\n        optimize_b_greedy_given_a(trialA2, N, T, srcDesc, rng, trialB2, 0.0, 5);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.06) {\n        trialA2 = best.a;\n        optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, 0, true, 4);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.06) {\n        trialA2 = best.a;\n        optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, 1, true, 4);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.06) {\n        trialA2 = best.a;\n        rebuild_edge_by_usage(best.b, best.useB, best.cnt, T, N, rng, trialB2, 4, 0.0);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.06) {\n        rebuild_edge_by_usage(best.a, best.useA, best.cnt, T, N, rng, trialA2, 2, 0.0);\n        rebuild_edge_by_usage(best.b, best.useB, best.cnt, T, N, rng, trialB2, 3, 0.0);\n        try_update(trialA2, trialB2);\n    }\n\n    auto polish_top_single_once = [&](State& st, int topKeep, int evalLimit) -> bool {\n        struct Cand {\n            long long pred;\n            int type; // 0:a, 1:b\n            int s, d;\n        };\n\n        vector<Cand> cands;\n        cands.reserve(22000);\n\n        array<long long, MAXN> res{};\n        for (int i = 0; i < N; i++) res[i] = (long long)st.cnt[i] - T[i];\n\n        for (int s = 0; s < N; s++) {\n            int ub = st.useB[s];\n            if (ub > 0) {\n                int old = st.b[s];\n                long long ro = res[old];\n                long long aro = absl(ro);\n                for (int d = 0; d < N; d++) if (d != old) {\n                    long long pred = absl(ro - ub) + absl(res[d] + ub) - aro - absl(res[d]);\n                    cands.push_back({pred, 1, s, d});\n                }\n            }\n\n            int ua = st.useA[s];\n            if (ua > 0) {\n                int old = st.a[s];\n                long long ro = res[old];\n                long long aro = absl(ro);\n                for (int d = 0; d < N; d++) if (d != old) {\n                    long long pred = absl(ro - ua) + absl(res[d] + ua) - aro - absl(res[d]);\n                    cands.push_back({pred, 0, s, d});\n                }\n            }\n        }\n\n        if (cands.empty()) return false;\n\n        auto cmp = [](const Cand& x, const Cand& y) { return x.pred < y.pred; };\n        if ((int)cands.size() > topKeep) {\n            nth_element(cands.begin(), cands.begin() + topKeep, cands.end(), cmp);\n            cands.resize(topKeep);\n        }\n        sort(cands.begin(), cands.end(), cmp);\n\n        State bestLocal = st;\n        bool improved = false;\n        int evals = 0;\n\n        for (const auto& cd : cands) {\n            if (evals >= evalLimit) break;\n            if (elapsed() >= T_END - 0.004) break;\n\n            State tmp;\n            tmp.a = st.a;\n            tmp.b = st.b;\n            if (cd.type == 0) tmp.a[cd.s] = cd.d;\n            else tmp.b[cd.s] = cd.d;\n\n            tmp.err = simulate(tmp.a, tmp.b, N, L, T, tmp.cnt, tmp.useA, tmp.useB, tmp.last);\n            evals++;\n\n            if (tmp.err < bestLocal.err) {\n                bestLocal = tmp;\n                improved = true;\n            }\n        }\n\n        if (improved) st = bestLocal;\n        return improved;\n    };\n\n    auto polish_top_swap_once = [&](State& st, bool onA, int topKeep, int evalLimit) -> bool {\n        struct Cand {\n            long long pred;\n            int i, j;\n        };\n\n        vector<Cand> cands;\n        cands.reserve(6000);\n\n        array<long long, MAXN> res{};\n        for (int k = 0; k < N; k++) res[k] = (long long)st.cnt[k] - T[k];\n\n        const array<int, MAXN>* pedge = onA ? &st.a : &st.b;\n        const array<int, MAXN>* puse  = onA ? &st.useA : &st.useB;\n\n        for (int i = 0; i < N; i++) {\n            int d1 = (*pedge)[i];\n            int u1 = (*puse)[i];\n            for (int j = i + 1; j < N; j++) {\n                int d2 = (*pedge)[j];\n                if (d1 == d2) continue;\n                int u2 = (*puse)[j];\n                if (u1 == 0 && u2 == 0) continue;\n\n                long long pred =\n                    absl(res[d1] - u1 + u2) + absl(res[d2] - u2 + u1)\n                    - absl(res[d1]) - absl(res[d2]);\n                cands.push_back({pred, i, j});\n            }\n        }\n\n        if (cands.empty()) return false;\n\n        auto cmp = [](const Cand& x, const Cand& y) { return x.pred < y.pred; };\n        if ((int)cands.size() > topKeep) {\n            nth_element(cands.begin(), cands.begin() + topKeep, cands.end(), cmp);\n            cands.resize(topKeep);\n        }\n        sort(cands.begin(), cands.end(), cmp);\n\n        State bestLocal = st;\n        bool improved = false;\n        int evals = 0;\n\n        for (const auto& cd : cands) {\n            if (evals >= evalLimit) break;\n            if (elapsed() >= T_END - 0.004) break;\n\n            State tmp = st;\n            if (onA) swap(tmp.a[cd.i], tmp.a[cd.j]);\n            else swap(tmp.b[cd.i], tmp.b[cd.j]);\n\n            tmp.err = simulate(tmp.a, tmp.b, N, L, T, tmp.cnt, tmp.useA, tmp.useB, tmp.last);\n            evals++;\n\n            if (tmp.err < bestLocal.err) {\n                bestLocal = tmp;\n                improved = true;\n            }\n        }\n\n        if (improved) st = bestLocal;\n        return improved;\n    };\n\n    // Exact top-predicted polish\n    if (elapsed() < T_END - 0.012) {\n        int noImp = 0;\n        while (elapsed() < T_END - 0.012 && noImp < 5) {\n            bool imp = false;\n            imp |= polish_top_single_once(best, 220, 16);\n            if (elapsed() < T_END - 0.010) imp |= polish_top_swap_once(best, false, 120, 8);\n            if (elapsed() < T_END - 0.008) imp |= polish_top_swap_once(best, true,  100, 6);\n\n            if (imp) {\n                add_pool(best);\n                noImp = 0;\n            } else {\n                noImp++;\n                if (elapsed() < T_END - 0.014) {\n                    trialA2 = best.a;\n                    trialB2 = best.b;\n                    if (noImp & 1) {\n                        rebuild_edge_by_usage(best.b, best.useB, best.cnt, T, N, rng, trialB2, 2, 0.0);\n                    } else {\n                        rebuild_edge_by_usage(best.a, best.useA, best.cnt, T, N, rng, trialA2, 1, 0.0);\n                        rebuild_edge_by_usage(best.b, best.useB, best.cnt, T, N, rng, trialB2, 2, 0.0);\n                    }\n                    try_update(trialA2, trialB2);\n                }\n            }\n        }\n    }\n\n    // last small random perturbations\n    int trials = 0;\n    while (elapsed() < T_END - 0.003 && trials < 18) {\n        trialA2 = best.a;\n        int i = rng.nextInt(N);\n        int j = rng.nextInt(N - 1);\n        if (j >= i) j++;\n        swap(trialA2[i], trialA2[j]);\n\n        if (rng.nextDouble() < 0.55) {\n            optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, rng.nextInt(3), true, 3);\n        } else {\n            optimize_b_greedy_given_a(trialA2, N, T, srcDesc, rng, trialB2, 0.4, 4);\n        }\n        try_update(trialA2, trialB2);\n        trials++;\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\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        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int MAXN = 800;\n    static constexpr int EDGE_BASE = 1024;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n\n    vector<int> lx, rx, ly, ry;\n    vector<int> wx, wy;              // rectangle widths\n    vector<int> cx2, cy2, cx, cy;    // center*2 and center\n    vector<uint32_t> zkey;\n\n    vector<int> d_center; // center-based distance (scaled coords)\n    vector<int> d_base;   // uncertainty-aware distance\n    vector<int> d_group;  // d_base + query-learned bonuses\n\n    vector<uint16_t> obsCnt;             // observed edge frequency\n    vector<pair<int,int>> touchedObs;    // unique (a<b) observed edges\n\n    mt19937 rng;\n\n    inline int ID(int a, int b) const { return a * N + b; }\n    inline int DBase(int a, int b) const { return d_base[ID(a, b)]; }\n    inline int DGroup(int a, int b) const { return d_group[ID(a, b)]; }\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffffu;\n        x = (x | (x << 8)) & 0x00FF00FFu;\n        x = (x | (x << 4)) & 0x0F0F0F0Fu;\n        x = (x | (x << 2)) & 0x33333333u;\n        x = (x | (x << 1)) & 0x55555555u;\n        return x;\n    }\n    static uint32_t morton(uint32_t x, uint32_t y) {\n        return part1by1(x) | (part1by1(y) << 1);\n    }\n\n    void input() {\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        wx.resize(N); wy.resize(N);\n        cx2.resize(N); cy2.resize(N);\n        cx.resize(N); cy.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            wx[i] = rx[i] - lx[i];\n            wy[i] = ry[i] - ly[i];\n            cx2[i] = lx[i] + rx[i];\n            cy2[i] = ly[i] + ry[i];\n            cx[i] = cx2[i] / 2;\n            cy[i] = cy2[i] / 2;\n        }\n    }\n\n    void init_rng() {\n        uint64_t seed = 0x9e3779b97f4a7c15ull;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n        };\n\n        mix(((uint64_t)N << 32) ^ (uint64_t)M);\n        mix(((uint64_t)Q << 32) ^ (uint64_t)L);\n        mix((uint64_t)W);\n        for (int i = 0; i < N; i++) {\n            mix(((uint64_t)(cx2[i] + 10007) << 32) ^ (uint64_t)(cy2[i] + 10009));\n            mix((uint64_t)(wx[i] + 1) * 1000003ull + (uint64_t)(wy[i] + 7));\n        }\n\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    void preprocess() {\n        zkey.resize(N);\n        for (int i = 0; i < N; i++) {\n            zkey[i] = morton((uint32_t)cx[i], (uint32_t)cy[i]);\n        }\n\n        d_center.assign(N * N, 0);\n        d_base.assign(N * N, 0);\n        d_group.assign(N * N, 0);\n\n        for (int i = 0; i < N; i++) {\n            d_center[ID(i, i)] = 0;\n            d_base[ID(i, i)] = 0;\n            for (int j = i + 1; j < N; j++) {\n                long long dx = (long long)cx2[i] - cx2[j];\n                long long dy = (long long)cy2[i] - cy2[j];\n                long long sq = dx * dx + dy * dy;\n                int dc = (int)std::sqrt((double)sq);\n                d_center[ID(i, j)] = d_center[ID(j, i)] = dc;\n\n                // uncertainty-aware proxy:\n                // E[(error_x)^2 + (error_y)^2] approx (wx_i^2 + wx_j^2 + wy_i^2 + wy_j^2)/3\n                long double add = ((long double)wx[i] * wx[i] + (long double)wx[j] * wx[j]\n                                 + (long double)wy[i] * wy[i] + (long double)wy[j] * wy[j]) / 3.0L;\n                long double bq = (long double)dc * dc + add;\n                int db = (int)std::sqrt((double)bq);\n\n                d_base[ID(i, j)] = d_base[ID(j, i)] = db;\n            }\n        }\n\n        d_group = d_base;\n        obsCnt.assign(N * N, 0);\n        touchedObs.clear();\n    }\n\n    int query_need(int g) const {\n        if (g <= 2) return 0;\n        return (g - 2) / (L - 1) + 1; // ceil((g-1)/(L-1))\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        cout << \"? \" << subset.size();\n        for (int c : subset) cout << \" \" << c;\n        cout << \"\\n\";\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)subset.size() - 1);\n        for (int i = 0; i < (int)subset.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.emplace_back(a, b);\n        }\n        return ret;\n    }\n\n    void record_edges(const vector<pair<int,int>>& edges) {\n        for (auto [a, b] : edges) {\n            if (a > b) swap(a, b);\n            int p = ID(a, b), q = ID(b, a);\n            if (obsCnt[p] == 0) touchedObs.emplace_back(a, b);\n            if (obsCnt[p] < 65535) obsCnt[p]++;\n            if (obsCnt[q] < 65535) obsCnt[q]++;\n        }\n    }\n\n    template<class F>\n    vector<int> make_city_order(F comp) const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), comp);\n        return ord;\n    }\n\n    vector<int> city_order_projection(double ang) const {\n        double ax = cos(ang), ay = sin(ang);\n        vector<double> key(N);\n        for (int i = 0; i < N; i++) key[i] = ax * cx2[i] + ay * cy2[i];\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (fabs(key[a] - key[b]) > 1e-12) return key[a] < key[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<vector<int>> build_knn(const vector<int>& mat, int K) const {\n        K = min(K, N - 1);\n        vector<vector<int>> near(N);\n\n        auto cmp = [](const pair<int,int>& p1, const pair<int,int>& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        };\n\n        for (int i = 0; i < N; i++) {\n            vector<pair<int,int>> arr;\n            arr.reserve(N - 1);\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                if (i == j) continue;\n                arr.emplace_back(mat[base + j], j);\n            }\n\n            if ((int)arr.size() > K) {\n                nth_element(arr.begin(), arr.begin() + K, arr.end(), cmp);\n                arr.resize(K);\n            }\n            sort(arr.begin(), arr.end(), cmp);\n\n            near[i].reserve((int)arr.size());\n            for (auto& p : arr) near[i].push_back(p.second);\n        }\n        return near;\n    }\n\n    void perform_exploration(int q_explore, int& q_used) {\n        if (q_explore <= 0) return;\n\n        int Kexp = min(N - 1, max(24, L * 4));\n        auto near = build_knn(d_base, Kexp);\n\n        vector<int> ordZ(N);\n        iota(ordZ.begin(), ordZ.end(), 0);\n        sort(ordZ.begin(), ordZ.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<double> w(N);\n        for (int i = 0; i < N; i++) w[i] = (double)(wx[i] + wy[i] + 20);\n        discrete_distribution<int> anchorDist(w.begin(), w.end());\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        vector<int> mark(N, 0);\n        int stamp = 1;\n\n        for (int t = 0; t < q_explore; t++) {\n            vector<int> subset;\n            subset.reserve(L);\n            ++stamp;\n\n            auto addNode = [&](int v) -> bool {\n                if (v < 0 || v >= N) return false;\n                if (mark[v] == stamp) return false;\n                mark[v] = stamp;\n                subset.push_back(v);\n                return true;\n            };\n\n            int mode = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (mode < 65) {\n                int a = anchorDist(rng);\n                addNode(a);\n                auto& ne = near[a];\n\n                int fixed = min((int)ne.size(), max(1, (L - 1) / 2));\n                for (int i = 0; i < fixed && (int)subset.size() < L; i++) addNode(ne[i]);\n\n                int R = min((int)ne.size(), max(10, L * 3));\n                if (R > 0) {\n                    for (int tries = 0; tries < R * 3 && (int)subset.size() < L; tries++) {\n                        int idx = uniform_int_distribution<int>(0, R - 1)(rng);\n                        addNode(ne[idx]);\n                    }\n                }\n\n                for (int tries = 0; tries < 20 && (int)subset.size() < L; tries++) addNode(uid(rng));\n            } else if (mode < 90) {\n                int a = anchorDist(rng);\n                addNode(a);\n\n                int b = uid(rng);\n                auto& na = near[a];\n                if (!na.empty()) {\n                    int R = min((int)na.size(), 10);\n                    b = na[uniform_int_distribution<int>(0, R - 1)(rng)];\n                }\n                addNode(b);\n\n                vector<int> bases = {a, b};\n                int ptr0 = 0, ptr1 = 0;\n\n                for (int step = 0; step < 200 && (int)subset.size() < L; step++) {\n                    int bi = step & 1;\n                    auto& ne = near[bases[bi]];\n                    int& ptr = (bi == 0 ? ptr0 : ptr1);\n\n                    while (ptr < (int)ne.size() && mark[ne[ptr]] == stamp) ptr++;\n                    if (ptr < (int)ne.size()) {\n                        addNode(ne[ptr]);\n                        ptr++;\n                    } else {\n                        addNode(uid(rng));\n                    }\n                }\n            } else {\n                int len = min(L, N);\n                int s = 0;\n                if (N > len) s = uniform_int_distribution<int>(0, N - len)(rng);\n                for (int i = 0; i < len; i++) addNode(ordZ[s + i]);\n                for (int tries = 0; tries < 20 && (int)subset.size() < L; tries++) addNode(uid(rng));\n            }\n\n            while ((int)subset.size() < 2) addNode(uid(rng));\n            if ((int)subset.size() > L) subset.resize(L);\n\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n        }\n    }\n\n    void rebuild_group_matrix_from_obs() {\n        d_group = d_base;\n        int beta = max(30, W / 14); // roughly 35..178\n\n        for (auto [a, b] : touchedObs) {\n            int c = (int)obsCnt[ID(a, b)];\n            if (c <= 0) continue;\n            int bonus = beta * c;\n            if (c >= 2) bonus += beta / 2;\n\n            int v = d_base[ID(a, b)] - bonus;\n            if (v < 1) v = 1;\n            d_group[ID(a, b)] = d_group[ID(b, a)] = v;\n        }\n    }\n\n    long long prim_cost(const vector<int>& nodes, const vector<int>& mat) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return 0;\n\n        const int INF = 1e9;\n        int mn[MAXN + 5];\n        unsigned char used[MAXN + 5];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        long long cost = 0;\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            cost += mn[v];\n\n            int idv = nodes[v];\n            int base = idv * N;\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = mat[base + nodes[u]];\n                if (w < mn[u]) mn[u] = w;\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> prim_tree(const vector<int>& nodes, const vector<int>& mat) const {\n        int n = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            edges.push_back(p);\n            return edges;\n        }\n\n        const int INF = 1e9;\n        int mn[MAXN + 5], par[MAXN + 5];\n        unsigned char used[MAXN + 5];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            par[i] = -1;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int idv = nodes[v];\n            int base = idv * N;\n\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = mat[base + nodes[u]];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        edges.reserve(n - 1);\n        for (int i = 1; i < n; i++) {\n            int a = nodes[i], b = nodes[par[i]];\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        return edges;\n    }\n\n    long long edge_proxy_cost(const vector<pair<int,int>>& edges, const vector<int>& mat) const {\n        long long s = 0;\n        for (auto [a, b] : edges) s += mat[ID(a, b)];\n        return s;\n    }\n\n    vector<int> global_mst_order(const vector<int>& mat) const {\n        const int INF = 1e9;\n        vector<int> mn(N, INF), par(N, -1);\n        vector<char> used(N, 0);\n\n        int root = 0;\n        for (int i = 1; i < N; i++) if (zkey[i] < zkey[root]) root = i;\n        mn[root] = 0;\n\n        for (int it = 0; it < N; it++) {\n            int v = -1;\n            for (int i = 0; i < N; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int base = v * N;\n            for (int u = 0; u < N; u++) {\n                if (used[u]) continue;\n                int w = mat[base + u];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<vector<int>> adj(N);\n        for (int i = 0; i < N; i++) {\n            if (i == root) continue;\n            if (par[i] >= 0) {\n                adj[i].push_back(par[i]);\n                adj[par[i]].push_back(i);\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            sort(adj[i].begin(), adj[i].end(), [&](int a, int b) {\n                if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                return a < b;\n            });\n        }\n\n        vector<int> order;\n        order.reserve(N);\n        vector<int> st;\n        vector<int> itPtr(N, 0);\n        vector<char> vis(N, 0);\n\n        st.push_back(root);\n        vis[root] = 1;\n        order.push_back(root);\n\n        while (!st.empty()) {\n            int v = st.back();\n            if (itPtr[v] == (int)adj[v].size()) {\n                st.pop_back();\n                continue;\n            }\n            int to = adj[v][itPtr[v]++];\n            if (vis[to]) continue;\n            vis[to] = 1;\n            order.push_back(to);\n            st.push_back(to);\n        }\n\n        if ((int)order.size() < N) {\n            vector<char> used2(N, 0);\n            for (int x : order) used2[x] = 1;\n            for (int i = 0; i < N; i++) if (!used2[i]) order.push_back(i);\n        }\n        return order;\n    }\n\n    bool validate_groups(const vector<vector<int>>& groups) const {\n        if ((int)groups.size() != M) return false;\n        vector<int> cnt(N, 0);\n        for (int g = 0; g < M; g++) {\n            if ((int)groups[g].size() != G[g]) return false;\n            for (int c : groups[g]) {\n                if (c < 0 || c >= N) return false;\n                cnt[c]++;\n            }\n        }\n        for (int i = 0; i < N; i++) if (cnt[i] != 1) return false;\n        return true;\n    }\n\n    long long eval_groups(const vector<vector<int>>& groups) const {\n        long long s = 0;\n        for (int g = 0; g < M; g++) s += prim_cost(groups[g], d_group);\n        return s;\n    }\n\n    vector<vector<int>> build_order_trial(const vector<int>& city_order, const vector<int>& group_order) const {\n        vector<vector<int>> out(M);\n        int p = 0;\n        for (int gid : group_order) {\n            int sz = G[gid];\n            out[gid].assign(city_order.begin() + p, city_order.begin() + p + sz);\n            p += sz;\n        }\n        return out;\n    }\n\n    void rec_assign(vector<int> cities, vector<int> gids, vector<vector<int>>& out, bool randomized) {\n        if ((int)gids.size() == 1) {\n            out[gids[0]] = std::move(cities);\n            return;\n        }\n\n        int S = (int)cities.size();\n\n        int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;\n        for (int c : cities) {\n            minx = min(minx, cx2[c]);\n            maxx = max(maxx, cx2[c]);\n            miny = min(miny, cy2[c]);\n            maxy = max(maxy, cy2[c]);\n        }\n\n        int axis = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 28) axis ^= 1;\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            if (axis == 0) {\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                return a < b;\n            } else {\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                return a < b;\n            }\n        });\n\n        vector<int> pg = gids;\n        if (randomized) shuffle(pg.begin(), pg.end(), rng);\n\n        vector<char> dp(S + 1, 0);\n        vector<int> prv(S + 1, -1), itm(S + 1, -1);\n        dp[0] = 1;\n\n        for (int j = 0; j < (int)pg.size(); j++) {\n            int w = G[pg[j]];\n            for (int s = S - w; s >= 0; s--) {\n                if (dp[s] && !dp[s + w]) {\n                    dp[s + w] = 1;\n                    prv[s + w] = s;\n                    itm[s + w] = j;\n                }\n            }\n        }\n\n        int target = S / 2;\n        if (randomized) {\n            int r = max(1, S / 6);\n            target += uniform_int_distribution<int>(-r, r)(rng);\n            target = max(1, min(S - 1, target));\n        }\n\n        int bestDiff = INT_MAX;\n        vector<int> candS;\n        for (int s = 1; s <= S - 1; s++) {\n            if (!dp[s]) continue;\n            int diff = abs(s - target);\n            if (diff < bestDiff) {\n                bestDiff = diff;\n                candS.clear();\n                candS.push_back(s);\n            } else if (diff == bestDiff) {\n                candS.push_back(s);\n            }\n        }\n\n        int split = -1;\n        if (!candS.empty()) {\n            split = randomized\n                ? candS[uniform_int_distribution<int>(0, (int)candS.size() - 1)(rng)]\n                : candS[0];\n        }\n\n        vector<int> gA, gB;\n        bool ok = (split > 0 && split < S);\n        if (ok) {\n            vector<char> take(pg.size(), 0);\n            int cur = split;\n            while (cur > 0) {\n                int j = itm[cur];\n                if (j < 0 || take[j]) {\n                    ok = false;\n                    break;\n                }\n                take[j] = 1;\n                cur = prv[cur];\n            }\n\n            if (ok) {\n                int sumA = 0;\n                for (int j = 0; j < (int)pg.size(); j++) {\n                    if (take[j]) {\n                        gA.push_back(pg[j]);\n                        sumA += G[pg[j]];\n                    } else {\n                        gB.push_back(pg[j]);\n                    }\n                }\n                if (gA.empty() || gB.empty() || sumA != split) ok = false;\n            }\n        }\n\n        if (!ok) {\n            gA.clear(); gB.clear();\n            gA.push_back(pg[0]);\n            split = G[pg[0]];\n            for (int j = 1; j < (int)pg.size(); j++) gB.push_back(pg[j]);\n        }\n\n        vector<int> cA(cities.begin(), cities.begin() + split);\n        vector<int> cB(cities.begin() + split, cities.end());\n\n        rec_assign(std::move(cA), std::move(gA), out, randomized);\n        rec_assign(std::move(cB), std::move(gB), out, randomized);\n    }\n\n    vector<vector<int>> build_recursive_trial(bool randomized) {\n        vector<vector<int>> out(M);\n        vector<int> cities(N), gids(M);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        sort(gids.begin(), gids.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 20) {\n            shuffle(gids.begin(), gids.end(), rng);\n        }\n\n        rec_assign(std::move(cities), std::move(gids), out, randomized);\n        return out;\n    }\n\n    vector<vector<int>> make_grouping() {\n        vector<vector<int>> best;\n        long long bestScore = (1LL << 62);\n\n        auto consider = [&](vector<vector<int>> cand) {\n            if (!validate_groups(cand)) return;\n            long long sc = eval_groups(cand);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = std::move(cand);\n            }\n        };\n\n        vector<int> goOrig(M), goDesc(M), goAsc(M), goRand(M);\n        iota(goOrig.begin(), goOrig.end(), 0);\n        goDesc = goOrig;\n        goAsc = goOrig;\n        goRand = goOrig;\n\n        sort(goDesc.begin(), goDesc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        sort(goAsc.begin(), goAsc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        shuffle(goRand.begin(), goRand.end(), rng);\n\n        vector<vector<int>> groupOrders = {goDesc, goOrig, goAsc, goRand};\n\n        vector<vector<int>> cityOrders;\n        auto ordZ = make_city_order([&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n        auto ordX = make_city_order([&](int a, int b) {\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        auto ordY = make_city_order([&](int a, int b) {\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ordD1 = make_city_order([&](int a, int b) {\n            int ka = cx2[a] + cy2[a];\n            int kb = cx2[b] + cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ordD2 = make_city_order([&](int a, int b) {\n            int ka = cx2[a] - cy2[a];\n            int kb = cx2[b] - cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n\n        cityOrders.push_back(ordZ);\n        cityOrders.push_back(ordX);\n        cityOrders.push_back(ordY);\n        cityOrders.push_back(ordD1);\n        cityOrders.push_back(ordD2);\n\n        auto rev = ordZ;\n        reverse(rev.begin(), rev.end());\n        cityOrders.push_back(rev);\n\n        cityOrders.push_back(global_mst_order(d_group));\n\n        const double PI = acos(-1.0);\n        cityOrders.push_back(city_order_projection(PI * 1.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 3.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 5.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 7.0 / 8.0));\n\n        uniform_real_distribution<double> ur(0.0, PI);\n        cityOrders.push_back(city_order_projection(ur(rng)));\n        cityOrders.push_back(city_order_projection(ur(rng)));\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                consider(build_order_trial(co, go));\n            }\n        }\n\n        consider(build_recursive_trial(false));\n        for (int t = 0; t < 6; t++) consider(build_recursive_trial(true));\n\n        if (best.empty()) best = build_order_trial(ordZ, goOrig);\n        return best;\n    }\n\n    void optimize_groups(vector<vector<int>>& groups, double sec_budget) {\n        using Clock = chrono::steady_clock;\n        auto start = Clock::now();\n        auto deadline = start + chrono::milliseconds((int)(sec_budget * 1000.0));\n        auto stage1 = start + chrono::milliseconds((int)(sec_budget * 650.0));\n\n        vector<int> gid(N, -1), pos(N, -1);\n        for (int g = 0; g < M; g++) {\n            for (int i = 0; i < (int)groups[g].size(); i++) {\n                int c = groups[g][i];\n                gid[c] = g;\n                pos[c] = i;\n            }\n        }\n\n        vector<long long> gcost(M, 0);\n        for (int g = 0; g < M; g++) gcost[g] = prim_cost(groups[g], d_group);\n\n        auto near = build_knn(d_group, 24);\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        long long opBudget = 45000000;\n\n        auto try_swap = [&](int u, int v) -> bool {\n            int ga = gid[u], gb = gid[v];\n            if (ga == gb || ga < 0 || gb < 0) return false;\n\n            int sa = (int)groups[ga].size();\n            int sb = (int)groups[gb].size();\n            long long est = 1LL * sa * sa + 1LL * sb * sb;\n            if (est > opBudget) return false;\n            opBudget -= est;\n\n            int pu = pos[u], pv = pos[v];\n            auto& A = groups[ga];\n            auto& B = groups[gb];\n\n            swap(A[pu], B[pv]);\n            long long nA = prim_cost(A, d_group);\n            long long nB = prim_cost(B, d_group);\n\n            if (nA + nB < gcost[ga] + gcost[gb]) {\n                gid[u] = gb; gid[v] = ga;\n                pos[u] = pv; pos[v] = pu;\n                gcost[ga] = nA;\n                gcost[gb] = nB;\n                return true;\n            } else {\n                swap(A[pu], B[pv]);\n                return false;\n            }\n        };\n\n        while (Clock::now() < stage1 && opBudget > 0) {\n            bool improved = false;\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int it = 0; it < N; it++) {\n                if ((it & 31) == 0) {\n                    if (Clock::now() >= stage1 || opBudget <= 0) break;\n                }\n\n                int u = order[it];\n                bool ok = false;\n\n                int T = min(12, (int)near[u].size());\n                for (int i = 0; i < T; i++) {\n                    int v = near[u][i];\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        ok = true;\n                        break;\n                    }\n                }\n                if (ok) continue;\n\n                for (int r = 0; r < 2; r++) {\n                    int v = uid(rng);\n                    if (v == u) continue;\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n\n        auto try_pair_repartition = [&](int a, int b) -> bool {\n            if (a == b) return false;\n            int sa = (int)groups[a].size();\n            int sb = (int)groups[b].size();\n            if (sa == 0 || sb == 0) return false;\n            if (sa + sb > 220) return false;\n\n            vector<int> U = groups[a];\n            U.insert(U.end(), groups[b].begin(), groups[b].end());\n\n            long long oldCost = gcost[a] + gcost[b];\n            long long bestCost = oldCost;\n            long long bestCA = gcost[a], bestCB = gcost[b];\n            vector<int> bestA = groups[a], bestB = groups[b];\n\n            auto centroid = [&](const vector<int>& V) -> pair<double,double> {\n                double sx = 0.0, sy = 0.0;\n                for (int c : V) {\n                    sx += cx2[c];\n                    sy += cy2[c];\n                }\n                double inv = 1.0 / (double)V.size();\n                return {sx * inv, sy * inv};\n            };\n\n            auto [ax, ay] = centroid(groups[a]);\n            auto [bx, by] = centroid(groups[b]);\n\n            auto considerAB = [&](const vector<int>& A, const vector<int>& B) {\n                if ((int)A.size() != sa || (int)B.size() != sb) return;\n                long long cA = prim_cost(A, d_group);\n                long long cB = prim_cost(B, d_group);\n                if (cA + cB < bestCost) {\n                    bestCost = cA + cB;\n                    bestCA = cA;\n                    bestCB = cB;\n                    bestA = A;\n                    bestB = B;\n                }\n            };\n\n            auto eval_sorted = [&](vector<pair<double,int>>& arr) {\n                sort(arr.begin(), arr.end(), [&](const auto& p1, const auto& p2) {\n                    if (fabs(p1.first - p2.first) > 1e-12) return p1.first < p2.first;\n                    return p1.second < p2.second;\n                });\n\n                vector<int> A, B;\n                A.reserve(sa); B.reserve(sb);\n\n                // first sa -> A\n                for (int i = 0; i < sa; i++) A.push_back(arr[i].second);\n                for (int i = sa; i < sa + sb; i++) B.push_back(arr[i].second);\n                considerAB(A, B);\n\n                // first sb -> B\n                A.clear(); B.clear();\n                for (int i = 0; i < sb; i++) B.push_back(arr[i].second);\n                for (int i = sb; i < sa + sb; i++) A.push_back(arr[i].second);\n                considerAB(A, B);\n            };\n\n            // proposal 1: da-db\n            {\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    double dax = cx2[v] - ax, day = cy2[v] - ay;\n                    double dbx = cx2[v] - bx, dby = cy2[v] - by;\n                    double da = dax * dax + day * day;\n                    double db = dbx * dbx + dby * dby;\n                    arr.push_back({da - db, v});\n                }\n                eval_sorted(arr);\n            }\n\n            // proposal 2: centroid axis projection\n            {\n                double vx = bx - ax, vy = by - ay;\n                if (fabs(vx) + fabs(vy) < 1e-12) {\n                    double ang = uniform_real_distribution<double>(0.0, acos(-1.0))(rng);\n                    vx = cos(ang); vy = sin(ang);\n                }\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    arr.push_back({vx * cx2[v] + vy * cy2[v], v});\n                }\n                eval_sorted(arr);\n            }\n\n            // proposal 3: random projection\n            {\n                double ang = uniform_real_distribution<double>(0.0, acos(-1.0))(rng);\n                double vx = cos(ang), vy = sin(ang);\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    arr.push_back({vx * cx2[v] + vy * cy2[v], v});\n                }\n                eval_sorted(arr);\n            }\n\n            if (bestCost < oldCost) {\n                groups[a] = std::move(bestA);\n                groups[b] = std::move(bestB);\n                gcost[a] = bestCA;\n                gcost[b] = bestCB;\n\n                for (int i = 0; i < (int)groups[a].size(); i++) {\n                    int c = groups[a][i];\n                    gid[c] = a;\n                    pos[c] = i;\n                }\n                for (int i = 0; i < (int)groups[b].size(); i++) {\n                    int c = groups[b][i];\n                    gid[c] = b;\n                    pos[c] = i;\n                }\n                return true;\n            }\n            return false;\n        };\n\n        for (int pass = 0; pass < 3; pass++) {\n            if (Clock::now() >= deadline) break;\n\n            vector<pair<double,double>> cent(M, {0.0, 0.0});\n            for (int g = 0; g < M; g++) {\n                double sx = 0.0, sy = 0.0;\n                for (int c : groups[g]) {\n                    sx += cx2[c];\n                    sy += cy2[c];\n                }\n                if (!groups[g].empty()) {\n                    double inv = 1.0 / (double)groups[g].size();\n                    cent[g] = {sx * inv, sy * inv};\n                }\n            }\n\n            const int K = 5;\n            vector<pair<int,int>> pairs;\n            vector<char> seen(M * M, 0);\n\n            for (int a = 0; a < M; a++) {\n                vector<pair<double,int>> arr;\n                arr.reserve(M - 1);\n                for (int b = 0; b < M; b++) {\n                    if (a == b) continue;\n                    double dx = cent[a].first - cent[b].first;\n                    double dy = cent[a].second - cent[b].second;\n                    arr.push_back({dx * dx + dy * dy, b});\n                }\n\n                int k = min(K, (int)arr.size());\n                if ((int)arr.size() > k) {\n                    nth_element(arr.begin(), arr.begin() + k, arr.end(),\n                                [&](const auto& p1, const auto& p2) { return p1.first < p2.first; });\n                    arr.resize(k);\n                }\n                sort(arr.begin(), arr.end(),\n                     [&](const auto& p1, const auto& p2) { return p1.first < p2.first; });\n\n                for (auto& e : arr) {\n                    int b = e.second;\n                    int x = min(a, b), y = max(a, b);\n                    int key = x * M + y;\n                    if (!seen[key]) {\n                        seen[key] = 1;\n                        pairs.push_back({x, y});\n                    }\n                }\n            }\n\n            shuffle(pairs.begin(), pairs.end(), rng);\n\n            bool improved = false;\n            for (auto [a, b] : pairs) {\n                if (Clock::now() >= deadline) break;\n                if (try_pair_repartition(a, b)) improved = true;\n            }\n            if (!improved) break;\n        }\n    }\n\n    int choose_medoid_idx(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        int best = 0;\n        long long bestSum = (1LL << 62);\n\n        for (int i = 0; i < n; i++) {\n            int a = nodes[i];\n            int base = a * N;\n            long long s = 0;\n            for (int j = 0; j < n; j++) {\n                s += d_base[base + nodes[j]];\n                if (s >= bestSum) break;\n            }\n            if (s < bestSum) {\n                bestSum = s;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_base_group_edges(const vector<int>& nodes, int& q_used, vector<pair<int,int>>& cand_store) {\n        int g = (int)nodes.size();\n        vector<pair<int,int>> base;\n        if (g <= 1) return base;\n\n        auto append_ret = [&](const vector<pair<int,int>>& ret) {\n            for (auto [a, b] : ret) {\n                if (a > b) swap(a, b);\n                base.emplace_back(a, b);\n                cand_store.emplace_back(a, b);\n            }\n        };\n\n        if (g == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            base.push_back(p);\n            cand_store.push_back(p);\n            return base;\n        }\n\n        int need = query_need(g);\n        if (q_used + need > Q) {\n            base = prim_tree(nodes, d_base);\n            cand_store.insert(cand_store.end(), base.begin(), base.end());\n            return base;\n        }\n\n        vector<int> ord = nodes;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        if (g <= L) {\n            auto ret = do_query(ord);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n            if ((int)base.size() != g - 1) {\n                base = prim_tree(nodes, d_base);\n                cand_store.insert(cand_store.end(), base.begin(), base.end());\n            }\n            return base;\n        }\n\n        int root = choose_medoid_idx(ord);\n\n        vector<char> conn(g, 0);\n        vector<int> nearestDist(g, (int)1e9), nearestAnchor(g, -1);\n\n        // first query: root + nearest (L-1)\n        vector<pair<int,int>> arr;\n        arr.reserve(g - 1);\n        for (int i = 0; i < g; i++) {\n            if (i == root) continue;\n            arr.push_back({DBase(ord[root], ord[i]), i});\n        }\n        sort(arr.begin(), arr.end(), [&](const auto& p1, const auto& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        });\n\n        int t0 = min(L - 1, g - 1);\n        vector<int> firstIdx;\n        firstIdx.reserve(t0);\n        for (int i = 0; i < t0; i++) firstIdx.push_back(arr[i].second);\n\n        vector<int> subset;\n        subset.reserve(1 + t0);\n        subset.push_back(ord[root]);\n        for (int idx : firstIdx) subset.push_back(ord[idx]);\n\n        {\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n        }\n\n        conn[root] = 1;\n        for (int idx : firstIdx) conn[idx] = 1;\n        int rem = g - 1 - t0;\n\n        auto update_by_new = [&](int idx) {\n            int c = ord[idx];\n            for (int j = 0; j < g; j++) {\n                if (conn[j]) continue;\n                int d = DBase(c, ord[j]);\n                if (d < nearestDist[j]) {\n                    nearestDist[j] = d;\n                    nearestAnchor[j] = idx;\n                }\n            }\n        };\n\n        for (int i = 0; i < g; i++) {\n            nearestDist[i] = (int)1e9;\n            nearestAnchor[i] = -1;\n        }\n        update_by_new(root);\n        for (int idx : firstIdx) update_by_new(idx);\n\n        while (rem > 0) {\n            int u = -1, best = (int)1e9;\n            for (int i = 0; i < g; i++) {\n                if (!conn[i] && nearestDist[i] < best) {\n                    best = nearestDist[i];\n                    u = i;\n                }\n            }\n            if (u < 0) break;\n\n            int anchor = nearestAnchor[u];\n            if (anchor < 0) anchor = root;\n\n            int t = min(L - 1, rem);\n            vector<int> batch;\n            batch.reserve(t);\n            batch.push_back(u);\n\n            if (t > 1) {\n                vector<pair<int,int>> cand;\n                cand.reserve(rem - 1);\n                int ac = ord[anchor];\n                for (int i = 0; i < g; i++) {\n                    if (conn[i] || i == u) continue;\n                    cand.push_back({DBase(ac, ord[i]), i});\n                }\n                sort(cand.begin(), cand.end(), [&](const auto& p1, const auto& p2) {\n                    if (p1.first != p2.first) return p1.first < p2.first;\n                    return p1.second < p2.second;\n                });\n                for (int i = 0; i < t - 1 && i < (int)cand.size(); i++) {\n                    batch.push_back(cand[i].second);\n                }\n            }\n\n            subset.clear();\n            subset.push_back(ord[anchor]);\n            for (int idx : batch) subset.push_back(ord[idx]);\n\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n\n            for (int idx : batch) {\n                if (!conn[idx]) {\n                    conn[idx] = 1;\n                    rem--;\n                }\n            }\n            for (int idx : batch) update_by_new(idx);\n        }\n\n        if ((int)base.size() != g - 1) {\n            base = prim_tree(nodes, d_base);\n            cand_store.insert(cand_store.end(), base.begin(), base.end());\n        }\n        return base;\n    }\n\n    vector<int> make_subset_window(const vector<int>& ordz) {\n        int g = (int)ordz.size();\n        int l = min(L, g);\n        if (l < 2) return {};\n        if (g == l) return ordz;\n        int s = uniform_int_distribution<int>(0, g - l)(rng);\n        return vector<int>(ordz.begin() + s, ordz.begin() + s + l);\n    }\n\n    vector<int> make_subset_star(const vector<int>& nodes) {\n        int g = (int)nodes.size();\n        int l = min(L, g);\n        if (l < 2) return {};\n        if (g == l) return nodes;\n\n        int center = nodes[uniform_int_distribution<int>(0, g - 1)(rng)];\n        vector<pair<int,int>> arr;\n        arr.reserve(g - 1);\n        for (int v : nodes) if (v != center) {\n            arr.push_back({DBase(center, v), v});\n        }\n\n        auto cmp = [](const pair<int,int>& p1, const pair<int,int>& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        };\n\n        if ((int)arr.size() > l - 1) {\n            nth_element(arr.begin(), arr.begin() + (l - 1), arr.end(), cmp);\n            arr.resize(l - 1);\n        }\n        sort(arr.begin(), arr.end(), cmp);\n\n        vector<int> subset;\n        subset.reserve(l);\n        subset.push_back(center);\n        for (auto& p : arr) {\n            if ((int)subset.size() >= l) break;\n            subset.push_back(p.second);\n        }\n\n        if ((int)subset.size() < 2) {\n            for (int v : nodes) if (v != center) {\n                subset.push_back(v);\n                break;\n            }\n        }\n        return subset;\n    }\n\n    vector<pair<int,int>> mst_from_candidates(const vector<int>& nodes, const vector<pair<int,int>>& cand) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return {};\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            return {p};\n        }\n\n        vector<int> loc(N, -1);\n        for (int i = 0; i < n; i++) loc[nodes[i]] = i;\n\n        unordered_map<int, int> cnt;\n        cnt.reserve(cand.size() * 2 + 1);\n\n        for (auto [a, b] : cand) {\n            if (a > b) swap(a, b);\n            if (a < 0 || b < 0 || a >= N || b >= N || a == b) continue;\n            if (loc[a] < 0 || loc[b] < 0) continue;\n            int key = a * EDGE_BASE + b;\n            cnt[key]++;\n        }\n\n        struct E {\n            long long w;\n            int a, b;\n        };\n        vector<E> es;\n        es.reserve(cnt.size());\n\n        for (auto& kv : cnt) {\n            int key = kv.first;\n            int c = kv.second;\n            int a = key / EDGE_BASE;\n            int b = key % EDGE_BASE;\n\n            long long w = 1LL * d_base[ID(a, b)] * 10 - 90LL * min(c, 6);\n            es.push_back({w, a, b});\n        }\n\n        sort(es.begin(), es.end(), [&](const E& e1, const E& e2) {\n            if (e1.w != e2.w) return e1.w < e2.w;\n            if (e1.a != e2.a) return e1.a < e2.a;\n            return e1.b < e2.b;\n        });\n\n        DSU dsu(n);\n        vector<pair<int,int>> out;\n        out.reserve(n - 1);\n\n        for (auto& e : es) {\n            int ia = loc[e.a], ib = loc[e.b];\n            if (ia < 0 || ib < 0) continue;\n            if (dsu.unite(ia, ib)) {\n                int a = e.a, b = e.b;\n                if (a > b) swap(a, b);\n                out.emplace_back(a, b);\n                if ((int)out.size() == n - 1) break;\n            }\n        }\n\n        if ((int)out.size() != n - 1) return {};\n        return out;\n    }\n\n    vector<vector<int>> fallback_grouping() const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<vector<int>> groups(M);\n        int p = 0;\n        for (int k = 0; k < M; k++) {\n            groups[k].assign(ord.begin() + p, ord.begin() + p + G[k]);\n            p += G[k];\n        }\n        return groups;\n    }\n\n    void solve() {\n        input();\n        init_rng();\n        preprocess();\n\n        int reqMin = 0;\n        for (int g : G) reqMin += query_need(g);\n        int spare = Q - reqMin;\n\n        int q_used = 0;\n        int q_explore = 0;\n        if (spare > 20) {\n            if (spare <= 80) q_explore = spare / 3;\n            else if (spare <= 180) q_explore = spare / 2;\n            else q_explore = (spare * 2) / 3;\n            q_explore = min(q_explore, 180);\n            q_explore = min(q_explore, spare);\n        }\n\n        // 1) Exploration for better grouping\n        perform_exploration(q_explore, q_used);\n        rebuild_group_matrix_from_obs();\n\n        // 2) Grouping + local improvement (on learned distance)\n        auto groups = make_grouping();\n        if (!validate_groups(groups)) groups = fallback_grouping();\n\n        optimize_groups(groups, 0.72);\n        if (!validate_groups(groups)) groups = fallback_grouping();\n\n        // 3) Mandatory group-edge construction queries\n        vector<vector<pair<int,int>>> baseEdges(M), candEdges(M);\n\n        vector<int> gidOrder(M);\n        iota(gidOrder.begin(), gidOrder.end(), 0);\n        sort(gidOrder.begin(), gidOrder.end(), [&](int a, int b) {\n            if ((int)groups[a].size() != (int)groups[b].size()) return groups[a].size() > groups[b].size();\n            return a < b;\n        });\n\n        for (int gid : gidOrder) {\n            baseEdges[gid] = build_base_group_edges(groups[gid], q_used, candEdges[gid]);\n        }\n\n        // 4) Extra queries for large groups only\n        if (q_used < Q) {\n            vector<int> targets;\n            for (int g = 0; g < M; g++) if ((int)groups[g].size() > L) targets.push_back(g);\n\n            if (!targets.empty()) {\n                vector<vector<int>> ordz(M);\n                for (int gid : targets) {\n                    ordz[gid] = groups[gid];\n                    sort(ordz[gid].begin(), ordz[gid].end(), [&](int a, int b) {\n                        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                        return a < b;\n                    });\n                }\n\n                vector<double> weights;\n                weights.reserve(targets.size());\n                for (int gid : targets) {\n                    double sz = (double)groups[gid].size();\n                    weights.push_back(pow(sz, 1.35));\n                }\n\n                discrete_distribution<int> pick(weights.begin(), weights.end());\n\n                while (q_used < Q) {\n                    int gid = targets[pick(rng)];\n                    vector<int> subset;\n                    int mode = uniform_int_distribution<int>(0, 99)(rng);\n                    if (mode < 55) subset = make_subset_window(ordz[gid]);\n                    else subset = make_subset_star(groups[gid]);\n\n                    if ((int)subset.size() < 2) continue;\n                    auto ret = do_query(subset);\n                    q_used++;\n                    record_edges(ret);\n\n                    for (auto [a, b] : ret) {\n                        if (a > b) swap(a, b);\n                        candEdges[gid].emplace_back(a, b);\n                    }\n                }\n            }\n        }\n\n        // 5) Build final trees\n        vector<int> city_gid(N, -1);\n        for (int g = 0; g < M; g++) {\n            for (int c : groups[g]) city_gid[c] = g;\n        }\n\n        // Add all observed in-group edges (explore + mandatory + extra) as candidates\n        for (auto [a, b] : touchedObs) {\n            int ga = city_gid[a], gb = city_gid[b];\n            if (ga >= 0 && ga == gb) {\n                int c = (int)obsCnt[ID(a, b)];\n                int rep = min(4, c);\n                for (int t = 0; t < rep; t++) candEdges[ga].emplace_back(a, b);\n            }\n        }\n\n        vector<vector<pair<int,int>>> finalEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int sz = (int)groups[k].size();\n            if (sz <= 1) {\n                finalEdges[k].clear();\n                continue;\n            }\n\n            if ((int)baseEdges[k].size() != sz - 1) {\n                baseEdges[k] = prim_tree(groups[k], d_base);\n            }\n\n            // If sz<=L, baseEdges is exact MST query result (or trivial), so keep it.\n            if (sz <= L) {\n                finalEdges[k] = baseEdges[k];\n                continue;\n            }\n\n            auto candTree = mst_from_candidates(groups[k], candEdges[k]);\n            if ((int)candTree.size() == sz - 1) {\n                long long bc = edge_proxy_cost(baseEdges[k], d_base);\n                long long cc = edge_proxy_cost(candTree, d_base);\n                if (cc < bc) finalEdges[k] = std::move(candTree);\n                else finalEdges[k] = baseEdges[k];\n            } else {\n                finalEdges[k] = baseEdges[k];\n            }\n\n            if ((int)finalEdges[k].size() != sz - 1) {\n                finalEdges[k] = prim_tree(groups[k], d_base);\n            }\n        }\n\n        // 6) Output\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n            for (auto [a, b] : finalEdges[k]) {\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int r, c; };\nstruct Action { char a, d; };\n\nclass Solver {\n    static constexpr int MAXN = 20;\n    static constexpr int INF = 1e9;\n    using Clock = chrono::steady_clock;\n\n    int N, M, LIMIT, n2;\n    vector<Point> pts;                 // pts[0]=start, pts[1..]=targets\n    vector<int> pid;                   // cell id for pts[i]\n    vector<int> cellR, cellC;          // cell id -> r,c\n    vector<array<int,4>> to;           // neighbors for move\n    vector<int> targetIdxAtCell;       // cell id -> index in pts, -1 if non-target\n\n    array<uint32_t, MAXN> lowMask{}, highMask{};\n    const array<int,4> DR{{-1, 1, 0, 0}};\n    const array<int,4> DC{{0, 0, -1, 1}};\n    const array<char,4> DCH{{'U','D','L','R'}};\n\n    struct Node {\n        array<uint32_t, MAXN> row{};\n        array<uint32_t, MAXN> col{};\n        int cost = INF;\n        int parent = -1;          // index in previous layer\n        uint8_t op = 0;           // 0:none, 1:A, 2:M+A, 3:S+A, 4:A+A\n        uint8_t d1 = 0, d2 = 0;   // params for op\n        uint16_t bcnt = 0;        // number of blocked cells (tracked incrementally)\n        int eval = 0;\n    };\n\n    struct Config {\n        bool allowFutureToggle = false;\n        bool enableDoubleAlter = false; // A+A\n        int wEarly = 180, wMid = 140, wLate = 110;\n        int preMul = 6;\n        int elitePct = 50;\n\n        int wCost = 10;\n        int wH1 = 4;\n        int wH2 = 2;\n        int wFutureBlocked = 0;\n        int wBlockBonus = 1;\n        int evalDistLimit = 55;\n    };\n\n    inline int widthAt(const Config& cfg, int k) const {\n        if (k < 12) return cfg.wEarly;\n        if (k < 26) return cfg.wMid;\n        return cfg.wLate;\n    }\n\n    inline bool isBlocked(const array<uint32_t,MAXN>& row, int id) const {\n        return ((row[cellR[id]] >> cellC[id]) & 1u) != 0u;\n    }\n\n    inline void toggleCell(array<uint32_t,MAXN>& row, array<uint32_t,MAXN>& col, int id) const {\n        int r = cellR[id], c = cellC[id];\n        row[r] ^= (1u << c);\n        col[c] ^= (1u << r);\n    }\n\n    inline int rowCompare(const array<uint32_t,MAXN>& a, const array<uint32_t,MAXN>& b) const {\n        return memcmp(a.data(), b.data(), N * sizeof(uint32_t));\n    }\n\n    inline bool isEmptyBoard(const array<uint32_t,MAXN>& row) const {\n        for (int r = 0; r < N; r++) if (row[r]) return false;\n        return true;\n    }\n\n    inline bool allowToggleCell(int cell, int k, const Config& cfg) const {\n        if (cell < 0) return false;\n        if (cfg.allowFutureToggle) return true;\n        int idx = targetIdxAtCell[cell];\n        return !(idx != -1 && idx > k);\n    }\n\n    inline int slideDest(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col, int u, int d) const {\n        int r = cellR[u], c = cellC[u];\n        if (d == 0) { // U\n            uint32_t m = col[c] & lowMask[r];\n            int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n            return nr * N + c;\n        } else if (d == 1) { // D\n            uint32_t m = col[c] & highMask[r];\n            int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n            return nr * N + c;\n        } else if (d == 2) { // L\n            uint32_t m = row[r] & lowMask[c];\n            int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n            return r * N + nc;\n        } else { // R\n            uint32_t m = row[r] & highMask[c];\n            int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n            return r * N + nc;\n        }\n    }\n\n    // Returns shortest distance if <= lim, else INF.\n    int bfsDistLimit(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                     int s, int g, int lim) const {\n        if (lim < 0) return INF;\n        if (s == g) return 0;\n\n        int dist[400];\n        for (int i = 0; i < n2; i++) dist[i] = -1;\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            if (du > lim) continue;\n            int r = cellR[u], c = cellC[u];\n\n            // Move\n            for (int d = 0; d < 4; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du;\n                if (v == g) return du;\n                q[tail++] = v;\n            }\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n        }\n        return INF;\n    }\n\n    bool bfsPath(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                 int s, int g, vector<Action>& out) const {\n        out.clear();\n        if (s == g) return true;\n\n        int dist[400], par[400];\n        uint8_t pdir[400];\n        char pact[400];\n        for (int i = 0; i < n2; i++) {\n            dist[i] = -1;\n            par[i] = -1;\n        }\n\n        int q[400], head = 0, tail = 0;\n        dist[s] = 0;\n        par[s] = s;\n        q[tail++] = s;\n\n        bool found = false;\n        while (head < tail && !found) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            auto relax = [&](int v, char a, int d)->bool {\n                if (v == u) return false;\n                if (dist[v] != -1) return false;\n                dist[v] = du;\n                par[v] = u;\n                pact[v] = a;\n                pdir[v] = (uint8_t)d;\n                q[tail++] = v;\n                return v == g;\n            };\n\n            // Move\n            for (int d = 0; d < 4 && !found; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (relax(v, 'M', d)) found = true;\n            }\n            if (found) break;\n\n            // Slides\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 0)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 1)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 2)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 3)) found = true;\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        vector<Action> rev;\n        int cur = g;\n        while (cur != s) {\n            if (cur < 0 || par[cur] < 0) return false;\n            rev.push_back(Action{pact[cur], DCH[pdir[cur]]});\n            cur = par[cur];\n        }\n        reverse(rev.begin(), rev.end());\n        out.swap(rev);\n        return true;\n    }\n\n    int countBlockedFutureTargets(const array<uint32_t,MAXN>& row, int fromIdx) const {\n        if (fromIdx >= M) return 0;\n        int cnt = 0;\n        for (int i = fromIdx; i < M; i++) {\n            int id = pid[i];\n            if ((row[cellR[id]] >> cellC[id]) & 1u) cnt++;\n        }\n        return cnt;\n    }\n\n    vector<Action> fallbackManhattan() const {\n        vector<Action> ans;\n        int r = pts[0].r, c = pts[0].c;\n        for (int k = 1; k < M; k++) {\n            int tr = pts[k].r, tc = pts[k].c;\n            while (r < tr) { ans.push_back({'M','D'}); r++; }\n            while (r > tr) { ans.push_back({'M','U'}); r--; }\n            while (c < tc) { ans.push_back({'M','R'}); c++; }\n            while (c > tc) { ans.push_back({'M','L'}); c--; }\n        }\n        return ans;\n    }\n\n    vector<Action> fallbackNoBlock() const {\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u); col.fill(0u);\n\n        vector<Action> ans;\n        int cur = pid[0];\n        for (int k = 0; k < M - 1; k++) {\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, pid[k+1], path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = pid[k+1];\n        }\n        return ans;\n    }\n\n    bool validate(const vector<Action>& acts) const {\n        if ((int)acts.size() > LIMIT) return false;\n        vector<vector<uint8_t>> blk(N, vector<uint8_t>(N, 0));\n\n        int r = pts[0].r, c = pts[0].c;\n        int nxt = 1;\n\n        auto dirId = [&](char ch)->int {\n            if (ch == 'U') return 0;\n            if (ch == 'D') return 1;\n            if (ch == 'L') return 2;\n            if (ch == 'R') return 3;\n            return -1;\n        };\n\n        for (const auto& ac : acts) {\n            int d = dirId(ac.d);\n            if (d < 0) return false;\n\n            if (ac.a == 'M') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                if (blk[nr][nc]) return false;\n                r = nr; c = nc;\n            } else if (ac.a == 'S') {\n                int nr = r, nc = c;\n                while (true) {\n                    int tr = nr + DR[d], tc = nc + DC[d];\n                    if (!(0 <= tr && tr < N && 0 <= tc && tc < N)) break;\n                    if (blk[tr][tc]) break;\n                    nr = tr; nc = tc;\n                }\n                r = nr; c = nc;\n            } else if (ac.a == 'A') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                blk[nr][nc] ^= 1;\n            } else {\n                return false;\n            }\n\n            if (nxt < M && r == pts[nxt].r && c == pts[nxt].c) nxt++;\n        }\n\n        return nxt == M;\n    }\n\n    vector<Action> runBeam(int upperBound, const Config& cfg, Clock::time_point dl) {\n        if (upperBound <= 0) return {};\n\n        vector<vector<Node>> layers(M);\n        layers[0].reserve(1);\n        Node init;\n        init.row.fill(0u);\n        init.col.fill(0u);\n        init.cost = 0;\n        init.parent = -1;\n        init.op = 0;\n        init.d1 = init.d2 = 0;\n        init.bcnt = 0;\n        layers[0].push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            if (Clock::now() >= dl) return {};\n\n            int s = pid[k], g = pid[k+1];\n            int W = widthAt(cfg, k);\n            int PRE = max(W + 1, W * cfg.preMul);\n\n            int approxTrans = 1 + 4 + 16 + 16 + (cfg.enableDoubleAlter ? 6 : 0);\n            vector<Node> cand;\n            cand.reserve((int)layers[k].size() * approxTrans + 16);\n\n            for (int si = 0; si < (int)layers[k].size(); si++) {\n                if ((si & 15) == 0 && Clock::now() >= dl) return {};\n                const Node& st = layers[k][si];\n\n                // 0) no prep\n                {\n                    int rem = upperBound - 1 - st.cost;\n                    if (rem >= 0) {\n                        int d0 = bfsDistLimit(st.row, st.col, s, g, rem);\n                        if (d0 < INF) {\n                            Node nd = st;\n                            nd.cost = st.cost + d0;\n                            nd.parent = si;\n                            nd.op = 0;\n                            nd.d1 = nd.d2 = 0;\n                            nd.eval = 0;\n                            cand.push_back(std::move(nd));\n                        }\n                    }\n                }\n\n                // 1) A\n                {\n                    int rem = upperBound - 1 - (st.cost + 1);\n                    if (rem >= 0) {\n                        array<uint32_t,MAXN> rowA = st.row;\n                        array<uint32_t,MAXN> colA = st.col;\n\n                        for (int ad = 0; ad < 4; ad++) {\n                            int tcell = to[s][ad];\n                            if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                            bool was = isBlocked(rowA, tcell);\n                            toggleCell(rowA, colA, tcell);\n\n                            int d = bfsDistLimit(rowA, colA, s, g, rem);\n                            if (d < INF) {\n                                Node nd;\n                                nd.row = rowA;\n                                nd.col = colA;\n                                nd.cost = st.cost + 1 + d;\n                                nd.parent = si;\n                                nd.op = 1;\n                                nd.d1 = (uint8_t)ad;\n                                nd.d2 = 0;\n                                int nb = (int)st.bcnt + (was ? -1 : +1);\n                                if (nb < 0) nb = 0;\n                                nd.bcnt = (uint16_t)nb;\n                                nd.eval = 0;\n                                cand.push_back(std::move(nd));\n                            }\n\n                            toggleCell(rowA, colA, tcell); // revert\n                        }\n                    }\n                }\n\n                // 2) M + A\n                // 3) S + A\n                {\n                    int rem = upperBound - 1 - (st.cost + 2);\n                    if (rem >= 0) {\n                        // M + A\n                        for (int md = 0; md < 4; md++) {\n                            int ncell = to[s][md];\n                            if (ncell == -1) continue;\n                            if (isBlocked(st.row, ncell)) continue; // move first\n\n                            array<uint32_t,MAXN> rowMA = st.row;\n                            array<uint32_t,MAXN> colMA = st.col;\n\n                            for (int ad = 0; ad < 4; ad++) {\n                                int tcell = to[ncell][ad];\n                                if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                                bool was = isBlocked(rowMA, tcell);\n                                toggleCell(rowMA, colMA, tcell);\n\n                                int d = bfsDistLimit(rowMA, colMA, ncell, g, rem);\n                                if (d < INF) {\n                                    Node nd;\n                                    nd.row = rowMA;\n                                    nd.col = colMA;\n                                    nd.cost = st.cost + 2 + d;\n                                    nd.parent = si;\n                                    nd.op = 2;\n                                    nd.d1 = (uint8_t)md;\n                                    nd.d2 = (uint8_t)ad;\n                                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                                    if (nb < 0) nb = 0;\n                                    nd.bcnt = (uint16_t)nb;\n                                    nd.eval = 0;\n                                    cand.push_back(std::move(nd));\n                                }\n\n                                toggleCell(rowMA, colMA, tcell); // revert\n                            }\n                        }\n\n                        // S + A\n                        for (int sd = 0; sd < 4; sd++) {\n                            int ncell = slideDest(st.row, st.col, s, sd);\n                            if (ncell == s) continue; // cannot slide\n\n                            array<uint32_t,MAXN> rowSA = st.row;\n                            array<uint32_t,MAXN> colSA = st.col;\n\n                            for (int ad = 0; ad < 4; ad++) {\n                                int tcell = to[ncell][ad];\n                                if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                                bool was = isBlocked(rowSA, tcell);\n                                toggleCell(rowSA, colSA, tcell);\n\n                                int d = bfsDistLimit(rowSA, colSA, ncell, g, rem);\n                                if (d < INF) {\n                                    Node nd;\n                                    nd.row = rowSA;\n                                    nd.col = colSA;\n                                    nd.cost = st.cost + 2 + d;\n                                    nd.parent = si;\n                                    nd.op = 3;\n                                    nd.d1 = (uint8_t)sd;\n                                    nd.d2 = (uint8_t)ad;\n                                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                                    if (nb < 0) nb = 0;\n                                    nd.bcnt = (uint16_t)nb;\n                                    nd.eval = 0;\n                                    cand.push_back(std::move(nd));\n                                }\n\n                                toggleCell(rowSA, colSA, tcell); // revert\n                            }\n                        }\n\n                        // 4) A + A (optional)\n                        if (cfg.enableDoubleAlter) {\n                            array<uint32_t,MAXN> rowAA = st.row;\n                            array<uint32_t,MAXN> colAA = st.col;\n\n                            for (int d1 = 0; d1 < 4; d1++) {\n                                int c1 = to[s][d1];\n                                if (!allowToggleCell(c1, k, cfg)) continue;\n\n                                bool was1 = isBlocked(rowAA, c1);\n                                toggleCell(rowAA, colAA, c1);\n                                int delta1 = was1 ? -1 : +1;\n\n                                for (int d2 = d1 + 1; d2 < 4; d2++) {\n                                    int c2 = to[s][d2];\n                                    if (!allowToggleCell(c2, k, cfg)) continue;\n\n                                    bool was2 = isBlocked(rowAA, c2); // c2 != c1\n                                    toggleCell(rowAA, colAA, c2);\n\n                                    int d = bfsDistLimit(rowAA, colAA, s, g, rem);\n                                    if (d < INF) {\n                                        Node nd;\n                                        nd.row = rowAA;\n                                        nd.col = colAA;\n                                        nd.cost = st.cost + 2 + d;\n                                        nd.parent = si;\n                                        nd.op = 4;\n                                        nd.d1 = (uint8_t)d1;\n                                        nd.d2 = (uint8_t)d2;\n                                        int nb = (int)st.bcnt + delta1 + (was2 ? -1 : +1);\n                                        if (nb < 0) nb = 0;\n                                        nd.bcnt = (uint16_t)nb;\n                                        nd.eval = 0;\n                                        cand.push_back(std::move(nd));\n                                    }\n\n                                    toggleCell(rowAA, colAA, c2); // revert d2\n                                }\n\n                                toggleCell(rowAA, colAA, c1); // revert d1\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (cand.empty()) return {};\n\n            // Dedup by board\n            sort(cand.begin(), cand.end(), [&](const Node& a, const Node& b) {\n                int cmp = rowCompare(a.row, b.row);\n                if (cmp != 0) return cmp < 0;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.bcnt != b.bcnt) return a.bcnt > b.bcnt;\n                return a.parent < b.parent;\n            });\n\n            vector<Node> uniq;\n            uniq.reserve(cand.size());\n            for (auto& nd : cand) {\n                if (uniq.empty() || rowCompare(uniq.back().row, nd.row) != 0) {\n                    uniq.push_back(nd);\n                } else {\n                    Node& cur = uniq.back();\n                    if (nd.cost < cur.cost || (nd.cost == cur.cost && nd.bcnt > cur.bcnt)) {\n                        cur = nd;\n                    }\n                }\n            }\n\n            sort(uniq.begin(), uniq.end(), [](const Node& a, const Node& b) {\n                if (a.cost != b.cost) return a.cost < b.cost;\n                return a.bcnt > b.bcnt;\n            });\n\n            if ((int)uniq.size() > PRE) uniq.resize(PRE);\n\n            // Heuristic pruning\n            if ((int)uniq.size() > W) {\n                int from1 = pid[k+1];\n                int to1 = (k + 2 < M ? pid[k+2] : -1);\n                int from2 = (k + 2 < M ? pid[k+2] : -1);\n                int to2 = (k + 3 < M ? pid[k+3] : -1);\n\n                for (auto& nd : uniq) {\n                    int h1 = 0, h2 = 0;\n                    if (to1 != -1) {\n                        h1 = bfsDistLimit(nd.row, nd.col, from1, to1, cfg.evalDistLimit);\n                        if (h1 >= INF) h1 = cfg.evalDistLimit + 20;\n                    }\n                    if (to2 != -1) {\n                        h2 = bfsDistLimit(nd.row, nd.col, from2, to2, cfg.evalDistLimit);\n                        if (h2 >= INF) h2 = cfg.evalDistLimit + 20;\n                    }\n                    int fblk = (cfg.wFutureBlocked > 0) ? countBlockedFutureTargets(nd.row, k + 2) : 0;\n                    nd.eval = nd.cost * cfg.wCost\n                              + h1 * cfg.wH1\n                              + h2 * cfg.wH2\n                              + fblk * cfg.wFutureBlocked\n                              - min<int>(nd.bcnt, 40) * cfg.wBlockBonus;\n                }\n\n                vector<int> ord(uniq.size());\n                iota(ord.begin(), ord.end(), 0);\n                sort(ord.begin(), ord.end(), [&](int i, int j) {\n                    const Node& a = uniq[i];\n                    const Node& b = uniq[j];\n                    if (a.eval != b.eval) return a.eval < b.eval;\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                vector<Node> chosen;\n                chosen.reserve(W);\n                vector<char> used(uniq.size(), 0);\n\n                int elite = max(1, W * cfg.elitePct / 100);\n                elite = min(elite, (int)uniq.size());\n\n                for (int i = 0; i < elite; i++) {\n                    chosen.push_back(uniq[i]);\n                    used[i] = 1;\n                }\n                for (int id : ord) {\n                    if ((int)chosen.size() >= W) break;\n                    if (used[id]) continue;\n                    chosen.push_back(uniq[id]);\n                    used[id] = 1;\n                }\n\n                // keep empty-board state if available\n                bool hasEmpty = false;\n                for (const auto& nd : chosen) {\n                    if (isEmptyBoard(nd.row)) { hasEmpty = true; break; }\n                }\n                if (!hasEmpty) {\n                    for (const auto& nd : uniq) {\n                        if (isEmptyBoard(nd.row)) {\n                            if (!chosen.empty()) chosen.back() = nd;\n                            else chosen.push_back(nd);\n                            break;\n                        }\n                    }\n                }\n\n                sort(chosen.begin(), chosen.end(), [](const Node& a, const Node& b) {\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                uniq.swap(chosen);\n            }\n\n            if (uniq.empty()) return {};\n            layers[k+1].swap(uniq);\n        }\n\n        if (layers[M-1].empty()) return {};\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)layers[M-1].size(); i++) {\n            if (layers[M-1][i].cost < layers[M-1][bestIdx].cost) bestIdx = i;\n        }\n\n        struct Dec { uint8_t op, d1, d2; };\n        vector<Dec> dec(max(0, M - 1));\n\n        int idx = bestIdx;\n        for (int k = M - 2; k >= 0; k--) {\n            const Node& nd = layers[k+1][idx];\n            dec[k] = Dec{nd.op, nd.d1, nd.d2};\n            idx = nd.parent;\n            if (idx < 0 && k > 0) return {};\n        }\n        if (M >= 2 && idx < 0) return {};\n\n        // Reconstruct concrete actions\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u);\n        col.fill(0u);\n\n        int cur = pid[0];\n        vector<Action> ans;\n        ans.reserve(layers[M-1][bestIdx].cost + 16);\n\n        for (int k = 0; k < M - 1; k++) {\n            int s = pid[k], g = pid[k+1];\n            if (cur != s) return {};\n\n            auto [op, d1, d2] = dec[k];\n\n            if (op == 1) { // A\n                int t = to[cur][d1];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d1]});\n                toggleCell(row, col, t);\n\n            } else if (op == 2) { // M + A\n                int ncell = to[cur][d1];\n                if (ncell == -1 || isBlocked(row, ncell)) return {};\n                ans.push_back({'M', DCH[d1]});\n                cur = ncell;\n\n                int t = to[cur][d2];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t);\n\n            } else if (op == 3) { // S + A\n                int ncell = slideDest(row, col, cur, d1);\n                if (ncell == cur) return {};\n                ans.push_back({'S', DCH[d1]});\n                cur = ncell;\n\n                int t = to[cur][d2];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t);\n\n            } else if (op == 4) { // A + A\n                int t1 = to[cur][d1];\n                int t2 = to[cur][d2];\n                if (t1 == -1 || t2 == -1 || d1 == d2) return {};\n                ans.push_back({'A', DCH[d1]});\n                toggleCell(row, col, t1);\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t2);\n            }\n\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, g, path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = g;\n        }\n\n        return ans;\n    }\n\n    void init() {\n        n2 = N * N;\n        LIMIT = 2 * N * M;\n\n        pid.resize(M);\n        for (int i = 0; i < M; i++) pid[i] = pts[i].r * N + pts[i].c;\n\n        cellR.resize(n2);\n        cellC.resize(n2);\n        to.assign(n2, array<int,4>{-1,-1,-1,-1});\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                cellR[id] = r;\n                cellC[id] = c;\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + DR[d], nc = c + DC[d];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                        to[id][d] = nr * N + nc;\n                    }\n                }\n            }\n        }\n\n        for (int i = 0; i < MAXN; i++) {\n            lowMask[i] = (i == 0 ? 0u : ((1u << i) - 1u));\n            highMask[i] = ~((1u << (i + 1)) - 1u);\n        }\n\n        targetIdxAtCell.assign(n2, -1);\n        for (int i = 0; i < M; i++) {\n            targetIdxAtCell[pid[i]] = i;\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        pts.resize(M);\n        for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n        init();\n\n        vector<Action> best = fallbackNoBlock();\n        if (best.empty() || (int)best.size() > LIMIT || !validate(best)) {\n            best = fallbackManhattan();\n        }\n\n        auto start = Clock::now();\n        auto globalDL = start + chrono::milliseconds(1950);\n\n        Config c1;\n        c1.allowFutureToggle = false;\n        c1.enableDoubleAlter = false;\n        c1.wEarly = 190; c1.wMid = 150; c1.wLate = 115;\n        c1.preMul = 6; c1.elitePct = 50;\n        c1.wCost = 10; c1.wH1 = 4; c1.wH2 = 2;\n        c1.wFutureBlocked = 0; c1.wBlockBonus = 1;\n        c1.evalDistLimit = 55;\n\n        Config c2;\n        c2.allowFutureToggle = true;\n        c2.enableDoubleAlter = false;\n        c2.wEarly = 175; c2.wMid = 140; c2.wLate = 105;\n        c2.preMul = 6; c2.elitePct = 45;\n        c2.wCost = 10; c2.wH1 = 5; c2.wH2 = 2;\n        c2.wFutureBlocked = 4; c2.wBlockBonus = 1;\n        c2.evalDistLimit = 55;\n\n        Config c3;\n        c3.allowFutureToggle = true;\n        c3.enableDoubleAlter = true;\n        c3.wEarly = 145; c3.wMid = 115; c3.wLate = 90;\n        c3.preMul = 5; c3.elitePct = 40;\n        c3.wCost = 10; c3.wH1 = 5; c3.wH2 = 3;\n        c3.wFutureBlocked = 4; c3.wBlockBonus = 1;\n        c3.evalDistLimit = 55;\n\n        Config c4 = c3;\n        c4.wEarly = 130; c4.wMid = 105; c4.wLate = 82;\n        c4.elitePct = 35;\n        c4.wH1 = 6;\n        c4.wFutureBlocked = 5;\n        c4.evalDistLimit = 50;\n\n        vector<pair<Config, int>> plan = {\n            {c1, 1100},\n            {c2, 1650},\n            {c3, 1930},\n            {c4, 1950},\n        };\n\n        for (auto &p : plan) {\n            auto dl = min(globalDL, start + chrono::milliseconds(p.second));\n            if (Clock::now() >= dl) continue;\n\n            vector<Action> cand = runBeam((int)best.size(), p.first, dl);\n            if (cand.empty()) continue;\n            if ((int)cand.size() <= LIMIT && cand.size() < best.size() && validate(cand)) {\n                best.swap(cand);\n            }\n        }\n\n        if ((int)best.size() > LIMIT || !validate(best)) {\n            best = fallbackManhattan();\n        }\n\n        for (const auto& ac : best) {\n            cout << ac.a << ' ' << ac.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}"},"16":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int BOARD = 10000;\nenum Side { LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3 };\n\nstruct Company {\n    int x, y, r; // desired point cell (x,y), target area r\n};\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n};\n\nstruct State {\n    vector<Rect> rects;\n    vector<long long> area;\n    vector<double> p;\n    double total = 0.0;\n};\n\nint n;\nvector<Company> C;\nchrono::steady_clock::time_point gStart;\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - gStart).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed ? seed : 88172645463325252ull) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int nextInt(int l, int r) {\n        if (l >= r) return l;\n        uint64_t span = (uint64_t)(r - l + 1);\n        return l + (int)(nextU64() % span);\n    }\n};\n\ninline bool overlap1D(int l1, int r1, int l2, int r2) {\n    return max(l1, l2) < min(r1, r2);\n}\n\ninline long long rectArea(const Rect& rc) {\n    return 1LL * (rc.r - rc.l) * (rc.t - rc.b);\n}\n\ninline double satisfaction(long long s, long long target) {\n    if (s <= 0) return 0.0;\n    double ratio = (s < target) ? (double)s / (double)target : (double)target / (double)s;\n    double d = 1.0 - ratio;\n    return 1.0 - d * d;\n}\n\ninline int getCoord(const Rect& rc, int side) {\n    if (side == LEFT) return rc.l;\n    if (side == RIGHT) return rc.r;\n    if (side == BOTTOM) return rc.b;\n    return rc.t;\n}\n\ninline void setCoord(Rect& rc, int side, int v) {\n    if (side == LEFT) rc.l = v;\n    else if (side == RIGHT) rc.r = v;\n    else if (side == BOTTOM) rc.b = v;\n    else rc.t = v;\n}\n\ninline long long areaWithSide(const Rect& rc, int side, int v) {\n    if (side == LEFT) return 1LL * (rc.r - v) * (rc.t - rc.b);\n    if (side == RIGHT) return 1LL * (v - rc.l) * (rc.t - rc.b);\n    if (side == BOTTOM) return 1LL * (rc.r - rc.l) * (rc.t - v);\n    return 1LL * (rc.r - rc.l) * (v - rc.b);\n}\n\nState makeState(const vector<Rect>& rects) {\n    State st;\n    st.rects = rects;\n    st.area.resize(n);\n    st.p.resize(n);\n    st.total = 0.0;\n    for (int i = 0; i < n; ++i) {\n        st.area[i] = rectArea(st.rects[i]);\n        st.p[i] = satisfaction(st.area[i], C[i].r);\n        st.total += st.p[i];\n    }\n    return st;\n}\n\nbool validateRects(const vector<Rect>& rects) {\n    if ((int)rects.size() != n) return false;\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = rects[i];\n        if (!(0 <= a.l && a.l < a.r && a.r <= BOARD && 0 <= a.b && a.b < a.t && a.t <= BOARD)) return false;\n        if (!(a.l <= C[i].x && C[i].x + 1 <= a.r && a.b <= C[i].y && C[i].y + 1 <= a.t)) return false;\n    }\n    for (int i = 0; i < n; ++i) {\n        for (int j = i + 1; j < n; ++j) {\n            const Rect& a = rects[i];\n            const Rect& b = rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && overlap1D(a.b, a.t, b.b, b.t)) return false;\n        }\n    }\n    return true;\n}\n\n// Movable range for one side, optionally ignoring one rectangle (for pair moves).\npair<int, int> sideRange(const State& st, int i, int side, int ignore = -1) {\n    const Rect& a = st.rects[i];\n\n    if (side == LEFT) {\n        int L = 0;\n        int U = min(C[i].x, a.r - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.l < a.r) L = max(L, b.r);\n        }\n        return {L, U};\n    }\n\n    if (side == RIGHT) {\n        int L = max(C[i].x + 1, a.l + 1);\n        int U = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.b, a.t, b.b, b.t) && b.r > a.l) U = min(U, b.l);\n        }\n        return {L, U};\n    }\n\n    if (side == BOTTOM) {\n        int L = 0;\n        int U = min(C[i].y, a.t - 1);\n        for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n            const Rect& b = st.rects[j];\n            if (overlap1D(a.l, a.r, b.l, b.r) && b.b < a.t) L = max(L, b.t);\n        }\n        return {L, U};\n    }\n\n    int L = max(C[i].y + 1, a.b + 1);\n    int U = BOARD;\n    for (int j = 0; j < n; ++j) if (j != i && j != ignore) {\n        const Rect& b = st.rects[j];\n        if (overlap1D(a.l, a.r, b.l, b.r) && b.t > a.b) U = min(U, b.b);\n    }\n    return {L, U};\n}\n\npair<int, int> shiftRangeX(const State& st, int i) {\n    const Rect& a = st.rects[i];\n\n    int LB = -a.l;\n    int UB = BOARD - a.r;\n\n    // point containment\n    LB = max(LB, C[i].x + 1 - a.r);\n    UB = min(UB, C[i].x - a.l);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.b, a.t, b.b, b.t)) continue;\n        if (b.r <= a.l) LB = max(LB, b.r - a.l);\n        else if (b.l >= a.r) UB = min(UB, b.l - a.r);\n        else return {1, 0}; // invalid state\n    }\n    return {LB, UB};\n}\n\npair<int, int> shiftRangeY(const State& st, int i) {\n    const Rect& a = st.rects[i];\n\n    int LB = -a.b;\n    int UB = BOARD - a.t;\n\n    // point containment\n    LB = max(LB, C[i].y + 1 - a.t);\n    UB = min(UB, C[i].y - a.b);\n\n    for (int j = 0; j < n; ++j) if (j != i) {\n        const Rect& b = st.rects[j];\n        if (!overlap1D(a.l, a.r, b.l, b.r)) continue;\n        if (b.t <= a.b) LB = max(LB, b.t - a.b);\n        else if (b.b >= a.t) UB = min(UB, b.b - a.t);\n        else return {1, 0}; // invalid state\n    }\n    return {LB, UB};\n}\n\nconstexpr int MAX_CAND = 24;\n\ninline void addCand(int arr[], int& m, int v, int L, int U) {\n    if (v < L || v > U) return;\n    for (int i = 0; i < m; ++i) if (arr[i] == v) return;\n    if (m < MAX_CAND) arr[m++] = v;\n}\n\nvoid fillCandidatesForSide(const State& st, int i, int side, int L, int U, int arr[], int& m, RNG* rng = nullptr) {\n    m = 0;\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n\n    addCand(arr, m, cur, L, U);\n    addCand(arr, m, L, L, U);\n    addCand(arr, m, U, L, U);\n    addCand(arr, m, (L + U) >> 1, L, U);\n\n    long long target = C[i].r;\n    if (side == LEFT || side == RIGHT) {\n        int h = a.t - a.b;\n        if (h > 0) {\n            int w0 = (int)llround((double)target / (double)h);\n            for (int dw = -2; dw <= 2; ++dw) {\n                int w = w0 + dw;\n                if (w < 1) continue;\n                int v = (side == LEFT) ? (a.r - w) : (a.l + w);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    } else {\n        int w = a.r - a.l;\n        if (w > 0) {\n            int h0 = (int)llround((double)target / (double)w);\n            for (int dh = -2; dh <= 2; ++dh) {\n                int h = h0 + dh;\n                if (h < 1) continue;\n                int v = (side == BOTTOM) ? (a.t - h) : (a.b + h);\n                addCand(arr, m, v, L, U);\n            }\n        }\n    }\n\n    if (rng && U > L) {\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n        addCand(arr, m, rng->nextInt(L, U), L, U);\n    }\n}\n\nint bestCoordForSide(const State& st, int i, int side, int L, int U) {\n    int cands[MAX_CAND], m;\n    fillCandidatesForSide(st, i, side, L, U, cands, m, nullptr);\n\n    const Rect& a = st.rects[i];\n    int cur = getCoord(a, side);\n    int best = cur;\n    double bestP = st.p[i];\n\n    for (int k = 0; k < m; ++k) {\n        int v = cands[k];\n        long long ar = areaWithSide(a, side, v);\n        double np = satisfaction(ar, C[i].r);\n        if (np > bestP + 1e-15 || (fabs(np - bestP) <= 1e-15 && abs(v - cur) < abs(best - cur))) {\n            bestP = np;\n            best = v;\n        }\n    }\n    return best;\n}\n\ninline void applySingleSide(State& st, int i, int side, int v) {\n    st.total -= st.p[i];\n    setCoord(st.rects[i], side, v);\n    st.area[i] = rectArea(st.rects[i]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.total += st.p[i];\n}\n\nint pickRect(const State& st, RNG& rng) {\n    int best = rng.nextInt(0, n - 1);\n    for (int t = 0; t < 4; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nint pickRect2(const State& st, RNG& rng, int avoid) {\n    int best = rng.nextInt(0, n - 1);\n    if (best == avoid) best = (best + 1) % n;\n    for (int t = 0; t < 4; ++t) {\n        int j = rng.nextInt(0, n - 1);\n        if (j == avoid) continue;\n        if (st.p[j] < st.p[best]) best = j;\n    }\n    return best;\n}\n\nstruct PairMove {\n    int i = -1, j = -1;\n    int sideI = -1, sideJ = -1;\n    int vI = 0, vJ = 0;\n    double delta = 0.0;\n    bool valid = false;\n};\n\nbool proposeHorizontal(const State& st, int left, int right, RNG& rng, bool greedy, PairMove& out) {\n    // left is left of right (in x): left.r <= right.l\n    auto [L1, U1] = sideRange(st, left, RIGHT, right);\n    auto [L2, U2] = sideRange(st, right, LEFT, left);\n\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false;\n\n    int curX = st.rects[left].r;\n    int curY = st.rects[right].l;\n    double oldS = st.p[left] + st.p[right];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, left, RIGHT, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, right, LEFT, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n                long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n                double s = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[left], RIGHT, x);\n        long long ar2 = areaWithSide(st.rects[right], LEFT, y);\n        double ns = satisfaction(ar1, C[left].r) + satisfaction(ar2, C[right].r);\n\n        out.i = left; out.j = right;\n        out.sideI = RIGHT; out.sideJ = LEFT;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposeVertical(const State& st, int bottom, int top, RNG& rng, bool greedy, PairMove& out) {\n    // bottom is below top (in y): bottom.t <= top.b\n    auto [L1, U1] = sideRange(st, bottom, TOP, top);\n    auto [L2, U2] = sideRange(st, top, BOTTOM, bottom);\n\n    if (L1 > U1 || L2 > U2) return false;\n    if (L1 > U2) return false;\n\n    int curX = st.rects[bottom].t;\n    int curY = st.rects[top].b;\n    double oldS = st.p[bottom] + st.p[top];\n\n    if (greedy) {\n        int c1[MAX_CAND], m1, c2[MAX_CAND], m2;\n        fillCandidatesForSide(st, bottom, TOP, L1, U1, c1, m1, nullptr);\n        fillCandidatesForSide(st, top, BOTTOM, L2, U2, c2, m2, nullptr);\n\n        int bestX = curX, bestY = curY;\n        double bestS = oldS;\n\n        for (int a = 0; a < m1; ++a) {\n            int x = c1[a];\n            for (int b = 0; b < m2; ++b) {\n                int y = c2[b];\n                if (x > y) continue;\n                long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n                long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n                double s = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n                int gap = y - x;\n                int bestGap = bestY - bestX;\n                if (s > bestS + 1e-15 || (fabs(s - bestS) <= 1e-15 && gap < bestGap)) {\n                    bestS = s;\n                    bestX = x;\n                    bestY = y;\n                }\n            }\n        }\n\n        if (bestX == curX && bestY == curY) return false;\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = bestX; out.vJ = bestY;\n        out.delta = bestS - oldS;\n        out.valid = true;\n        return true;\n    } else {\n        int xL = L1;\n        int xU = min(U1, U2);\n        if (xL > xU) return false;\n\n        int x = rng.nextInt(xL, xU);\n        int yL = max(L2, x);\n        if (yL > U2) return false;\n        int y = rng.nextInt(yL, U2);\n\n        if (x == curX && y == curY) return false;\n\n        long long ar1 = areaWithSide(st.rects[bottom], TOP, x);\n        long long ar2 = areaWithSide(st.rects[top], BOTTOM, y);\n        double ns = satisfaction(ar1, C[bottom].r) + satisfaction(ar2, C[top].r);\n\n        out.i = bottom; out.j = top;\n        out.sideI = TOP; out.sideJ = BOTTOM;\n        out.vI = x; out.vJ = y;\n        out.delta = ns - oldS;\n        out.valid = true;\n        return true;\n    }\n}\n\nbool proposePairMove(const State& st, int i, int j, RNG& rng, bool greedy, PairMove& out) {\n    if (i == j) return false;\n    const Rect& a = st.rects[i];\n    const Rect& b = st.rects[j];\n\n    bool found = false;\n    PairMove best;\n\n    // Horizontal relation\n    if (overlap1D(a.b, a.t, b.b, b.t)) {\n        if (a.r <= b.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, i, j, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        } else if (b.r <= a.l) {\n            PairMove mv;\n            if (proposeHorizontal(st, j, i, rng, greedy, mv)) {\n                best = mv;\n                found = true;\n            }\n        }\n    }\n\n    // Vertical relation\n    if (overlap1D(a.l, a.r, b.l, b.r)) {\n        if (a.t <= b.b) {\n            PairMove mv;\n            if (proposeVertical(st, i, j, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        } else if (b.t <= a.b) {\n            PairMove mv;\n            if (proposeVertical(st, j, i, rng, greedy, mv)) {\n                if (!found || mv.delta > best.delta) best = mv;\n                found = true;\n            }\n        }\n    }\n\n    if (!found) return false;\n    out = best;\n    return true;\n}\n\ninline void applyPairMove(State& st, const PairMove& mv) {\n    int i = mv.i, j = mv.j;\n    st.total -= st.p[i] + st.p[j];\n\n    setCoord(st.rects[i], mv.sideI, mv.vI);\n    setCoord(st.rects[j], mv.sideJ, mv.vJ);\n\n    st.area[i] = rectArea(st.rects[i]);\n    st.area[j] = rectArea(st.rects[j]);\n    st.p[i] = satisfaction(st.area[i], C[i].r);\n    st.p[j] = satisfaction(st.area[j], C[j].r);\n\n    st.total += st.p[i] + st.p[j];\n}\n\n// Build neighbor-focused pair list (nearest left/right/up/down for each rectangle)\nvector<pair<int, int>> buildNeighborPairs(const State& st) {\n    vector<pair<int, int>> pairs;\n    vector<unsigned char> used(n * n, 0);\n    auto addPair = [&](int a, int b) {\n        if (a < 0 || b < 0 || a == b) return;\n        if (a > b) swap(a, b);\n        int id = a * n + b;\n        if (!used[id]) {\n            used[id] = 1;\n            pairs.push_back({a, b});\n        }\n    };\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& a = st.rects[i];\n\n        int leftJ = -1, leftV = -1;\n        int rightJ = -1, rightV = BOARD + 1;\n        int downJ = -1, downV = -1;\n        int upJ = -1, upV = BOARD + 1;\n\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& b = st.rects[j];\n\n            if (overlap1D(a.b, a.t, b.b, b.t)) {\n                if (b.r <= a.l && b.r > leftV) {\n                    leftV = b.r;\n                    leftJ = j;\n                }\n                if (b.l >= a.r && b.l < rightV) {\n                    rightV = b.l;\n                    rightJ = j;\n                }\n            }\n\n            if (overlap1D(a.l, a.r, b.l, b.r)) {\n                if (b.t <= a.b && b.t > downV) {\n                    downV = b.t;\n                    downJ = j;\n                }\n                if (b.b >= a.t && b.b < upV) {\n                    upV = b.b;\n                    upJ = j;\n                }\n            }\n        }\n\n        addPair(i, leftJ);\n        addPair(i, rightJ);\n        addPair(i, downJ);\n        addPair(i, upJ);\n    }\n\n    return pairs;\n}\n\npair<int, int> pickNeighborPair(const State& st, const vector<pair<int, int>>& pairs, RNG& rng) {\n    if (pairs.empty()) return {-1, -1};\n    int m = (int)pairs.size();\n\n    int bestIdx = rng.nextInt(0, m - 1);\n    double bestScore = -1e100;\n\n    int trials = min(6, m);\n    for (int t = 0; t < trials; ++t) {\n        int idx = rng.nextInt(0, m - 1);\n        auto [i, j] = pairs[idx];\n\n        double e1 = (double)st.area[i] / (double)C[i].r - 1.0;\n        double e2 = (double)st.area[j] / (double)C[j].r - 1.0;\n        double opposite = max(0.0, -e1 * e2); // useful for area transfer\n        double score = (1.0 - st.p[i]) + (1.0 - st.p[j]) + 0.25 * opposite;\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestIdx = idx;\n        }\n    }\n    return pairs[bestIdx];\n}\n\nvoid greedyOptimize(State& st, RNG& rng, int maxPass) {\n    vector<int> ord(n);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (st.p[a] != st.p[b]) return st.p[a] < st.p[b];\n            return a < b;\n        });\n\n        int rndSwap = max(1, n / 12);\n        for (int s = 0; s < rndSwap; ++s) {\n            int i = rng.nextInt(0, n - 1);\n            int j = rng.nextInt(0, n - 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int idx = 0; idx < n; ++idx) {\n            int i = ord[idx];\n            double oldP = st.p[i];\n\n            int bestSide = -1;\n            int bestV = 0;\n            double bestDelta = 1e-12;\n\n            for (int side = 0; side < 4; ++side) {\n                auto [L, U] = sideRange(st, i, side);\n                if (L > U) continue;\n\n                int curV = getCoord(st.rects[i], side);\n                int v = bestCoordForSide(st, i, side, L, U);\n                if (v == curV) continue;\n\n                long long ar = areaWithSide(st.rects[i], side, v);\n                double np = satisfaction(ar, C[i].r);\n                double delta = np - oldP;\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSide = side;\n                    bestV = v;\n                }\n            }\n\n            if (bestSide != -1) {\n                applySingleSide(st, i, bestSide, bestV);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid pairGreedyOptimize(State& st, RNG& rng, int maxPass) {\n    for (int pass = 0; pass < maxPass; ++pass) {\n        auto pairs = buildNeighborPairs(st);\n        if (pairs.empty()) break;\n\n        for (int i = (int)pairs.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(0, i);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        for (auto [a, b] : pairs) {\n            PairMove mv;\n            if (!proposePairMove(st, a, b, rng, true, mv)) continue;\n            if (mv.delta > 1e-12) {\n                applyPairMove(st, mv);\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\n// -------- Randomized guillotine initializer --------\nstruct SplitCand {\n    int ori; // 0 vertical, 1 horizontal\n    int k;\n    int t;\n    double cost;\n};\n\nint buildCallCount = 0;\nconstexpr int BUILD_CALL_LIMIT = 80000;\n\nbool buildPartitionRec(const vector<int>& ids, int L, int B, int R, int T, vector<Rect>& out, RNG& rng) {\n    if (++buildCallCount > BUILD_CALL_LIMIT) return false;\n\n    int m = (int)ids.size();\n    if (m == 0) return true;\n    if (L >= R || B >= T) return false;\n    if (1LL * (R - L) * (T - B) < m) return false;\n\n    if (m == 1) {\n        int id = ids[0];\n        if (!(L <= C[id].x && C[id].x + 1 <= R && B <= C[id].y && C[id].y + 1 <= T)) return false;\n        out[id] = {L, B, R, T};\n        return true;\n    }\n\n    int W = R - L, H = T - B;\n    if (W <= 0 || H <= 0) return false;\n\n    vector<int> ox = ids, oy = ids;\n    sort(ox.begin(), ox.end(), [](int a, int b) {\n        if (C[a].x != C[b].x) return C[a].x < C[b].x;\n        return C[a].y < C[b].y;\n    });\n    sort(oy.begin(), oy.end(), [](int a, int b) {\n        if (C[a].y != C[b].y) return C[a].y < C[b].y;\n        return C[a].x < C[b].x;\n    });\n\n    vector<long long> px(m + 1, 0), py(m + 1, 0);\n    for (int i = 0; i < m; ++i) {\n        px[i + 1] = px[i] + C[ox[i]].r;\n        py[i + 1] = py[i] + C[oy[i]].r;\n    }\n    long long totalR = px[m];\n\n    vector<SplitCand> cands;\n    cands.reserve(2 * (m - 1));\n\n    // Vertical split\n    if (W >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int xl = C[ox[k - 1]].x;\n            int xr = C[ox[k]].x;\n            int low = max(L + 1, xl + 1);\n            int high = min(R - 1, xr);\n            if (low > high) continue;\n\n            long long leftR = px[k];\n            long long rightR = totalR - leftR;\n\n            int t = (int)llround(L + (double)leftR / (double)H);\n            t = max(low, min(high, t));\n\n            long long leftArea = 1LL * (t - L) * H;\n            long long rightArea = 1LL * (R - t) * H;\n\n            double cost = fabs((double)(leftArea - leftR)) + fabs((double)(rightArea - rightR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({0, k, t, cost});\n        }\n    }\n\n    // Horizontal split\n    if (H >= 2) {\n        for (int k = 1; k < m; ++k) {\n            int yb = C[oy[k - 1]].y;\n            int yt = C[oy[k]].y;\n            int low = max(B + 1, yb + 1);\n            int high = min(T - 1, yt);\n            if (low > high) continue;\n\n            long long botR = py[k];\n            long long topR = totalR - botR;\n\n            int t = (int)llround(B + (double)botR / (double)W);\n            t = max(low, min(high, t));\n\n            long long botArea = 1LL * (t - B) * W;\n            long long topArea = 1LL * (T - t) * W;\n\n            double cost = fabs((double)(botArea - botR)) + fabs((double)(topArea - topR));\n            cost += 0.02 * abs(m - 2 * k);\n            cost += rng.nextDouble() * 1e-3;\n\n            cands.push_back({1, k, t, cost});\n        }\n    }\n\n    if (cands.empty()) return false;\n\n    sort(cands.begin(), cands.end(), [](const SplitCand& a, const SplitCand& b) {\n        return a.cost < b.cost;\n    });\n\n    int lim = min((int)cands.size(), 18);\n    for (int i = 0; i < lim; ++i) {\n        int span = min(3, lim - 1 - i);\n        if (span > 0) {\n            int j = i + rng.nextInt(0, span);\n            swap(cands[i], cands[j]);\n        }\n    }\n\n    for (int idx = 0; idx < lim; ++idx) {\n        const SplitCand& c = cands[idx];\n\n        if (c.ori == 0) {\n            long long areaL = 1LL * (c.t - L) * (T - B);\n            long long areaR = 1LL * (R - c.t) * (T - B);\n            if (areaL < c.k || areaR < (m - c.k)) continue;\n\n            vector<int> leftIds(ox.begin(), ox.begin() + c.k);\n            vector<int> rightIds(ox.begin() + c.k, ox.end());\n\n            if (buildPartitionRec(leftIds, L, B, c.t, T, out, rng) &&\n                buildPartitionRec(rightIds, c.t, B, R, T, out, rng)) {\n                return true;\n            }\n        } else {\n            long long areaB = 1LL * (R - L) * (c.t - B);\n            long long areaT = 1LL * (R - L) * (T - c.t);\n            if (areaB < c.k || areaT < (m - c.k)) continue;\n\n            vector<int> botIds(oy.begin(), oy.begin() + c.k);\n            vector<int> topIds(oy.begin() + c.k, oy.end());\n\n            if (buildPartitionRec(botIds, L, B, R, c.t, out, rng) &&\n                buildPartitionRec(topIds, L, c.t, R, T, out, rng)) {\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nvoid addPool(vector<State>& pool, const State& st, int cap = 8) {\n    pool.push_back(st);\n    sort(pool.begin(), pool.end(), [](const State& a, const State& b) {\n        return a.total > b.total;\n    });\n    if ((int)pool.size() > cap) pool.resize(cap);\n}\n\nvoid anneal(State& cur, State& bestGlobal, RNG& rng,\n            double tEnd, double T0, double T1, bool allowKick) {\n    double tStart = elapsedSec();\n    if (tEnd <= tStart + 1e-4) return;\n    double span = tEnd - tStart;\n\n    State bestLocal = cur;\n    auto neighborPairs = buildNeighborPairs(cur);\n\n    double nextRebuild = tStart + 0.22;\n    double nextRefine = tStart + 0.58;\n    double lastImprove = tStart;\n\n    long long iter = 0;\n    double temp = T0;\n\n    while (true) {\n        double t = 0.0;\n        if ((iter & 255LL) == 0) {\n            t = elapsedSec();\n            if (t >= tEnd) break;\n\n            double prog = (t - tStart) / span;\n            if (prog < 0.0) prog = 0.0;\n            if (prog > 1.0) prog = 1.0;\n            temp = T0 * pow(T1 / T0, prog);\n\n            if (t >= nextRebuild) {\n                neighborPairs = buildNeighborPairs(cur);\n                nextRebuild = t + 0.22;\n            }\n\n            if (t >= nextRefine) {\n                pairGreedyOptimize(cur, rng, 1);\n                greedyOptimize(cur, rng, 2);\n\n                if (cur.total > bestLocal.total + 1e-15) {\n                    bestLocal = cur;\n                    if (bestLocal.total > bestGlobal.total) bestGlobal = bestLocal;\n                    lastImprove = t;\n                }\n\n                nextRefine = t + 0.58;\n            }\n\n            if (allowKick && t - lastImprove > 0.90) {\n                if (bestLocal.total > cur.total + 1e-12) cur = bestLocal;\n\n                // light random perturb\n                for (int z = 0; z < 3; ++z) {\n                    int i = pickRect(cur, rng);\n                    int side = rng.nextInt(0, 3);\n                    auto [L, U] = sideRange(cur, i, side);\n                    if (L <= U) {\n                        int v = rng.nextInt(L, U);\n                        if (v != getCoord(cur.rects[i], side)) applySingleSide(cur, i, side, v);\n                    }\n                }\n                neighborPairs = buildNeighborPairs(cur);\n                lastImprove = t;\n            }\n        }\n\n        double op = rng.nextDouble();\n\n        if (op < 0.56) {\n            // Single side move\n            int i = pickRect(cur, rng);\n            int side = rng.nextInt(0, 3);\n\n            auto [L, U] = sideRange(cur, i, side);\n            if (L > U) { ++iter; continue; }\n\n            int curV = getCoord(cur.rects[i], side);\n            int v = curV;\n\n            double mode = rng.nextDouble();\n            if (mode < 0.55) {\n                v = bestCoordForSide(cur, i, side, L, U);\n            } else if (mode < 0.85) {\n                int spanv = U - L;\n                int step = max(1, (int)(spanv * 0.35));\n                int d = rng.nextInt(-step, step);\n                v = curV + d;\n                if (v < L) v = L;\n                if (v > U) v = U;\n            } else {\n                v = rng.nextInt(L, U);\n            }\n\n            if (v != curV) {\n                long long newA = areaWithSide(cur.rects[i], side, v);\n                double newP = satisfaction(newA, C[i].r);\n                double delta = newP - cur.p[i];\n\n                if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                    cur.total += delta;\n                    cur.p[i] = newP;\n                    cur.area[i] = newA;\n                    setCoord(cur.rects[i], side, v);\n                }\n            }\n\n        } else if (op < 0.86) {\n            // Pair move\n            int i = -1, j = -1;\n            if (!neighborPairs.empty() && rng.nextDouble() < 0.86) {\n                auto pr = pickNeighborPair(cur, neighborPairs, rng);\n                i = pr.first; j = pr.second;\n            } else {\n                i = pickRect(cur, rng);\n                j = pickRect2(cur, rng, i);\n            }\n\n            if (i >= 0 && j >= 0 && i != j) {\n                PairMove mv;\n                bool greedySel = (rng.nextDouble() < 0.68);\n                if (proposePairMove(cur, i, j, rng, greedySel, mv)) {\n                    double delta = mv.delta;\n                    if (delta >= 0.0 || exp(delta / temp) > rng.nextDouble()) {\n                        applyPairMove(cur, mv);\n                    }\n                }\n            }\n\n        } else if (op < 0.93) {\n            // Shift X\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeX(cur, i);\n            if (LB <= UB) {\n                int dx = 0;\n                if (LB == UB) dx = LB;\n                else if (rng.nextDouble() < 0.55) dx = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dx = rng.nextInt(LB, UB);\n\n                if (dx != 0) {\n                    cur.rects[i].l += dx;\n                    cur.rects[i].r += dx;\n                }\n            }\n\n        } else {\n            // Shift Y\n            int i = pickRect(cur, rng);\n            auto [LB, UB] = shiftRangeY(cur, i);\n            if (LB <= UB) {\n                int dy = 0;\n                if (LB == UB) dy = LB;\n                else if (rng.nextDouble() < 0.55) dy = (rng.nextDouble() < 0.5 ? LB : UB);\n                else dy = rng.nextInt(LB, UB);\n\n                if (dy != 0) {\n                    cur.rects[i].b += dy;\n                    cur.rects[i].t += dy;\n                }\n            }\n        }\n\n        if (cur.total > bestLocal.total + 1e-15) {\n            bestLocal = cur;\n            if (bestLocal.total > bestGlobal.total) bestGlobal = bestLocal;\n        }\n\n        ++iter;\n    }\n\n    cur = bestLocal;\n    if (cur.total > bestGlobal.total) bestGlobal = cur;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n;\n    C.resize(n);\n\n    uint64_t seed = 1469598103934665603ull ^ (uint64_t)n * 1000003ull;\n    for (int i = 0; i < n; ++i) {\n        cin >> C[i].x >> C[i].y >> C[i].r;\n        seed ^= (uint64_t)(C[i].x + 1) * 1000003ull;\n        seed ^= (uint64_t)(C[i].y + 1) * 1009837ull;\n        seed ^= (uint64_t)(C[i].r + 3) * 10000019ull;\n        seed *= 1099511628211ull;\n    }\n    RNG rng(seed);\n\n    gStart = chrono::steady_clock::now();\n\n    vector<State> pool;\n    pool.reserve(10);\n\n    // Base 1x1 state\n    vector<Rect> baseRects(n);\n    for (int i = 0; i < n; ++i) {\n        baseRects[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n    }\n    State base = makeState(baseRects);\n    addPool(pool, base, 8);\n\n    // Multiple 1x1-polished variants\n    for (int rep = 0; rep < 4; ++rep) {\n        if (elapsedSec() > 0.55) break;\n        State st = base;\n        greedyOptimize(st, rng, 32 + rep * 4);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 10);\n        addPool(pool, st, 8);\n    }\n\n    // Randomized guillotine initial states\n    const double INIT_END = 1.10;\n    int attempts = 0;\n    while (elapsedSec() < INIT_END && attempts < 26) {\n        ++attempts;\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n);\n\n        buildCallCount = 0;\n        bool ok = buildPartitionRec(ids, 0, 0, BOARD, BOARD, rects, rng);\n        if (!ok) continue;\n        if (!validateRects(rects)) continue;\n\n        State st = makeState(rects);\n        greedyOptimize(st, rng, 26);\n        pairGreedyOptimize(st, rng, 1);\n        greedyOptimize(st, rng, 8);\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const State& a, const State& b) {\n        return a.total > b.total;\n    });\n\n    State bestInit = pool[0];\n    State bestGlobal = bestInit;\n\n    // Portfolio SA on top few candidates\n    const double PORT_END = 2.75;\n    int K = min((int)pool.size(), 3);\n    for (int idx = 0; idx < K; ++idx) {\n        double now = elapsedSec();\n        if (now >= PORT_END) break;\n        double end = now + (PORT_END - now) / (double)(K - idx);\n\n        State cur = pool[idx];\n        anneal(cur, bestGlobal, rng, end, 0.085, 0.0018, true);\n\n        if (elapsedSec() < PORT_END - 0.04) {\n            pairGreedyOptimize(cur, rng, 1);\n            greedyOptimize(cur, rng, 8);\n            if (cur.total > bestGlobal.total) bestGlobal = cur;\n        }\n    }\n\n    // Final intensification SA\n    State cur = bestGlobal;\n    const double FINAL_SA_END = 4.72;\n    if (elapsedSec() < FINAL_SA_END) {\n        anneal(cur, bestGlobal, rng, FINAL_SA_END, 0.045, 0.00005, true);\n    }\n\n    // Final polish\n    if (elapsedSec() < 4.82) {\n        pairGreedyOptimize(bestGlobal, rng, 2);\n        greedyOptimize(bestGlobal, rng, 24);\n    }\n    if (elapsedSec() < 4.90) {\n        pairGreedyOptimize(bestGlobal, rng, 1);\n        greedyOptimize(bestGlobal, rng, 12);\n    }\n\n    bestGlobal = makeState(bestGlobal.rects);\n\n    // Safety fallback\n    if (!validateRects(bestGlobal.rects)) {\n        if (validateRects(bestInit.rects)) {\n            bestGlobal = bestInit;\n        } else {\n            vector<Rect> safe(n);\n            for (int i = 0; i < n; ++i) safe[i] = {C[i].x, C[i].y, C[i].x + 1, C[i].y + 1};\n            bestGlobal = makeState(safe);\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        const Rect& rc = bestGlobal.rects[i];\n        cout << rc.l << ' ' << rc.b << ' ' << rc.r << ' ' << rc.t << '\\n';\n    }\n\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 N = H * W;\nstatic constexpr int MAXT = 2500;\nstatic constexpr int WORDS = (MAXT + 63) / 64;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + int(next_u64() % uint64_t(r - l + 1));\n    }\n};\n\nstruct Policy {\n    double wVal = 1.0;\n    double wLook = 0.5;\n    double wDeg = 1.0;\n    double wPair = 0.3;\n    double wRand = 0.0;\n    double eps = 0.0;\n    double deadPenalty = 10.0;\n};\n\nstruct RunParam {\n    Policy pol; // rollout policy\n\n    // main-step pre-score\n    double wVal = 1.0, wLook = 0.5, wDeg = 1.0, wPair = 0.3, wMob2 = 0.4;\n    double wNoise = 0.0, epsMain = 0.0;\n    double deadMain = 10.0;\n    double onePenalty = 4.0;\n    int oneUntil = 700;\n\n    // rollout control\n    int evalRollouts = 1;\n    int evalBestExtra = 0;\n    int evalDepth = 0;      // 0 => full\n    int earlyExtra = 0;\n    int earlySteps = 220;\n    int earlyDepthBonus = 30;\n\n    int rollTopK = 2;       // rollout only for top-K pre candidates\n    int rollFreq2 = 1;      // for nc==2, rollout every rollFreq2-th branch\n\n    double mixBest = 0.7;   // blend avg and best rollout\n    double preCoef = 0.7;   // final EV adds preCoef*pre\n    double evalNoise = 0.0;\n\n    double skipGap = 200.0; // if pre-gap large, skip rollout probabilistically\n    double skipProb = 0.7;\n};\n\nstruct Result {\n    long long score = LLONG_MIN;\n    string path;\n};\n\nstruct ModeStat {\n    int n = 0;\n    double mean = 0.0;\n};\n\nenum Mode {\n    FAST = 0,\n    BAL = 1,\n    DEEP = 2,\n    MODE_N = 3\n};\n\nint tileId[N], pval[N], pairLoss[N];\nint degCell[N];\nint nxtCell[N][4];\nchar nxtDir[N][4];\nint nextAll[N][4];\nint startCell = 0, M = 0;\n\nint tmpTileSeen[MAXT];\nint tmpTileToken = 1;\n\ninline bool bit_get(const uint64_t* bs, int t) {\n    return (bs[t >> 6] >> (t & 63)) & 1ULL;\n}\ninline void bit_set(uint64_t* bs, int t) {\n    bs[t >> 6] |= 1ULL << (t & 63);\n}\ninline void bit_clear_all(uint64_t* bs) {\n    memset(bs, 0, sizeof(uint64_t) * WORDS);\n}\n\ninline int charToDir(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\ninline bool betterResult(const Result& a, const Result& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.path.size() > b.path.size();\n}\n\ninline int gatherMovesMain(int cur, const uint64_t* vis, int outCands[4], char outDirs[4]) {\n    int nc = 0;\n    for (int k = 0; k < degCell[cur]; k++) {\n        int to = nxtCell[cur][k];\n        if (!bit_get(vis, tileId[to])) {\n            outCands[nc] = to;\n            outDirs[nc] = nxtDir[cur][k];\n            nc++;\n        }\n    }\n    return nc;\n}\n\ninline int gatherMovesSimple(int cur, const uint64_t* vis, int outCands[4]) {\n    int nc = 0;\n    for (int k = 0; k < degCell[cur]; k++) {\n        int to = nxtCell[cur][k];\n        if (!bit_get(vis, tileId[to])) outCands[nc++] = to;\n    }\n    return nc;\n}\n\ninline int nextTmpToken() {\n    ++tmpTileToken;\n    if (tmpTileToken == INT_MAX) {\n        memset(tmpTileSeen, 0, sizeof(tmpTileSeen));\n        tmpTileToken = 1;\n    }\n    return tmpTileToken;\n}\n\n// Cheap local future-mobility feature:\n// count distinct unvisited tiles within <=2 steps from cand (excluding cand's tile).\nint countTwoStepTiles(int cand, const uint64_t* vis) {\n    int token = nextTmpToken();\n    int blocked = tileId[cand];\n    int cnt = 0;\n\n    auto addTile = [&](int t) {\n        if (t == blocked) return;\n        if (bit_get(vis, t)) return;\n        if (tmpTileSeen[t] != token) {\n            tmpTileSeen[t] = token;\n            cnt++;\n        }\n    };\n\n    for (int k = 0; k < degCell[cand]; k++) {\n        int u = nxtCell[cand][k];\n        int tu = tileId[u];\n        if (tu == blocked || bit_get(vis, tu)) continue;\n        addTile(tu);\n\n        for (int kk = 0; kk < degCell[u]; kk++) {\n            int w = nxtCell[u][kk];\n            int tw = tileId[w];\n            addTile(tw);\n        }\n    }\n    return cnt;\n}\n\ninline int selectByPolicy(const int cands[4], int nc, const uint64_t* vis, const Policy& pol, XorShift64& rng) {\n    if (nc == 1) return 0;\n    if (rng.next_double() < pol.eps) return rng.next_int(0, nc - 1);\n\n    double bestScore = -1e100;\n    int bestIdx = 0;\n\n    for (int i = 0; i < nc; i++) {\n        int v = cands[i];\n        int degNext = 0;\n        int bestNextVal = 0;\n\n        for (int k = 0; k < degCell[v]; k++) {\n            int u = nxtCell[v][k];\n            if (!bit_get(vis, tileId[u])) {\n                degNext++;\n                if (pval[u] > bestNextVal) bestNextVal = pval[u];\n            }\n        }\n\n        double s = pol.wVal * pval[v]\n                 + pol.wLook * bestNextVal\n                 - pol.wDeg * degNext\n                 - pol.wPair * pairLoss[v]\n                 + pol.wRand * rng.next_double();\n\n        if (degNext == 0) s -= pol.deadPenalty;\n\n        if (s > bestScore + 1e-12) {\n            bestScore = s;\n            bestIdx = i;\n        } else if (fabs(s - bestScore) <= 1e-12) {\n            if (rng.next_u64() & 1ULL) bestIdx = i;\n        }\n    }\n    return bestIdx;\n}\n\nint playoutGain(\n    int cur,\n    uint64_t* vis,\n    const Policy& pol,\n    XorShift64& rng,\n    int maxDepth, // 0 => full\n    const chrono::steady_clock::time_point& deadline\n) {\n    using Clock = chrono::steady_clock;\n    int gain = 0;\n    int step = 0;\n\n    while (true) {\n        if (maxDepth > 0 && step >= maxDepth) break;\n\n        int cands[4];\n        int nc = gatherMovesSimple(cur, vis, cands);\n        if (nc == 0) break;\n\n        int idx = selectByPolicy(cands, nc, vis, pol, rng);\n        int nxt = cands[idx];\n\n        bit_set(vis, tileId[nxt]);\n        cur = nxt;\n        gain += pval[cur];\n        step++;\n\n        if ((step & 63) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n    }\n    return gain;\n}\n\nResult simulate(\n    const RunParam& rp,\n    const string* basePath,\n    int cut,\n    XorShift64& rng,\n    const chrono::steady_clock::time_point& deadline\n) {\n    using Clock = chrono::steady_clock;\n    Result res;\n\n    uint64_t vis[WORDS];\n    bit_clear_all(vis);\n\n    string path;\n    path.reserve(2600);\n\n    int cur = startCell;\n    long long score = pval[cur];\n    bit_set(vis, tileId[cur]);\n\n    // Replay prefix\n    if (basePath && cut > 0) {\n        int L = min<int>(cut, basePath->size());\n        for (int i = 0; i < L; i++) {\n            int d = charToDir((*basePath)[i]);\n            if (d < 0) break;\n            int to = nextAll[cur][d];\n            if (to < 0) break;\n            if (bit_get(vis, tileId[to])) break;\n\n            path.push_back((*basePath)[i]);\n            cur = to;\n            bit_set(vis, tileId[cur]);\n            score += pval[cur];\n        }\n    }\n\n    int stepMain = (int)path.size();\n    int branchCnt = 0;\n\n    while (true) {\n        if ((stepMain & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int cands[4];\n        char dirs[4];\n        int nc = gatherMovesMain(cur, vis, cands, dirs);\n        if (nc == 0) break;\n\n        int pickIdx = 0;\n\n        if (nc == 1) {\n            pickIdx = 0;\n        } else if (rng.next_double() < rp.epsMain) {\n            pickIdx = rng.next_int(0, nc - 1);\n        } else {\n            branchCnt++;\n\n            double pre[4];\n            for (int i = 0; i < nc; i++) {\n                int cand = cands[i];\n\n                int degNext = 0;\n                int bestNextVal = 0;\n                for (int k = 0; k < degCell[cand]; k++) {\n                    int u = nxtCell[cand][k];\n                    if (!bit_get(vis, tileId[u])) {\n                        degNext++;\n                        bestNextVal = max(bestNextVal, pval[u]);\n                    }\n                }\n\n                int mob2 = 0;\n                if (rp.wMob2 > 1e-12) {\n                    mob2 = countTwoStepTiles(cand, vis);\n                }\n\n                double s = rp.wVal * pval[cand]\n                         + rp.wLook * bestNextVal\n                         - rp.wDeg * degNext\n                         - rp.wPair * pairLoss[cand]\n                         + rp.wMob2 * mob2\n                         + rp.wNoise * rng.next_double();\n\n                if (degNext == 0) s -= rp.deadMain;\n                else if (degNext == 1 && stepMain < rp.oneUntil) s -= rp.onePenalty;\n\n                pre[i] = s;\n            }\n\n            int ord[4] = {0, 1, 2, 3};\n            sort(ord, ord + nc, [&](int a, int b) { return pre[a] > pre[b]; });\n\n            bool doRoll = (rp.rollTopK > 0 &&\n                           (rp.evalRollouts + rp.evalBestExtra +\n                            (stepMain < rp.earlySteps ? rp.earlyExtra : 0)) > 0);\n\n            if (doRoll && nc == 2 && rp.rollFreq2 > 1) {\n                if ((branchCnt % rp.rollFreq2) != 0) doRoll = false;\n            }\n\n            if (doRoll && nc >= 2) {\n                double gap = pre[ord[0]] - pre[ord[1]];\n                if (gap > rp.skipGap && rng.next_double() < rp.skipProb) doRoll = false;\n            }\n\n            if (!doRoll || Clock::now() >= deadline) {\n                pickIdx = ord[0];\n            } else {\n                int rankPos[4];\n                for (int r = 0; r < nc; r++) rankPos[ord[r]] = r;\n\n                double ev[4];\n                for (int i = 0; i < nc; i++) ev[i] = rp.preCoef * pre[i];\n\n                for (int i = 0; i < nc; i++) {\n                    int rank = rankPos[i];\n                    if (rank >= rp.rollTopK) continue;\n\n                    int rnum = rp.evalRollouts;\n                    if (rank == 0) rnum += rp.evalBestExtra;\n                    if (stepMain < rp.earlySteps) rnum += rp.earlyExtra;\n                    if (stepMain > 1200 && rnum > 1) rnum--;\n                    if (stepMain > 1700 && rnum > 1) rnum--;\n\n                    if (rnum <= 0) continue;\n                    if (Clock::now() >= deadline) continue;\n\n                    int cand = cands[i];\n                    long long sumGain = 0;\n                    long long bestGain = LLONG_MIN;\n                    int done = 0;\n\n                    for (int r = 0; r < rnum; r++) {\n                        if ((r & 1) == 0 && Clock::now() >= deadline) break;\n\n                        uint64_t vis2[WORDS];\n                        memcpy(vis2, vis, sizeof(vis2));\n                        bit_set(vis2, tileId[cand]);\n\n                        uint64_t sd = rng.next_u64();\n                        sd ^= (uint64_t)(cand + 1) * 0x9e3779b97f4a7c15ULL;\n                        sd ^= (uint64_t)(r + 1) * 0xbf58476d1ce4e5b9ULL;\n                        XorShift64 rr(sd);\n\n                        int depth = rp.evalDepth;\n                        if (depth > 0 && stepMain < rp.earlySteps) depth += rp.earlyDepthBonus;\n\n                        long long g = pval[cand];\n                        g += playoutGain(cand, vis2, rp.pol, rr, depth, deadline);\n\n                        sumGain += g;\n                        bestGain = max(bestGain, g);\n                        done++;\n                    }\n\n                    if (done > 0) {\n                        double avg = (double)sumGain / done;\n                        double pilot = (1.0 - rp.mixBest) * avg + rp.mixBest * (double)bestGain;\n                        ev[i] = pilot + rp.preCoef * pre[i] + rp.evalNoise * rng.next_double();\n                    }\n                }\n\n                pickIdx = 0;\n                double bestEv = ev[0];\n                for (int i = 1; i < nc; i++) {\n                    if (ev[i] > bestEv + 1e-9) {\n                        bestEv = ev[i];\n                        pickIdx = i;\n                    } else if (fabs(ev[i] - bestEv) <= 1e-9) {\n                        if (rng.next_u64() & 1ULL) pickIdx = i;\n                    }\n                }\n            }\n        }\n\n        int nxt = cands[pickIdx];\n        path.push_back(dirs[pickIdx]);\n        cur = nxt;\n        bit_set(vis, tileId[cur]);\n        score += pval[cur];\n        stepMain++;\n    }\n\n    res.score = score;\n    res.path = std::move(path);\n    return res;\n}\n\nint chooseMode(double phase, XorShift64& rng, const array<ModeStat, MODE_N>& st, int totalRuns) {\n    auto weighted = [&]() -> int {\n        double u = rng.next_double();\n        if (phase < 0.28) {\n            if (u < 0.45) return FAST;\n            if (u < 0.83) return BAL;\n            return DEEP;\n        } else if (phase < 0.82) {\n            if (u < 0.15) return FAST;\n            if (u < 0.62) return BAL;\n            return DEEP;\n        } else {\n            if (u < 0.05) return FAST;\n            if (u < 0.30) return BAL;\n            return DEEP;\n        }\n    };\n\n    if (totalRuns >= 8 && rng.next_double() < 0.27) {\n        double logt = log((double)totalRuns + 1.0);\n        int bestM = BAL;\n        double bestS = -1e100;\n\n        for (int m = 0; m < MODE_N; m++) {\n            double mean = (st[m].n > 0 ? st[m].mean : 38000.0);\n            double bonus = 1100.0 * sqrt(logt / (st[m].n + 1.0));\n\n            double bias = 0.0;\n            if (m == FAST) {\n                if (phase < 0.30) bias += 260.0;\n                if (phase > 0.85) bias -= 250.0;\n            } else if (m == BAL) {\n                if (phase >= 0.25 && phase <= 0.85) bias += 120.0;\n            } else { // DEEP\n                if (phase > 0.78) bias += 420.0;\n                if (phase < 0.25) bias -= 180.0;\n            }\n\n            double s = mean + bonus + bias;\n            if (s > bestS) {\n                bestS = s;\n                bestM = m;\n            }\n        }\n        return bestM;\n    }\n\n    return weighted();\n}\n\nRunParam sampleParam(int mode, double phase, XorShift64& rng) {\n    auto R = [&](double l, double r) { return l + (r - l) * rng.next_double(); };\n    RunParam rp{};\n\n    if (mode == FAST) {\n        rp.wVal = R(1.0, 2.4);\n        rp.wLook = R(0.0, 1.4);\n        rp.wDeg = R(-0.3, 4.8);\n        rp.wPair = R(0.0, 1.4);\n        rp.wMob2 = R(0.0, 1.2);\n        rp.wNoise = R(3.0, 30.0);\n        rp.epsMain = R(0.01, 0.14);\n        rp.deadMain = R(0.0, 18.0);\n        rp.onePenalty = R(0.0, 6.0);\n        rp.oneUntil = rng.next_int(420, 760);\n\n        rp.evalRollouts = (rng.next_double() < 0.70 ? 0 : 1);\n        rp.evalBestExtra = (rng.next_double() < 0.35 ? 1 : 0);\n        rp.rollTopK = (rng.next_double() < 0.65 ? 1 : 2);\n        rp.rollFreq2 = (rng.next_double() < 0.60 ? 3 : 4);\n\n        rp.evalDepth = (rng.next_double() < 0.90 ? rng.next_int(120, 230) : 0);\n        rp.earlyExtra = 0;\n        rp.earlySteps = 170;\n        rp.earlyDepthBonus = 25;\n\n        rp.mixBest = R(0.45, 0.82);\n        rp.preCoef = R(0.80, 1.80);\n        rp.evalNoise = R(0.0, 18.0);\n\n        rp.skipGap = R(80.0, 220.0);\n        rp.skipProb = R(0.60, 0.92);\n\n        rp.pol.wVal = R(0.8, 2.3);\n        rp.pol.wLook = R(0.0, 1.4);\n        rp.pol.wDeg = R(-0.3, 4.8);\n        rp.pol.wPair = R(0.0, 1.6);\n        rp.pol.wRand = R(0.0, 14.0);\n        rp.pol.eps = R(0.0, 0.18);\n        rp.pol.deadPenalty = R(0.0, 24.0);\n    } else if (mode == BAL) {\n        rp.wVal = R(1.0, 2.0);\n        rp.wLook = R(0.0, 1.2);\n        rp.wDeg = R(0.0, 4.5);\n        rp.wPair = R(0.0, 1.2);\n        rp.wMob2 = R(0.2, 1.0);\n        rp.wNoise = R(0.0, 12.0);\n        rp.epsMain = R(0.0, 0.06);\n        rp.deadMain = R(4.0, 24.0);\n        rp.onePenalty = R(1.0, 8.0);\n        rp.oneUntil = rng.next_int(560, 900);\n\n        rp.evalRollouts = (rng.next_double() < 0.75 ? 1 : 2);\n        rp.evalBestExtra = (rng.next_double() < 0.45 ? 1 : 0);\n        rp.rollTopK = 2;\n        rp.rollFreq2 = 2;\n\n        rp.evalDepth = (rng.next_double() < 0.60 ? 0 : rng.next_int(150, 280));\n        rp.earlyExtra = (rng.next_double() < 0.40 ? 1 : 0);\n        rp.earlySteps = 220;\n        rp.earlyDepthBonus = 35;\n\n        rp.mixBest = R(0.55, 0.90);\n        rp.preCoef = R(0.40, 1.20);\n        rp.evalNoise = R(0.0, 10.0);\n\n        rp.skipGap = R(140.0, 380.0);\n        rp.skipProb = R(0.45, 0.78);\n\n        rp.pol.wVal = R(0.9, 2.1);\n        rp.pol.wLook = R(0.0, 1.2);\n        rp.pol.wDeg = R(0.0, 4.5);\n        rp.pol.wPair = R(0.0, 1.4);\n        rp.pol.wRand = R(0.0, 8.0);\n        rp.pol.eps = R(0.0, 0.10);\n        rp.pol.deadPenalty = R(1.0, 22.0);\n    } else { // DEEP\n        rp.wVal = R(1.0, 1.8);\n        rp.wLook = R(0.2, 1.0);\n        rp.wDeg = R(0.8, 3.5);\n        rp.wPair = R(0.1, 0.9);\n        rp.wMob2 = R(0.2, 0.9);\n        rp.wNoise = R(0.0, 3.0);\n        rp.epsMain = R(0.0, 0.03);\n        rp.deadMain = R(8.0, 24.0);\n        rp.onePenalty = R(2.0, 10.0);\n        rp.oneUntil = rng.next_int(780, 1100);\n\n        rp.evalRollouts = (rng.next_double() < (phase > 0.90 ? 0.40 : 0.70) ? 2 : 3);\n        rp.evalBestExtra = 1;\n        rp.rollTopK = (rng.next_double() < 0.70 ? 2 : 3);\n        rp.rollFreq2 = 1;\n\n        rp.evalDepth = 0; // full playout\n        rp.earlyExtra = 1;\n        rp.earlySteps = 260;\n        rp.earlyDepthBonus = 0;\n\n        rp.mixBest = R(0.65, 0.93);\n        rp.preCoef = R(0.25, 0.85);\n        rp.evalNoise = R(0.0, 4.0);\n\n        rp.skipGap = R(260.0, 850.0);\n        rp.skipProb = R(0.30, 0.62);\n\n        rp.pol.wVal = R(1.0, 1.9);\n        rp.pol.wLook = R(0.2, 1.1);\n        rp.pol.wDeg = R(0.8, 3.8);\n        rp.pol.wPair = R(0.1, 1.0);\n        rp.pol.wRand = R(0.0, 3.0);\n        rp.pol.eps = R(0.0, 0.05);\n        rp.pol.deadPenalty = R(4.0, 18.0);\n    }\n\n    return rp;\n}\n\nint pickCut(int L, double phase, bool intense, XorShift64& rng) {\n    if (L <= 1) return 0;\n    int hi = L - 1;\n    int lo = 0;\n    double r = rng.next_double();\n\n    if (intense) {\n        if (r < 0.78) lo = max(0, L - 180);\n        else if (r < 0.97) lo = max(0, L - 560);\n        else lo = 0;\n    } else if (phase < 0.35) {\n        if (r < 0.35) lo = max(0, L - 250);\n        else if (r < 0.75) lo = max(0, L - 850);\n        else lo = 0;\n    } else if (phase < 0.85) {\n        if (r < 0.62) lo = max(0, L - 250);\n        else if (r < 0.92) lo = max(0, L - 760);\n        else lo = 0;\n    } else {\n        if (r < 0.82) lo = max(0, L - 180);\n        else if (r < 0.98) lo = max(0, L - 560);\n        else lo = 0;\n    }\n\n    if (lo > hi) lo = hi;\n    return rng.next_int(lo, hi);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int si, sj;\n    if (!(cin >> si >> sj)) return 0;\n\n    int maxTile = -1;\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x;\n            cin >> x;\n            int v = i * W + j;\n            tileId[v] = x;\n            maxTile = max(maxTile, x);\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[i * W + j];\n        }\n    }\n\n    startCell = si * W + sj;\n\n    // pairLoss for domino tiles\n    fill(pairLoss, pairLoss + N, 0);\n    vector<int> c1(M, -1), c2(M, -1);\n    for (int v = 0; v < N; v++) {\n        int t = tileId[v];\n        if (c1[t] == -1) c1[t] = v;\n        else c2[t] = v;\n    }\n    for (int t = 0; t < M; t++) {\n        if (c1[t] != -1 && c2[t] != -1) {\n            int a = c1[t], b = c2[t];\n            pairLoss[a] = max(0, pval[b] - pval[a]);\n            pairLoss[b] = max(0, pval[a] - pval[b]);\n        }\n    }\n\n    // Build graph\n    for (int v = 0; v < N; v++) {\n        degCell[v] = 0;\n        for (int d = 0; d < 4; d++) nextAll[v][d] = -1;\n    }\n\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    const char dc[4] = {'U', 'D', 'L', 'R'};\n\n    auto inside = [&](int r, int c) {\n        return (0 <= r && r < H && 0 <= c && c < W);\n    };\n\n    for (int r = 0; r < H; r++) {\n        for (int c = 0; c < W; c++) {\n            int v = r * W + c;\n            for (int d = 0; d < 4; d++) {\n                int nr = r + di[d], nc = c + dj[d];\n                if (!inside(nr, nc)) continue;\n                int to = nr * W + nc;\n                nextAll[v][d] = to;\n                if (tileId[to] != tileId[v]) {\n                    int k = degCell[v]++;\n                    nxtCell[v][k] = to;\n                    nxtDir[v][k] = dc[d];\n                }\n            }\n        }\n    }\n\n    // deterministic seed from input\n    uint64_t seed = 1469598103934665603ULL;\n    auto mixSeed = [&](uint64_t x) {\n        seed ^= x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed((uint64_t)(startCell + 1));\n    for (int v = 0; v < N; v++) {\n        uint64_t z = (uint64_t)(tileId[v] + 1) * 1315423911ULL\n                   ^ (uint64_t)(pval[v] + 1) * 2654435761ULL\n                   ^ (uint64_t)(v + 1) * 97531ULL;\n        mixSeed(z);\n    }\n    XorShift64 rng(seed);\n\n    using Clock = chrono::steady_clock;\n    auto t0 = Clock::now();\n    auto deadline = t0 + chrono::milliseconds(1910);\n    const double totalUs = (double)chrono::duration_cast<chrono::microseconds>(deadline - t0).count();\n\n    Result best;\n    vector<Result> elites;\n    const int ELITE_K = 8;\n\n    auto pushElite = [&](const Result& r) {\n        for (auto &e : elites) {\n            if (e.path == r.path) {\n                if (betterResult(r, e)) e = r;\n                sort(elites.begin(), elites.end(), betterResult);\n                if ((int)elites.size() > ELITE_K) elites.resize(ELITE_K);\n                return;\n            }\n        }\n        elites.push_back(r);\n        sort(elites.begin(), elites.end(), betterResult);\n        if ((int)elites.size() > ELITE_K) elites.resize(ELITE_K);\n    };\n\n    array<ModeStat, MODE_N> stats{};\n    int totalRuns = 0;\n    auto updateStat = [&](int mode, long long score) {\n        ModeStat &s = stats[mode];\n        s.n++;\n        s.mean += ((double)score - s.mean) / s.n;\n        totalRuns++;\n    };\n\n    // Initial runs\n    if (Clock::now() < deadline) {\n        RunParam rp = sampleParam(DEEP, 0.95, rng);\n        rp.wNoise = 0.0;\n        rp.epsMain = 0.0;\n        rp.evalNoise = 0.0;\n        rp.skipProb = 0.0;\n        rp.evalRollouts = max(rp.evalRollouts, 2);\n\n        Result r = simulate(rp, nullptr, 0, rng, deadline);\n        best = r;\n        pushElite(r);\n        updateStat(DEEP, r.score);\n    }\n\n    if (Clock::now() < deadline) {\n        RunParam rp = sampleParam(BAL, 0.20, rng);\n        Result r = simulate(rp, nullptr, 0, rng, deadline);\n        if (betterResult(r, best)) best = r;\n        pushElite(r);\n        updateStat(BAL, r.score);\n    }\n\n    // Start-prefix diversification (first move + best second move for each first)\n    vector<pair<int, string>> seedPref;\n    {\n        uint64_t vis0[WORDS];\n        bit_clear_all(vis0);\n        bit_set(vis0, tileId[startCell]);\n\n        int c1s[4];\n        char d1s[4];\n        int n1 = gatherMovesMain(startCell, vis0, c1s, d1s);\n\n        for (int i = 0; i < n1; i++) {\n            int a = c1s[i];\n            string s1(1, d1s[i]);\n            int sc1 = pval[a];\n            seedPref.push_back({sc1, s1});\n\n            uint64_t vis1[WORDS];\n            memcpy(vis1, vis0, sizeof(vis1));\n            bit_set(vis1, tileId[a]);\n\n            int c2s[4];\n            char d2s[4];\n            int n2 = gatherMovesMain(a, vis1, c2s, d2s);\n            if (n2 > 0) {\n                int best2 = 0;\n                for (int k = 1; k < n2; k++) {\n                    if (pval[c2s[k]] > pval[c2s[best2]]) best2 = k;\n                }\n                string s2 = s1;\n                s2.push_back(d2s[best2]);\n                seedPref.push_back({sc1 + pval[c2s[best2]], s2});\n            }\n        }\n    }\n\n    sort(seedPref.begin(), seedPref.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second.size() > b.second.size();\n    });\n\n    vector<string> prefixes;\n    for (auto &pr : seedPref) {\n        bool dup = false;\n        for (auto &s : prefixes) {\n            if (s == pr.second) { dup = true; break; }\n        }\n        if (!dup) prefixes.push_back(pr.second);\n        if ((int)prefixes.size() >= 6) break;\n    }\n\n    auto prefixBudgetEnd = t0 + chrono::milliseconds(340);\n    for (int i = 0; i < (int)prefixes.size(); i++) {\n        if (Clock::now() >= deadline || Clock::now() >= prefixBudgetEnd) break;\n        int mode = (i < 2 ? DEEP : BAL);\n        RunParam rp = sampleParam(mode, 0.20, rng);\n        if (mode == DEEP) rp.wNoise *= 0.3;\n        Result r = simulate(rp, &prefixes[i], (int)prefixes[i].size(), rng, deadline);\n        if (betterResult(r, best)) best = r;\n        pushElite(r);\n        updateStat(mode, r.score);\n    }\n\n    // Main loop\n    while (Clock::now() < deadline) {\n        double phase = (double)chrono::duration_cast<chrono::microseconds>(Clock::now() - t0).count() / totalUs;\n        phase = max(0.0, min(1.0, phase));\n\n        int mode = chooseMode(phase, rng, stats, totalRuns);\n        if (phase > 0.92 && rng.next_double() < 0.45) mode = DEEP;\n\n        RunParam rp = sampleParam(mode, phase, rng);\n\n        const string* basePath = nullptr;\n        int cut = 0;\n\n        double useEliteProb = (phase < 0.30 ? 0.62 : (phase < 0.85 ? 0.84 : 0.96));\n        if (!elites.empty() && rng.next_double() < useEliteProb) {\n            int top = (phase < 0.55 ? min<int>((int)elites.size(), 6) : min<int>((int)elites.size(), 4));\n            int idx = 0;\n            if (phase > 0.92 && rng.next_double() < 0.58) {\n                idx = 0;\n            } else {\n                double u = rng.next_double();\n                idx = (int)(u * u * top);\n                if (idx >= top) idx = top - 1;\n            }\n            basePath = &elites[idx].path;\n            bool intense = (mode == DEEP) && (phase > 0.86) && (idx == 0 || rng.next_double() < 0.55);\n            cut = pickCut((int)basePath->size(), phase, intense, rng);\n        } else if (phase < 0.25 && !prefixes.empty() && rng.next_double() < 0.18) {\n            int id = rng.next_int(0, (int)prefixes.size() - 1);\n            basePath = &prefixes[id];\n            cut = (int)prefixes[id].size();\n        }\n\n        Result cur = simulate(rp, basePath, cut, rng, deadline);\n        updateStat(mode, cur.score);\n\n        bool improved = betterResult(cur, best);\n        if (improved) best = cur;\n        pushElite(cur);\n\n        // Extra late intensification\n        if (Clock::now() < deadline) {\n            bool doExtra = false;\n            if (improved && phase > 0.50 && rng.next_double() < 0.35) doExtra = true;\n            else if (phase > 0.94 && rng.next_double() < 0.14) doExtra = true;\n\n            if (doExtra) {\n                RunParam ip = sampleParam(DEEP, 0.99, rng);\n                ip.wNoise *= 0.15;\n                ip.epsMain *= 0.20;\n                ip.evalNoise *= 0.20;\n\n                const string* bp = &best.path;\n                int cut2 = pickCut((int)bp->size(), 0.99, true, rng);\n                Result r2 = simulate(ip, bp, cut2, rng, deadline);\n                updateStat(DEEP, r2.score);\n\n                if (betterResult(r2, best)) best = r2;\n                pushElite(r2);\n            }\n        }\n    }\n\n    if (best.score == LLONG_MIN) cout << \"\\n\";\n    else cout << best.path << \"\\n\";\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nclass Solver {\n    static constexpr int N = 30;\n    static constexpr int Q = 1000;\n\n    static constexpr double COST_MIN = 1000.0;\n    static constexpr double COST_MAX = 9000.0;\n\n    static constexpr double PRIOR_CNT = 1.0;\n    static constexpr double DELTA_CLIP = 4200.0;\n\n    static constexpr int WARMUP_MONO = 45;\n    static constexpr int REFIT_INTERVAL = 20;\n\n    using HMatD = array<array<double, N - 1>, N>;\n    using VMatD = array<array<double, N>, N - 1>;\n    using HMatI = array<array<int, N - 1>, N>;\n    using VMatI = array<array<int, N>, N - 1>;\n\n    struct EdgeRef {\n        bool horiz; // true: H edge, false: V edge\n        int i, j;\n    };\n\n    struct FitInfo {\n        double mean1 = 5000.0;\n        int split = -1; // 1..28\n        double meanL = 5000.0;\n        double meanR = 5000.0;\n        double ratio = 0.0; // (sse1 - sse2) / sse1\n        double diff = 0.0;  // |meanL - meanR|\n        int cLeft = 0;\n        int cRight = 0;\n    };\n\n    // Base model (piecewise line parameters)\n    array<double, N> row0{}, row1{}, col0{}, col1{};\n    array<int, N> rowSplit{}, colSplit{}; // split=29 => effectively 1 segment\n\n    // Local residuals\n    HMatD deltaH{};\n    VMatD deltaV{};\n\n    // Visit counts\n    HMatI cntH{};\n    VMatI cntV{};\n\n    bool m2Likely = false;\n\n    mt19937 rng;\n    uniform_real_distribution<double> urd;\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 int vid(int i, int j) { return i * N + j; }\n\n    double rndSym() {\n        return urd(rng) * 2.0 - 1.0;\n    }\n\n    inline double baseH(int i, int j) const {\n        return (j < rowSplit[i]) ? row0[i] : row1[i];\n    }\n\n    inline double baseV(int i, int j) const {\n        return (i < colSplit[j]) ? col0[j] : col1[j];\n    }\n\n    inline double edgeEstH(int i, int j) const {\n        double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n        double c = baseH(i, j) + sh * deltaH[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    inline double edgeEstV(int i, int j) const {\n        double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n        double c = baseV(i, j) + sh * deltaV[i][j];\n        return clampd(c, COST_MIN, COST_MAX);\n    }\n\n    string directPath(int si, int sj, int ti, int tj) const {\n        string p;\n        if (ti > si) p.append(ti - si, 'D');\n        else p.append(si - ti, 'U');\n        if (tj > sj) p.append(tj - sj, 'R');\n        else p.append(sj - tj, 'L');\n        return p;\n    }\n\n    void buildCostTables(int q, HMatD& baseHMat, VMatD& baseVMat, HMatD& searchHMat, VMatD& searchVMat) {\n        double stepPenalty = (q < 140) ? (180.0 * (140 - q) / 140.0) : 0.0;\n        double bonusCoef = (q < 240) ? (360.0 * (240 - q) / 240.0) : 0.0;\n        double jitter = (q < 220) ? (0.025 * (220 - q) / 220.0) : 0.0;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                double b = edgeEstH(i, j);\n                baseHMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntH[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchHMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                double b = edgeEstV(i, j);\n                baseVMat[i][j] = b;\n\n                double c = b + stepPenalty;\n                double unc = 1.0 / sqrt(cntV[i][j] + 1.0);\n                if (bonusCoef > 0.0) c -= bonusCoef * unc;\n                if (jitter > 0.0) c *= (1.0 + jitter * unc * rndSym());\n                searchVMat[i][j] = clampd(c, 1.0, 20000.0);\n            }\n        }\n    }\n\n    string dijkstraPath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        constexpr double INF = 1e100;\n        array<double, N * N> dist;\n        array<int, N * N> prv;\n        array<char, N * N> pmv;\n        dist.fill(INF);\n        prv.fill(-1);\n        pmv.fill(0);\n\n        int S = vid(si, sj), T = vid(ti, tj);\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[S] = 0.0;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if (d > dist[u] + 1e-12) continue;\n            if (u == T) break;\n\n            int i = u / N, j = u % N;\n\n            if (i > 0) {\n                int to = vid(i - 1, j);\n                double nd = d + v[i - 1][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'U';\n                    pq.push({nd, to});\n                }\n            }\n            if (i + 1 < N) {\n                int to = vid(i + 1, j);\n                double nd = d + v[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'D';\n                    pq.push({nd, to});\n                }\n            }\n            if (j > 0) {\n                int to = vid(i, j - 1);\n                double nd = d + h[i][j - 1];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'L';\n                    pq.push({nd, to});\n                }\n            }\n            if (j + 1 < N) {\n                int to = vid(i, j + 1);\n                double nd = d + h[i][j];\n                if (nd + 1e-12 < dist[to]) {\n                    dist[to] = nd;\n                    prv[to] = u;\n                    pmv[to] = 'R';\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        if (prv[T] == -1) return directPath(si, sj, ti, tj);\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmv[cur]);\n            cur = prv[cur];\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Best among monotone-only paths (length = Manhattan)\n    string bestMonotoneDP(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) const {\n        if (si == ti && sj == tj) return \"\";\n\n        int di = (ti > si) ? 1 : (ti < si ? -1 : 0);\n        int dj = (tj > sj) ? 1 : (tj < sj ? -1 : 0);\n\n        int R = abs(ti - si) + 1;\n        int C = abs(tj - sj) + 1;\n\n        const double INF = 1e100;\n        vector<vector<double>> dp(R, vector<double>(C, INF));\n        vector<vector<char>> pre(R, vector<char>(C, 0));\n        dp[0][0] = 0.0;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = 0; b < C; b++) {\n                if (dp[a][b] >= INF / 2) continue;\n                int i = si + di * a;\n                int j = sj + dj * b;\n\n                if (a + 1 < R) {\n                    double w = (di == 1) ? v[i][j] : v[i - 1][j];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a + 1][b]) {\n                        dp[a + 1][b] = nd;\n                        pre[a + 1][b] = 'V';\n                    }\n                }\n                if (b + 1 < C) {\n                    double w = (dj == 1) ? h[i][j] : h[i][j - 1];\n                    double nd = dp[a][b] + w;\n                    if (nd < dp[a][b + 1]) {\n                        dp[a][b + 1] = nd;\n                        pre[a][b + 1] = 'H';\n                    }\n                }\n            }\n        }\n\n        string path;\n        int a = R - 1, b = C - 1;\n        while (a > 0 || b > 0) {\n            char p = pre[a][b];\n            if (p == 'V') {\n                path.push_back(di == 1 ? 'D' : 'U');\n                --a;\n            } else {\n                path.push_back(dj == 1 ? 'R' : 'L');\n                --b;\n            }\n        }\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    // Warmup monotone exploration\n    string biasedMonotonePath(int si, int sj, int ti, int tj, const HMatD& h, const VMatD& v) {\n        int i = si, j = sj;\n        string path;\n        path.reserve(abs(ti - si) + abs(tj - sj));\n\n        while (i != ti || j != tj) {\n            bool canV = (i != ti);\n            bool canH = (j != tj);\n\n            if (canV && canH) {\n                double cv, ch;\n                int nv, nh;\n\n                if (ti > i) { // D\n                    cv = v[i][j];\n                    nv = cntV[i][j];\n                } else {      // U\n                    cv = v[i - 1][j];\n                    nv = cntV[i - 1][j];\n                }\n\n                if (tj > j) { // R\n                    ch = h[i][j];\n                    nh = cntH[i][j];\n                } else {      // L\n                    ch = h[i][j - 1];\n                    nh = cntH[i][j - 1];\n                }\n\n                double sv = (1.0 / (cv + 1e-9)) * (1.0 + 1.2 / sqrt(nv + 1.0));\n                double sh = (1.0 / (ch + 1e-9)) * (1.0 + 1.2 / sqrt(nh + 1.0));\n\n                double r = urd(rng) * (sv + sh);\n                if (r < sv) {\n                    if (ti > i) { path.push_back('D'); ++i; }\n                    else { path.push_back('U'); --i; }\n                } else {\n                    if (tj > j) { path.push_back('R'); ++j; }\n                    else { path.push_back('L'); --j; }\n                }\n            } else if (canV) {\n                if (ti > i) { path.push_back('D'); ++i; }\n                else { path.push_back('U'); --i; }\n            } else {\n                if (tj > j) { path.push_back('R'); ++j; }\n                else { path.push_back('L'); --j; }\n            }\n        }\n\n        return path;\n    }\n\n    void pathToEdges(\n        int si, int sj, const string& path, vector<EdgeRef>& edges,\n        array<int, N>& row0Cnt, array<int, N>& row1Cnt,\n        array<int, N>& col0Cnt, array<int, N>& col1Cnt\n    ) const {\n        row0Cnt.fill(0);\n        row1Cnt.fill(0);\n        col0Cnt.fill(0);\n        col1Cnt.fill(0);\n\n        edges.clear();\n        edges.reserve(path.size());\n\n        int i = si, j = sj;\n        for (char c : path) {\n            if (c == 'U') {\n                int ei = i - 1, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                --i;\n            } else if (c == 'D') {\n                int ei = i, ej = j;\n                edges.push_back({false, ei, ej});\n                if (ei < colSplit[ej]) col0Cnt[ej]++;\n                else col1Cnt[ej]++;\n                ++i;\n            } else if (c == 'L') {\n                int ei = i, ej = j - 1;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                --j;\n            } else { // 'R'\n                int ei = i, ej = j;\n                edges.push_back({true, ei, ej});\n                if (ej < rowSplit[ei]) row0Cnt[ei]++;\n                else row1Cnt[ei]++;\n                ++j;\n            }\n        }\n    }\n\n    FitInfo fitLine29(const array<double, N - 1>& val, const array<int, N - 1>& cnt) const {\n        const double W0 = 0.35;\n\n        array<double, N> pw{}, ps{}, ps2{};\n        array<int, N> pc{};\n        for (int k = 0; k < N - 1; k++) {\n            double w = cnt[k] + W0;\n            double x = val[k];\n            pw[k + 1] = pw[k] + w;\n            ps[k + 1] = ps[k] + w * x;\n            ps2[k + 1] = ps2[k] + w * x * x;\n            pc[k + 1] = pc[k] + cnt[k];\n        }\n\n        FitInfo f;\n\n        double W = pw[N - 1];\n        double S = ps[N - 1];\n        double Qv = ps2[N - 1];\n        if (W <= 1e-12) {\n            f.mean1 = 5000.0;\n            return f;\n        }\n\n        f.mean1 = S / W;\n        double sse1 = max(0.0, Qv - S * S / W);\n\n        double bestSSE = 1e100;\n        int bestS = -1;\n        double bestL = f.mean1, bestR = f.mean1;\n\n        for (int s = 1; s <= N - 2; s++) { // 1..28\n            double WL = pw[s], WR = pw[N - 1] - pw[s];\n            if (WL <= 1e-12 || WR <= 1e-12) continue;\n\n            double SL = ps[s], SR = ps[N - 1] - ps[s];\n            double QL = ps2[s], QR = ps2[N - 1] - ps2[s];\n\n            double mL = SL / WL, mR = SR / WR;\n            double sse = max(0.0, QL - SL * SL / WL) + max(0.0, QR - SR * SR / WR);\n\n            if (sse < bestSSE) {\n                bestSSE = sse;\n                bestS = s;\n                bestL = mL;\n                bestR = mR;\n            }\n        }\n\n        f.split = bestS;\n        if (bestS == -1) {\n            f.meanL = f.meanR = f.mean1;\n            f.ratio = 0.0;\n            f.diff = 0.0;\n            return f;\n        }\n\n        f.meanL = bestL;\n        f.meanR = bestR;\n        f.diff = fabs(bestL - bestR);\n        f.cLeft = pc[bestS];\n        f.cRight = pc[N - 1] - pc[bestS];\n        f.ratio = (sse1 - bestSSE) / max(1.0, sse1);\n        if (f.ratio < 0.0) f.ratio = 0.0;\n\n        return f;\n    }\n\n    void refitStructure(int q) {\n        // 1) Current effective estimates\n        HMatD effH;\n        VMatD effV;\n        for (int i = 0; i < N; i++) for (int j = 0; j < N - 1; j++) effH[i][j] = edgeEstH(i, j);\n        for (int i = 0; i < N - 1; i++) for (int j = 0; j < N; j++) effV[i][j] = edgeEstV(i, j);\n\n        // 2) Fit each row/column as 1-seg vs best 2-seg\n        array<FitInfo, N> rowFit, colFit;\n\n        for (int i = 0; i < N; i++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int j = 0; j < N - 1; j++) {\n                val[j] = effH[i][j];\n                cnt[j] = cntH[i][j];\n            }\n            rowFit[i] = fitLine29(val, cnt);\n        }\n\n        for (int j = 0; j < N; j++) {\n            array<double, N - 1> val{};\n            array<int, N - 1> cnt{};\n            for (int i = 0; i < N - 1; i++) {\n                val[i] = effV[i][j];\n                cnt[i] = cntV[i][j];\n            }\n            colFit[j] = fitLine29(val, cnt);\n        }\n\n        // 3) Infer whether M=2 is likely globally\n        int strong = 0, considered = 0;\n        auto countStrong = [&](const FitInfo& f) {\n            if (f.split < 1 || f.split > N - 2) return;\n            int mc = min(f.cLeft, f.cRight);\n            if (mc < 5) return;\n            considered++;\n            if (f.ratio > 0.09 && f.diff > 500.0) strong++;\n        };\n        for (int i = 0; i < N; i++) countStrong(rowFit[i]);\n        for (int j = 0; j < N; j++) countStrong(colFit[j]);\n\n        if (q >= 70 && considered >= 20) {\n            if (strong >= 18) m2Likely = true;\n            else if (strong <= 8) m2Likely = false;\n        }\n\n        auto useTwoSeg = [&](const FitInfo& f) -> bool {\n            if (f.split < 1 || f.split > N - 2) return false;\n            if (q < 55) return false;\n            int mc = min(f.cLeft, f.cRight);\n\n            if (m2Likely) {\n                double thrRatio = (q < 220) ? 0.07 : 0.045;\n                double thrDiff = (q < 220) ? 450.0 : 300.0;\n                int thrCnt = (q < 220) ? 5 : 3;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            } else {\n                // strict mode for likely M=1, but allow very strong evidence\n                if (f.ratio > 0.22 && f.diff > 1200.0 && mc >= 8) return true;\n                double thrRatio = (q < 320) ? 0.16 : 0.12;\n                double thrDiff = (q < 320) ? 800.0 : 650.0;\n                int thrCnt = (q < 320) ? 10 : 7;\n                return (mc >= thrCnt && f.ratio > thrRatio && f.diff > thrDiff);\n            }\n        };\n\n        // 4) Update base model\n        for (int i = 0; i < N; i++) {\n            const auto& f = rowFit[i];\n            if (useTwoSeg(f)) {\n                rowSplit[i] = f.split;\n                row0[i] = clampd(f.meanL, COST_MIN, COST_MAX);\n                row1[i] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                rowSplit[i] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                row0[i] = m;\n                row1[i] = m;\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            const auto& f = colFit[j];\n            if (useTwoSeg(f)) {\n                colSplit[j] = f.split;\n                col0[j] = clampd(f.meanL, COST_MIN, COST_MAX);\n                col1[j] = clampd(f.meanR, COST_MIN, COST_MAX);\n            } else {\n                colSplit[j] = N - 1;\n                double m = clampd(f.mean1, COST_MIN, COST_MAX);\n                col0[j] = m;\n                col1[j] = m;\n            }\n        }\n\n        // 5) Re-center local residuals around the new base\n        //    (trusted edges mostly preserved; low-count edges pulled to new base)\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N - 1; j++) {\n                if (cntH[i][j] == 0) {\n                    deltaH[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseH(i, j);\n                double sh = static_cast<double>(cntH[i][j]) / (cntH[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaH[i][j] = clampd((effH[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n\n        for (int i = 0; i < N - 1; i++) {\n            for (int j = 0; j < N; j++) {\n                if (cntV[i][j] == 0) {\n                    deltaV[i][j] = 0.0;\n                    continue;\n                }\n                double b = baseV(i, j);\n                double sh = static_cast<double>(cntV[i][j]) / (cntV[i][j] + PRIOR_CNT);\n                double denom = max(0.70, sh);\n                deltaV[i][j] = clampd((effV[i][j] - b) / denom, -DELTA_CLIP, DELTA_CLIP);\n            }\n        }\n    }\n\npublic:\n    Solver() : rng(20240315), urd(0.0, 1.0) {\n        row0.fill(5000.0);\n        row1.fill(5000.0);\n        col0.fill(5000.0);\n        col1.fill(5000.0);\n        rowSplit.fill(N - 1);\n        colSplit.fill(N - 1);\n\n        for (auto& r : deltaH) r.fill(0.0);\n        for (auto& r : deltaV) r.fill(0.0);\n        for (auto& r : cntH) r.fill(0);\n        for (auto& r : cntV) r.fill(0);\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int q = 0; q < Q; q++) {\n            if (q > 0 && q % REFIT_INTERVAL == 0) {\n                refitStructure(q);\n            }\n\n            int si, sj, ti, tj;\n            if (!(cin >> si >> sj >> ti >> tj)) return;\n\n            HMatD baseHMat, searchHMat;\n            VMatD baseVMat, searchVMat;\n            buildCostTables(q, baseHMat, baseVMat, searchHMat, searchVMat);\n\n            string path;\n            if (q < WARMUP_MONO) {\n                path = biasedMonotonePath(si, sj, ti, tj, baseHMat, baseVMat);\n            } else {\n                path = dijkstraPath(si, sj, ti, tj, searchHMat, searchVMat);\n\n                int md = abs(si - ti) + abs(sj - tj);\n                int detourLimit = (q < 200) ? 10 : 16;\n                if ((int)path.size() > md + detourLimit) {\n                    path = bestMonotoneDP(si, sj, ti, tj, baseHMat, baseVMat);\n                }\n            }\n\n            cout << path << '\\n' << flush;\n\n            int obsInt;\n            if (!(cin >> obsInt)) return;\n            if (obsInt < 0) return; // interactive guard\n            double obs = static_cast<double>(obsInt);\n\n            vector<EdgeRef> edges;\n            array<int, N> row0Cnt, row1Cnt, col0Cnt, col1Cnt;\n            pathToEdges(si, sj, path, edges, row0Cnt, row1Cnt, col0Cnt, col1Cnt);\n\n            if (edges.empty()) continue;\n\n            // Prediction before update\n            double pred = 0.0;\n            for (const auto& e : edges) {\n                pred += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double err = obs - pred;\n\n            // Segment-level base update\n            double norm = 1e-9;\n            for (int i = 0; i < N; i++) {\n                norm += 1.0 * row0Cnt[i] * row0Cnt[i];\n                norm += 1.0 * row1Cnt[i] * row1Cnt[i];\n            }\n            for (int j = 0; j < N; j++) {\n                norm += 1.0 * col0Cnt[j] * col0Cnt[j];\n                norm += 1.0 * col1Cnt[j] * col1Cnt[j];\n            }\n\n            double etaBase = 0.40 * exp(-0.0022 * q) + 0.06;\n\n            for (int i = 0; i < N; i++) {\n                if (row0Cnt[i]) {\n                    row0[i] += etaBase * err * row0Cnt[i] / norm;\n                    row0[i] = clampd(row0[i], COST_MIN, COST_MAX);\n                }\n                if (row1Cnt[i]) {\n                    row1[i] += etaBase * err * row1Cnt[i] / norm;\n                    row1[i] = clampd(row1[i], COST_MIN, COST_MAX);\n                }\n            }\n            for (int j = 0; j < N; j++) {\n                if (col0Cnt[j]) {\n                    col0[j] += etaBase * err * col0Cnt[j] / norm;\n                    col0[j] = clampd(col0[j], COST_MIN, COST_MAX);\n                }\n                if (col1Cnt[j]) {\n                    col1[j] += etaBase * err * col1Cnt[j] / norm;\n                    col1[j] = clampd(col1[j], COST_MIN, COST_MAX);\n                }\n            }\n\n            // Residual after base update\n            double pred2 = 0.0;\n            for (const auto& e : edges) {\n                pred2 += e.horiz ? edgeEstH(e.i, e.j) : edgeEstV(e.i, e.j);\n            }\n            double residual = obs - pred2;\n\n            // Local residual update (uncertainty weighted)\n            double etaDelta = 0.60 * exp(-0.0015 * q) + 0.18;\n\n            vector<double> w(edges.size());\n            double sw = 0.0;\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                int c = e.horiz ? cntH[e.i][e.j] : cntV[e.i][e.j];\n                w[idx] = 1.0 / sqrt(c + 1.0);\n                sw += w[idx];\n            }\n            if (sw < 1e-12) sw = 1.0;\n\n            for (size_t idx = 0; idx < edges.size(); idx++) {\n                const auto& e = edges[idx];\n                double d = etaDelta * residual * w[idx] / sw;\n                if (e.horiz) {\n                    deltaH[e.i][e.j] = clampd(deltaH[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntH[e.i][e.j]++;\n                } else {\n                    deltaV[e.i][e.j] = clampd(deltaV[e.i][e.j] + d, -DELTA_CLIP, DELTA_CLIP);\n                    cntV[e.i][e.j]++;\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M;\n    int CELL, PPS, P;\n\n    vector<vector<uint8_t>> strs;\n    vector<uint8_t> len;\n    vector<int> groupLen;\n\n    // For each cell, entries are grouped by sid.\n    // packed = (pid << 3) | req(0..7)\n    vector<vector<uint32_t>> cellEntries;\n\n    vector<int16_t> matchCount;       // per placement\n    vector<array<int, 13>> hist;      // hist[sid][mc]\n    vector<uint8_t> best;             // best mc per sid\n\n    vector<int> fullCnt;              // #full placements per sid\n    int cCur = 0;                     // #sid with fullCnt > 0\n\n    vector<uint8_t> grid;\n    vector<uint8_t> bestGrid;\n    vector<uint8_t> altGrid;          // second elite basin\n\n    int bestC = -1, bestSoft = -1;\n    int altC = -1, altSoft = -1;\n\n    int g1[13];\n    int scoreTbl[13][13];\n\n    int lenW[13];\n    vector<int> sidW;\n    bool curLenBias = false;\n\n    vector<int> order;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 2.94;\n\n    Solver(int N_, int M_, const vector<string>& S) : N(N_), M(M_) {\n        CELL = N * N;\n        PPS = 2 * CELL;\n        P = M * PPS;\n\n        strs.resize(M);\n        len.resize(M);\n        groupLen.resize(M);\n\n        for (int i = 0; i < M; i++) {\n            len[i] = (uint8_t)S[i].size();\n            groupLen[i] = 2 * (int)len[i];\n            strs[i].resize(len[i]);\n            for (int j = 0; j < (int)len[i]; j++) strs[i][j] = (uint8_t)(S[i][j] - 'A');\n        }\n\n        // Mild length emphasis for soft tie-break\n        for (int k = 0; k <= 12; k++) {\n            if (k <= 6) lenW[k] = 1;\n            else if (k <= 8) lenW[k] = 2;\n            else if (k <= 10) lenW[k] = 3;\n            else lenW[k] = 4;\n        }\n\n        cellEntries.assign(CELL, {});\n        buildEntries();\n\n        matchCount.assign(P, 0);\n\n        hist.resize(M);\n        for (auto &a : hist) a.fill(0);\n        best.assign(M, 0);\n\n        fullCnt.assign(M, 0);\n\n        grid.assign(CELL, 0);\n        bestGrid.assign(CELL, 0);\n        altGrid.assign(CELL, 0);\n\n        sidW.assign(M, 1);\n\n        order.resize(CELL);\n        iota(order.begin(), order.end(), 0);\n\n        g1[0] = 1;\n        for (int i = 1; i <= 12; i++) g1[i] = g1[i - 1] << 1;\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        seed ^= (uint64_t)P * 1009ULL;\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline int randInt(int l, int r) {\n        return l + (int)(rng() % (uint32_t)(r - l + 1));\n    }\n\n    void buildEntries() {\n        int perCell = 0;\n        for (int i = 0; i < M; i++) perCell += groupLen[i];\n        for (int c = 0; c < CELL; c++) cellEntries[c].reserve(perCell);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            int k = len[sid];\n            for (int r = 0; r < N; r++) {\n                for (int c = 0; c < N; c++) {\n                    int start = r * N + c;\n                    int pidH = base + start;\n                    int pidV = base + CELL + start;\n                    for (int p = 0; p < k; p++) {\n                        uint32_t req = strs[sid][p];\n                        int ch = r * N + ((c + p) % N);\n                        int cv = ((r + p) % N) * N + c;\n                        cellEntries[ch].push_back((uint32_t(pidH) << 3) | req);\n                        cellEntries[cv].push_back((uint32_t(pidV) << 3) | req);\n                    }\n                }\n            }\n        }\n    }\n\n    inline bool betterPair(int c1, int s1, int c2, int s2) const {\n        return (c1 > c2) || (c1 == c2 && s1 > s2);\n    }\n\n    int hammingDist(const vector<uint8_t>& a, const vector<uint8_t>& b) const {\n        int d = 0;\n        for (int i = 0; i < CELL; i++) d += (a[i] != b[i]);\n        return d;\n    }\n\n    void considerAlt(const vector<uint8_t>& cand, int c, int s, const vector<uint8_t>& ref) {\n        if (c < 0) return;\n        if (hammingDist(cand, ref) < 20) return;\n        if (altC < 0 || betterPair(c, s, altC, altSoft)) {\n            altC = c;\n            altSoft = s;\n            altGrid = cand;\n        }\n    }\n\n    void prepareBias(bool lenBias) {\n        curLenBias = lenBias;\n        if (!lenBias) {\n            for (int i = 0; i < M; i++) sidW[i] = 1;\n        } else {\n            for (int i = 0; i < M; i++) sidW[i] = lenW[len[i]];\n        }\n    }\n\n    void initRandom() {\n        for (int i = 0; i < CELL; i++) grid[i] = (uint8_t)(rng() & 7);\n    }\n\n    void initFromBest() {\n        const vector<uint8_t>* src = &bestGrid;\n        if (altC >= 0 && randInt(0, 99) < 30) src = &altGrid;\n        grid = *src;\n\n        int mut;\n        if (bestC >= (int)(0.75 * M)) mut = randInt(6, 24);\n        else if (bestC >= (int)(0.60 * M)) mut = randInt(10, 40);\n        else mut = randInt(20, 80);\n\n        for (int i = 0; i < mut; i++) {\n            int cell = randInt(0, CELL - 1);\n            grid[cell] = (uint8_t)randInt(0, 7);\n        }\n\n        // Torus shift (objective invariant)\n        if (randInt(0, 1)) {\n            int dr = randInt(0, N - 1), dc = randInt(0, N - 1);\n            vector<uint8_t> tmp = grid;\n            for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n                int nr = (r + dr) % N, nc = (c + dc) % N;\n                grid[nr * N + nc] = tmp[r * N + c];\n            }\n        }\n\n        // Occasional transpose (also invariant)\n        if (randInt(0, 9) == 0) {\n            vector<uint8_t> tmp = grid;\n            for (int r = 0; r < N; r++) for (int c = 0; c < N; c++) {\n                grid[c * N + r] = tmp[r * N + c];\n            }\n        }\n    }\n\n    void recomputeMatchCount() {\n        fill(matchCount.begin(), matchCount.end(), 0);\n        for (int cell = 0; cell < CELL; cell++) {\n            int ch = grid[cell];\n            if (ch > 7) continue;\n            const auto &vec = cellEntries[cell];\n            for (uint32_t x : vec) {\n                if ((int)(x & 7u) == ch) {\n                    int pid = (int)(x >> 3);\n                    matchCount[pid]++;\n                }\n            }\n        }\n    }\n\n    int phase1Sweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 15) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            long long bonus[8] = {0,0,0,0,0,0,0,0};\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                int w = sidW[sid];\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n                    int mc = matchCount[pid];\n                    int base = mc - ((old == req) ? 1 : 0);\n                    bonus[req] += 1LL * w * (g1[base + 1] - g1[base]);\n                }\n                pos += gsz;\n            }\n\n            int nw = old;\n            long long bestV = bonus[old];\n            int tie = 1;\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                if (bonus[a] > bestV) {\n                    bestV = bonus[a];\n                    nw = a;\n                    tie = 1;\n                } else if (bonus[a] == bestV && bonus[a] > bonus[old]) {\n                    tie++;\n                    if ((int)(rng() % tie) == 0) nw = a;\n                }\n            }\n\n            if (nw == old) continue;\n\n            for (uint32_t x : vec) {\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                if (req == old) matchCount[pid]--;\n                else if (req == nw) matchCount[pid]++;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildHistBest() {\n        for (int sid = 0; sid < M; sid++) hist[sid].fill(0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int base = sid * PPS;\n            for (int t = 0; t < PPS; t++) {\n                int mc = matchCount[base + t];\n                hist[sid][mc]++;\n            }\n        }\n\n        for (int sid = 0; sid < M; sid++) {\n            int b = len[sid];\n            while (b > 0 && hist[sid][b] == 0) b--;\n            best[sid] = (uint8_t)b;\n        }\n    }\n\n    inline int calcC() const {\n        int c = 0;\n        for (int sid = 0; sid < M; sid++) if (best[sid] == len[sid]) c++;\n        return c;\n    }\n\n    inline int calcSoft() const {\n        int s = 0;\n        for (int sid = 0; sid < M; sid++) s += lenW[len[sid]] * (int)best[sid];\n        return s;\n    }\n\n    void updateGlobal() {\n        int c = calcC();\n        int soft = calcSoft();\n\n        if (betterPair(c, soft, bestC, bestSoft)) {\n            if (bestC >= 0) considerAlt(bestGrid, bestC, bestSoft, grid);\n            bestC = c;\n            bestSoft = soft;\n            bestGrid = grid;\n        } else {\n            considerAlt(grid, c, soft, bestGrid);\n        }\n    }\n\n    void updateGlobalByCOnly() {\n        if (cCur > bestC) {\n            if (bestC >= 0) considerAlt(bestGrid, bestC, bestSoft, grid);\n            bestC = cCur;\n            bestSoft = -1;\n            bestGrid = grid;\n        } else if (cCur == bestC) {\n            considerAlt(grid, cCur, -1, bestGrid);\n        }\n    }\n\n    void buildScoreTbl(int fullBonus) {\n        for (int k = 0; k <= 12; k++) {\n            int w = curLenBias ? lenW[k] : 1;\n            for (int b = 0; b <= 12; b++) {\n                if (b > k) scoreTbl[k][b] = -1000000000;\n                else scoreTbl[k][b] = w * b * b + ((b == k) ? fullBonus : 0);\n            }\n        }\n    }\n\n    pair<int, long long> chooseLetterPhase2(int cell) {\n        int old = grid[cell];\n        long long delta[8] = {0,0,0,0,0,0,0,0};\n\n        const auto &vec = cellEntries[cell];\n        int pos = 0;\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int b = best[sid];\n            int gsz = groupLen[sid];\n\n            int cnt[8][3];\n            memset(cnt, 0, sizeof(cnt));\n\n            for (int t = 0; t < gsz; t++) {\n                uint32_t x = vec[pos + t];\n                int req = (int)(x & 7u);\n                int pid = (int)(x >> 3);\n                int mc = matchCount[pid];\n\n                if (b > 0 && mc == b - 1) cnt[req][0]++;\n                if (mc == b) cnt[req][1]++;\n                if (b < k && mc == b + 1) cnt[req][2]++;\n            }\n            pos += gsz;\n\n            int baseScore = scoreTbl[k][b];\n            int hb = hist[sid][b];\n            int hbp1 = (b < k ? hist[sid][b + 1] : 0);\n\n            int old0 = cnt[old][1];\n            int oldp1 = cnt[old][2];\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                int nb;\n\n                if (b < k) {\n                    int cb1 = hbp1 - oldp1 + cnt[a][1];\n                    if (cb1 > 0) {\n                        nb = b + 1;\n                    } else {\n                        int cb = hb - old0 + oldp1 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                        nb = (cb > 0 ? b : b - 1);\n                        if (nb < 0) nb = 0;\n                    }\n                } else {\n                    int cb = hb - old0 - cnt[a][1] + (b > 0 ? cnt[a][0] : 0);\n                    nb = (cb > 0 ? b : b - 1);\n                    if (nb < 0) nb = 0;\n                }\n\n                delta[a] += (long long)scoreTbl[k][nb] - baseScore;\n            }\n        }\n\n        int nw = old;\n        long long bestD = 0;\n        int tie = 1;\n        for (int a = 0; a < 8; a++) {\n            if (a == old) continue;\n            if (delta[a] > bestD) {\n                bestD = delta[a];\n                nw = a;\n                tie = 1;\n            } else if (delta[a] == bestD && bestD > 0) {\n                tie++;\n                if ((int)(rng() % tie) == 0) nw = a;\n            }\n        }\n\n        return {nw, bestD};\n    }\n\n    int phase2Sweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 7) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            auto [nw, gain] = chooseLetterPhase2(cell);\n            if (nw == old || gain <= 0) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc + 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc + 1]++;\n                    }\n                }\n                pos += gsz;\n\n                int b = best[sid];\n                int k = len[sid];\n                if (b < k && hist[sid][b + 1] > 0) b++;\n                else if (b > 0 && hist[sid][b] == 0) b--;\n                best[sid] = (uint8_t)b;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void buildFullCnt() {\n        cCur = 0;\n        fill(fullCnt.begin(), fullCnt.end(), 0);\n\n        for (int sid = 0; sid < M; sid++) {\n            int k = len[sid];\n            int base = sid * PPS;\n            int cnt = 0;\n            for (int t = 0; t < PPS; t++) {\n                if (matchCount[base + t] == k) cnt++;\n            }\n            fullCnt[sid] = cnt;\n            if (cnt > 0) cCur++;\n        }\n    }\n\n    // Exact c-local search: lexicographic (deltaC, deltaSmoothRelative)\n    int exactSweep(double deadline) {\n        shuffle(order.begin(), order.end(), rng);\n        int changes = 0;\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 7) == 0 && elapsed() >= deadline) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n\n            int deltaC[8] = {0,0,0,0,0,0,0,0};\n            long long sm[8] = {0,0,0,0,0,0,0,0};\n\n            int pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                int k = len[sid];\n                int fc = fullCnt[sid];\n                int was = (fc > 0);\n\n                int cntF[8]  = {0,0,0,0,0,0,0,0};\n                int cntM1[8] = {0,0,0,0,0,0,0,0};\n\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n                    int mc = matchCount[pid];\n\n                    int base = mc - ((old == req) ? 1 : 0);\n                    sm[req] += (long long)g1[base + 1] - g1[base];\n\n                    if (mc == k) cntF[req]++;\n                    else if (mc == k - 1) cntM1[req]++;\n                }\n                pos += gsz;\n\n                int oldLose = cntF[old];\n                for (int a = 0; a < 8; a++) {\n                    if (a == old) continue;\n                    int newFc = fc - oldLose + cntM1[a];\n                    int now = (newFc > 0);\n                    deltaC[a] += (now - was);\n                }\n            }\n\n            long long smOld = sm[old];\n\n            int nw = old;\n            int bestDC = 0;\n            long long bestDS = 0;\n            int tie = 1;\n\n            for (int a = 0; a < 8; a++) {\n                if (a == old) continue;\n                long long ds = sm[a] - smOld;\n\n                if (deltaC[a] > bestDC) {\n                    bestDC = deltaC[a];\n                    bestDS = ds;\n                    nw = a;\n                    tie = 1;\n                } else if (deltaC[a] == bestDC) {\n                    if (ds > bestDS) {\n                        bestDS = ds;\n                        nw = a;\n                        tie = 1;\n                    } else if (ds == bestDS && (bestDC > 0 || bestDS > 0)) {\n                        tie++;\n                        if ((int)(rng() % tie) == 0) nw = a;\n                    }\n                }\n            }\n\n            if (nw == old) continue;\n            if (bestDC == 0 && bestDS <= 0) continue;\n\n            // apply move\n            pos = 0;\n            for (int sid = 0; sid < M; sid++) {\n                bool before = (fullCnt[sid] > 0);\n                int k = len[sid];\n                int gsz = groupLen[sid];\n\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    int pid = (int)(x >> 3);\n\n                    if (req == old) {\n                        int mc = matchCount[pid];\n                        if (mc == k) fullCnt[sid]--;\n                        matchCount[pid] = (int16_t)(mc - 1);\n                    } else if (req == nw) {\n                        int mc = matchCount[pid];\n                        if (mc == k - 1) fullCnt[sid]++;\n                        matchCount[pid] = (int16_t)(mc + 1);\n                    }\n                }\n                pos += gsz;\n\n                bool after = (fullCnt[sid] > 0);\n                if (before != after) cCur += after ? 1 : -1;\n            }\n\n            grid[cell] = (uint8_t)nw;\n            changes++;\n        }\n\n        return changes;\n    }\n\n    void runOne(double deadline, bool fromBest, bool lenBias) {\n        prepareBias(lenBias);\n\n        if (fromBest && bestC >= 0) initFromBest();\n        else initRandom();\n\n        recomputeMatchCount();\n\n        int p1 = fromBest ? 2 + randInt(0, 1) : 5 + randInt(0, 1);\n        if (lenBias && !fromBest) p1++;\n\n        for (int i = 0; i < p1; i++) {\n            if (elapsed() >= deadline) return;\n            int ch = phase1Sweep(deadline);\n            if (ch == 0) break;\n        }\n\n        if (elapsed() >= deadline) return;\n        buildHistBest();\n        updateGlobal();\n\n        array<int, 4> bonus, sweeps;\n        if (lenBias) {\n            bonus = {0, 120, 2500, 100000};\n            sweeps = {2, 3, 3, 2};\n        } else {\n            bonus = {0, 180, 4000, 130000};\n            sweeps = {2, 2, 3, 2};\n        }\n\n        for (int st = 0; st < 4; st++) {\n            if (elapsed() >= deadline) return;\n            buildScoreTbl(bonus[st]);\n\n            int lim = sweeps[st];\n            if (fromBest && st == 0) lim = max(1, lim - 1);\n\n            for (int it = 0; it < lim; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n        }\n\n        // kick + recover\n        if (elapsed() < deadline - 0.07) {\n            int mut = fromBest ? randInt(6, 18) : randInt(12, 34);\n            for (int i = 0; i < mut; i++) {\n                int cell = randInt(0, CELL - 1);\n                grid[cell] = (uint8_t)randInt(0, 7);\n            }\n\n            recomputeMatchCount();\n            if (elapsed() < deadline - 0.05) phase1Sweep(deadline - 0.04);\n\n            if (elapsed() >= deadline) return;\n            buildHistBest();\n            updateGlobal();\n\n            buildScoreTbl(lenBias ? 7000 : 9000);\n            for (int it = 0; it < 2; it++) {\n                if (elapsed() >= deadline) return;\n                int ch = phase2Sweep(deadline);\n                updateGlobal();\n                if (ch == 0) break;\n            }\n\n            if (!lenBias && elapsed() < deadline - 0.02) {\n                buildScoreTbl(170000);\n                (void)phase2Sweep(deadline);\n                updateGlobal();\n            }\n        }\n\n        // exact c polish\n        if (elapsed() < deadline - 0.02) {\n            buildFullCnt();\n            updateGlobalByCOnly();\n\n            int lim = fromBest ? 2 : 3;\n            if (lenBias && !fromBest) lim++;\n\n            for (int it = 0; it < lim; it++) {\n                if (elapsed() >= deadline) break;\n                int ch = exactSweep(deadline);\n                updateGlobalByCOnly();\n                if (ch == 0) break;\n            }\n\n            if (elapsed() < deadline - 0.003) {\n                buildHistBest();\n                updateGlobal();\n            }\n        }\n    }\n\n    void quickPolishAlt(double deadline) {\n        if (altC < 0) return;\n        if (elapsed() >= deadline) return;\n\n        grid = altGrid;\n        prepareBias(false);\n\n        recomputeMatchCount();\n        buildHistBest();\n        updateGlobal();\n\n        buildScoreTbl(220000);\n        for (int i = 0; i < 2 && elapsed() < deadline; i++) {\n            int ch = phase2Sweep(deadline);\n            updateGlobal();\n            if (ch == 0) break;\n        }\n\n        if (elapsed() < deadline) {\n            buildFullCnt();\n            updateGlobalByCOnly();\n            for (int i = 0; i < 2 && elapsed() < deadline; i++) {\n                int ch = exactSweep(deadline);\n                updateGlobalByCOnly();\n                if (ch == 0) break;\n            }\n        }\n\n        if (elapsed() < deadline) {\n            buildHistBest();\n            updateGlobal();\n        }\n    }\n\n    void quickPolishCross(double deadline) {\n        if (altC < 0) return;\n        if (elapsed() >= deadline) return;\n        if (hammingDist(bestGrid, altGrid) < 24) return;\n\n        // Build crossover grid\n        for (int i = 0; i < CELL; i++) {\n            uint8_t a = bestGrid[i], b = altGrid[i];\n            if (a == b) grid[i] = a;\n            else {\n                int r = randInt(0, 99);\n                if (r < 47) grid[i] = a;\n                else if (r < 94) grid[i] = b;\n                else grid[i] = (uint8_t)randInt(0, 7);\n            }\n        }\n\n        int mut = randInt(6, 18);\n        for (int i = 0; i < mut; i++) {\n            int cell = randInt(0, CELL - 1);\n            grid[cell] = (uint8_t)randInt(0, 7);\n        }\n\n        bool lb = (randInt(0, 99) < 35);\n        prepareBias(lb);\n\n        recomputeMatchCount();\n        if (elapsed() >= deadline) return;\n\n        (void)phase1Sweep(deadline);\n        if (elapsed() >= deadline) return;\n\n        buildHistBest();\n        updateGlobal();\n\n        buildScoreTbl(lb ? 9000 : 12000);\n        for (int it = 0; it < 2 && elapsed() < deadline; it++) {\n            int ch = phase2Sweep(deadline);\n            updateGlobal();\n            if (ch == 0) break;\n        }\n\n        if (elapsed() < deadline) {\n            buildFullCnt();\n            updateGlobalByCOnly();\n            for (int it = 0; it < 2 && elapsed() < deadline; it++) {\n                int ch = exactSweep(deadline);\n                updateGlobalByCOnly();\n                if (ch == 0) break;\n            }\n        }\n\n        if (elapsed() < deadline) {\n            buildHistBest();\n            updateGlobal();\n        }\n    }\n\n    void dotPostprocessIfPossible() {\n        if (bestC != M) return;\n        if (elapsed() > TL - 0.03) return;\n\n        grid = bestGrid;\n        recomputeMatchCount();\n        buildHistBest();\n        if (calcC() != M) return;\n\n        shuffle(order.begin(), order.end(), rng);\n\n        for (int qi = 0; qi < CELL; qi++) {\n            if ((qi & 15) == 0 && elapsed() > TL - 0.005) break;\n\n            int cell = order[qi];\n            int old = grid[cell];\n            if (old > 7) continue;\n\n            const auto &vec = cellEntries[cell];\n            int pos = 0;\n            bool touched = false;\n\n            // old -> '.'\n            for (int sid = 0; sid < M; sid++) {\n                int gsz = groupLen[sid];\n                for (int t = 0; t < gsz; t++) {\n                    uint32_t x = vec[pos + t];\n                    int req = (int)(x & 7u);\n                    if (req == old) {\n                        int pid = (int)(x >> 3);\n                        int mc = matchCount[pid];\n                        matchCount[pid] = (int16_t)(mc - 1);\n                        hist[sid][mc]--;\n                        hist[sid][mc - 1]++;\n                        touched = true;\n                    }\n                }\n                pos += gsz;\n\n                int b = best[sid];\n                int k = len[sid];\n                if (b < k && hist[sid][b + 1] > 0) b++;\n                else if (b > 0 && hist[sid][b] == 0) b--;\n                best[sid] = (uint8_t)b;\n            }\n\n            if (!touched) {\n                grid[cell] = 8;\n                continue;\n            }\n\n            if (calcC() == M) {\n                grid[cell] = 8;\n            } else {\n                // revert\n                pos = 0;\n                for (int sid = 0; sid < M; sid++) {\n                    int gsz = groupLen[sid];\n                    for (int t = 0; t < gsz; t++) {\n                        uint32_t x = vec[pos + t];\n                        int req = (int)(x & 7u);\n                        if (req == old) {\n                            int pid = (int)(x >> 3);\n                            int mc = matchCount[pid];\n                            matchCount[pid] = (int16_t)(mc + 1);\n                            hist[sid][mc]--;\n                            hist[sid][mc + 1]++;\n                        }\n                    }\n                    pos += gsz;\n\n                    int b = best[sid];\n                    int k = len[sid];\n                    if (b < k && hist[sid][b + 1] > 0) b++;\n                    else if (b > 0 && hist[sid][b] == 0) b--;\n                    best[sid] = (uint8_t)b;\n                }\n            }\n        }\n\n        bestGrid = grid;\n        bestSoft = calcSoft();\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        int restart = 0;\n        while (true) {\n            double now = elapsed();\n            double rem = TL - now;\n            if (rem < 0.12) break;\n\n            double budget;\n            if (restart == 0) budget = min(1.02, rem - 0.03);\n            else if (restart < 4) budget = min(0.50, rem - 0.03);\n            else budget = min(0.30, rem - 0.02);\n\n            if (budget < 0.08) break;\n\n            bool fromBest = false;\n            bool lenBias = false;\n\n            if (restart == 0) {\n                fromBest = false;\n                lenBias = true;\n            } else if (restart == 1) {\n                fromBest = false;\n                lenBias = false;\n            } else {\n                // periodic forced random restart\n                if (bestC >= 0 && restart % 6 != 0) {\n                    int p = (bestC < (int)(0.55 * M)) ? 62 : 78;\n                    fromBest = (randInt(0, 99) < p);\n                } else {\n                    fromBest = false;\n                }\n\n                int q;\n                if (bestC < 0) q = 50;\n                else if (bestC < (int)(0.50 * M)) q = 58;\n                else if (bestC < (int)(0.70 * M)) q = 45;\n                else q = 30;\n\n                lenBias = (randInt(0, 99) < q);\n                if (restart % 4 == 0) lenBias = false;\n            }\n\n            runOne(now + budget, fromBest, lenBias);\n            restart++;\n        }\n\n        if (bestC < 0) {\n            initRandom();\n            bestGrid = grid;\n            bestC = 0;\n            bestSoft = 0;\n        }\n\n        // quick alternate-basin polish\n        if (altC >= 0 && elapsed() < TL - 0.13) {\n            int gap = bestC - altC;\n            bool tryAlt = false;\n            if (altC > bestC) tryAlt = true;\n            else if (gap <= 2) tryAlt = true;\n            else if (gap <= 5 && randInt(0, 99) < 45) tryAlt = true;\n            else if (randInt(0, 99) < 12) tryAlt = true;\n\n            if (tryAlt) {\n                double dline = min(TL - 0.09, elapsed() + 0.045);\n                if (dline > elapsed() + 0.02) quickPolishAlt(dline);\n            }\n        }\n\n        // quick crossover polish between best and alt\n        if (altC >= 0 && elapsed() < TL - 0.11 && randInt(0, 99) < 55) {\n            double dline = min(TL - 0.075, elapsed() + 0.035);\n            if (dline > elapsed() + 0.015) quickPolishCross(dline);\n        }\n\n        // Final polish from best\n        if (elapsed() < TL - 0.03) {\n            grid = bestGrid;\n\n            prepareBias(false);\n            recomputeMatchCount();\n            buildHistBest();\n            updateGlobal();\n\n            // brief length-bias shake if still weak\n            if (elapsed() < TL - 0.09 && bestC < (int)(0.72 * M)) {\n                prepareBias(true);\n                buildScoreTbl(6000);\n                for (int it = 0; it < 2 && elapsed() < TL - 0.06; it++) {\n                    int ch = phase2Sweep(TL - 0.055);\n                    updateGlobal();\n                    if (ch == 0) break;\n                }\n                prepareBias(false);\n                recomputeMatchCount();\n                buildHistBest();\n                updateGlobal();\n            }\n\n            buildScoreTbl(280000);\n            bool kicked = false;\n            while (elapsed() < TL - 0.015) {\n                int ch = phase2Sweep(TL - 0.010);\n                updateGlobal();\n                if (ch == 0) {\n                    if (!kicked && elapsed() < TL - 0.05) {\n                        kicked = true;\n                        int mut = randInt(8, 24);\n                        for (int i = 0; i < mut; i++) {\n                            int cell = randInt(0, CELL - 1);\n                            grid[cell] = (uint8_t)randInt(0, 7);\n                        }\n                        recomputeMatchCount();\n                        buildHistBest();\n                        updateGlobal();\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (elapsed() < TL - 0.006) {\n                buildFullCnt();\n                updateGlobalByCOnly();\n                while (elapsed() < TL - 0.0032) {\n                    int ch = exactSweep(TL - 0.0028);\n                    updateGlobalByCOnly();\n                    if (ch == 0) break;\n                }\n            }\n\n            if (elapsed() < TL - 0.002) {\n                buildHistBest();\n                updateGlobal();\n            }\n        }\n\n        dotPostprocessIfPossible();\n    }\n\n    void output() const {\n        for (int r = 0; r < N; r++) {\n            string line(N, '.');\n            for (int c = 0; c < N; c++) {\n                int v = bestGrid[r * N + c];\n                line[c] = (0 <= v && v < 8) ? char('A' + v) : '.';\n            }\n            cout << line << '\\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<string> S(M);\n    for (int i = 0; i < M; i++) cin >> S[i];\n\n    Solver solver(N, M, S);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double next_double() { // [0,1)\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct Solver {\n    using ull = unsigned long long;\n    static constexpr int INF = 1e9;\n\n    inline static constexpr int DI[4] = {-1, 1, 0, 0};\n    inline static constexpr int DJ[4] = {0, 0, -1, 1};\n    inline static constexpr char MV[4] = {'U', 'D', 'L', 'R'};\n    inline static constexpr int OPP[4] = {1, 0, 3, 2};\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0;\n    int startRid = -1;\n\n    vector<vector<int>> id;\n    vector<int> ri, rj;\n    vector<int> enterCost;\n    vector<array<int,4>> nbr;\n\n    int B = 0;\n    vector<ull> allBits;\n    int allNonZeroBlocks = 0;\n    vector<ull> workBits; // reused for route-coverage checks\n\n    vector<vector<ull>> roadVisBits;\n    vector<int> roadVisCnt;\n\n    vector<int> candRid;              // candidate idx -> road id\n    vector<vector<ull>> candBits;     // visibility bitset\n    vector<vector<int>> candVisList;  // visibility list\n    vector<char> inCand;\n\n    vector<vector<int>> distC;        // directed shortest among candidates\n    vector<vector<int>> prevFrom;     // source candidate idx -> prev road-id tree\n\n    // route-aware edge visibility cache\n    vector<int> edgeCacheId;            // key = a*C+b\n    vector<vector<ull>> edgeCacheBits;  // cached visibility for shortest path edge a->b\n\n    chrono::steady_clock::time_point t0;\n    long long elapsed_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - t0\n        ).count();\n    }\n\n    void read_input() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void build_graph() {\n        id.assign(N, vector<int>(N, -1));\n        ri.clear();\n        rj.clear();\n        enterCost.clear();\n\n        R = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    ri.push_back(i);\n                    rj.push_back(j);\n                    enterCost.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n        startRid = id[si][sj];\n\n        nbr.assign(R, array<int,4>{-1, -1, -1, -1});\n        for (int u = 0; u < R; u++) {\n            int i = ri[u], j = rj[u];\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                    nbr[u][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void init_bits() {\n        B = (R + 63) >> 6;\n        allBits.assign(B, ~0ULL);\n        if (B > 0 && (R & 63)) allBits.back() = (1ULL << (R & 63)) - 1ULL;\n\n        allNonZeroBlocks = 0;\n        for (ull x : allBits) if (x) allNonZeroBlocks++;\n        workBits.resize(B);\n    }\n\n    void build_road_visibility() {\n        roadVisBits.assign(R, vector<ull>(B, 0ULL));\n        roadVisCnt.assign(R, 0);\n\n        for (int rid = 0; rid < R; rid++) {\n            auto &bits = roadVisBits[rid];\n            auto add = [&](int v) { bits[v >> 6] |= (1ULL << (v & 63)); };\n\n            int i = ri[rid], j = rj[rid];\n            add(rid);\n\n            for (int y = j - 1; y >= 0; y--) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int y = j + 1; y < N; y++) {\n                int v = id[i][y];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i - 1; x >= 0; x--) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n            for (int x = i + 1; x < N; x++) {\n                int v = id[x][j];\n                if (v == -1) break;\n                add(v);\n            }\n\n            int cnt = 0;\n            for (int b = 0; b < B; b++) cnt += __builtin_popcountll(bits[b]);\n            roadVisCnt[rid] = cnt;\n        }\n    }\n\n    vector<int> bits_to_list(const vector<ull>& bits) const {\n        vector<int> res;\n        for (int b = 0; b < B; b++) {\n            ull x = bits[b];\n            while (x) {\n                int t = __builtin_ctzll(x);\n                int v = (b << 6) + t;\n                if (v < R) res.push_back(v);\n                x &= (x - 1);\n            }\n        }\n        return res;\n    }\n\n    bool is_straight_2deg(int rid) const {\n        int deg = 0;\n        for (int d = 0; d < 4; d++) if (nbr[rid][d] != -1) deg++;\n        if (deg != 2) return false;\n        bool U = (nbr[rid][0] != -1);\n        bool D = (nbr[rid][1] != -1);\n        bool L = (nbr[rid][2] != -1);\n        bool Rr = (nbr[rid][3] != -1);\n        return (U && D) || (L && Rr);\n    }\n\n    void add_candidate(int rid) {\n        if (inCand[rid]) return;\n        inCand[rid] = 1;\n        candRid.push_back(rid);\n        candBits.push_back(roadVisBits[rid]);\n        candVisList.push_back(bits_to_list(roadVisBits[rid]));\n    }\n\n    void add_extra_candidates() {\n        int C0 = (int)candRid.size();\n        int addLimit = 0;\n        if (C0 < 220) addLimit = 24;\n        else if (C0 < 320) addLimit = 12;\n        else if (C0 < 400) addLimit = 6;\n        else addLimit = 0;\n\n        int maxC = 430;\n        addLimit = min(addLimit, max(0, maxC - C0));\n        if (addLimit <= 0) return;\n\n        vector<int> pool;\n        pool.reserve(R);\n        for (int rid = 0; rid < R; rid++) if (!inCand[rid]) pool.push_back(rid);\n\n        sort(pool.begin(), pool.end(), [&](int a, int b) {\n            if (roadVisCnt[a] != roadVisCnt[b]) return roadVisCnt[a] > roadVisCnt[b];\n            return enterCost[a] < enterCost[b];\n        });\n\n        int added = 0;\n        for (int pass = 0; pass < 2 && added < addLimit; pass++) {\n            for (int rid : pool) {\n                if (added >= addLimit) break;\n                if (inCand[rid]) continue;\n                if (pass == 0 && !is_straight_2deg(rid)) continue;\n                add_candidate(rid);\n                added++;\n            }\n        }\n    }\n\n    void build_candidates() {\n        candRid.clear();\n        candBits.clear();\n        candVisList.clear();\n        inCand.assign(R, 0);\n\n        add_candidate(startRid); // candidate 0 = start\n\n        for (int u = 0; u < R; u++) {\n            if (u == startRid) continue;\n\n            int deg = 0;\n            for (int d = 0; d < 4; d++) if (nbr[u][d] != -1) deg++;\n\n            bool isCand = false;\n            if (deg != 2) isCand = true;\n            else isCand = !is_straight_2deg(u);\n\n            if (isCand) add_candidate(u);\n        }\n\n        // safety completion\n        vector<ull> uni(B, 0ULL);\n        for (int c = 0; c < (int)candRid.size(); c++) {\n            for (int b = 0; b < B; b++) uni[b] |= candBits[c][b];\n        }\n        for (int b = 0; b < B; b++) {\n            ull miss = allBits[b] & (~uni[b]);\n            while (miss) {\n                int t = __builtin_ctzll(miss);\n                int rid = (b << 6) + t;\n                if (rid < R) add_candidate(rid);\n                miss &= (miss - 1);\n            }\n        }\n\n        add_extra_candidates();\n    }\n\n    void dijkstra_candidate(int sIdx, vector<int>& dist, vector<int>& prev) {\n        int src = candRid[sIdx];\n\n        dist.assign(R, INF);\n        prev.assign(R, -1);\n        vector<int> score(R, -1);\n\n        using State = tuple<int, int, int>; // dist, -score, node\n        priority_queue<State, vector<State>, greater<State>> pq;\n\n        dist[src] = 0;\n        score[src] = roadVisCnt[src];\n        prev[src] = src;\n        pq.push({0, -score[src], src});\n\n        while (!pq.empty()) {\n            auto [du, negSc, u] = pq.top();\n            pq.pop();\n            int su = -negSc;\n            if (du != dist[u] || su != score[u]) continue;\n\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1) continue;\n\n                int nd = du + enterCost[v];\n                int ns = su + roadVisCnt[v];\n\n                if (nd < dist[v] ||\n                    (nd == dist[v] && (ns > score[v] ||\n                     (ns == score[v] && (prev[v] == -1 || u < prev[v]))))) {\n                    dist[v] = nd;\n                    score[v] = ns;\n                    prev[v] = u;\n                    pq.push({nd, -ns, v});\n                }\n            }\n        }\n    }\n\n    void precompute_shortest_paths() {\n        int C = (int)candRid.size();\n\n        distC.assign(C, vector<int>(C, INF));\n        prevFrom.assign(C, vector<int>(R, -1));\n\n        vector<int> dist, prev;\n        for (int s = 0; s < C; s++) {\n            dijkstra_candidate(s, dist, prev);\n            prevFrom[s].swap(prev);\n            for (int t = 0; t < C; t++) distC[s][t] = dist[candRid[t]];\n        }\n\n        edgeCacheId.assign(C * C, -1);\n        edgeCacheBits.clear();\n        edgeCacheBits.reserve((size_t)min<long long>(1LL * C * C, 60000LL));\n    }\n\n    inline int edge_cost(int a, int b) const { return distC[a][b]; }\n\n    bool bits_empty(const vector<ull>& bits) const {\n        for (ull x : bits) if (x) return false;\n        return true;\n    }\n\n    int gain_of_candidate(int c, const vector<ull>& unc) const {\n        int g = 0;\n        for (int b = 0; b < B; b++) g += __builtin_popcountll(candBits[c][b] & unc[b]);\n        return g;\n    }\n\n    bool candidate_cover_full(const vector<int>& seq) const {\n        vector<ull> cov(B, 0ULL);\n        for (int c : seq) for (int b = 0; b < B; b++) cov[b] |= candBits[c][b];\n        for (int b = 0; b < B; b++) if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        return true;\n    }\n\n    struct Choice {\n        double score;\n        int cidx;\n        int pos;\n        int gain;\n        int inc;\n    };\n\n    void repair_cover(\n        vector<int>& seq,\n        vector<char>& used,\n        vector<ull>& unc,\n        double alpha,\n        double beta,\n        int topk,\n        double noise,\n        XorShift64& rng\n    ) {\n        int C = (int)candRid.size();\n\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            vector<Choice> top;\n            top.reserve(topk + 2);\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n\n                int gain = gain_of_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int bestInc = INF, bestPos = 0;\n                if (m == 1) {\n                    bestInc = edge_cost(seq[0], c) + edge_cost(c, seq[0]);\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < bestInc) {\n                            bestInc = inc;\n                            bestPos = p;\n                        }\n                    }\n                }\n                if (bestInc >= INF / 4) continue;\n\n                double num = (alpha == 1.0 ? (double)gain :\n                              (alpha == 2.0 ? (double)gain * gain : pow((double)gain, alpha)));\n                double den = (beta == 1.0 ? (double)(bestInc + 1) : pow((double)(bestInc + 1), beta));\n                double sc = num / den;\n                if (noise > 0.0) {\n                    double z = rng.next_double() * 2.0 - 1.0;\n                    sc *= (1.0 + noise * z);\n                }\n\n                Choice ch{sc, c, bestPos, gain, bestInc};\n\n                if ((int)top.size() < topk) {\n                    top.push_back(ch);\n                    int z = (int)top.size() - 1;\n                    while (z > 0 && top[z].score > top[z - 1].score) {\n                        swap(top[z], top[z - 1]);\n                        --z;\n                    }\n                } else if (ch.score > top.back().score) {\n                    top.back() = ch;\n                    int z = (int)top.size() - 1;\n                    while (z > 0 && top[z].score > top[z - 1].score) {\n                        swap(top[z], top[z - 1]);\n                        --z;\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            int pick = 0;\n            if ((int)top.size() > 1) {\n                int sz = (int)top.size();\n                int total = sz * (sz + 1) / 2;\n                int r = rng.next_int(1, total);\n                for (int i = 0; i < sz; i++) {\n                    int w = sz - i;\n                    r -= w;\n                    if (r <= 0) {\n                        pick = i;\n                        break;\n                    }\n                }\n            }\n\n            auto ch = top[pick];\n            seq.insert(seq.begin() + ch.pos + 1, ch.cidx);\n            used[ch.cidx] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[ch.cidx][b];\n        }\n\n        while (!bits_empty(unc)) {\n            int m = (int)seq.size();\n            int bestC = -1, bestPos = 0;\n            int bestGain = -1, bestInc = INF;\n\n            for (int c = 0; c < C; c++) {\n                if (used[c]) continue;\n                int gain = gain_of_candidate(c, unc);\n                if (gain <= 0) continue;\n\n                int incMin = INF, pos = 0;\n                if (m == 1) {\n                    incMin = edge_cost(seq[0], c) + edge_cost(c, seq[0]);\n                } else {\n                    for (int p = 0; p < m; p++) {\n                        int u = seq[p], v = seq[(p + 1) % m];\n                        int inc = edge_cost(u, c) + edge_cost(c, v) - edge_cost(u, v);\n                        if (inc < incMin) {\n                            incMin = inc;\n                            pos = p;\n                        }\n                    }\n                }\n\n                if (gain > bestGain || (gain == bestGain && incMin < bestInc)) {\n                    bestGain = gain;\n                    bestInc = incMin;\n                    bestC = c;\n                    bestPos = pos;\n                }\n            }\n\n            if (bestC == -1) break;\n            seq.insert(seq.begin() + bestPos + 1, bestC);\n            used[bestC] = 1;\n            for (int b = 0; b < B; b++) unc[b] &= ~candBits[bestC][b];\n        }\n    }\n\n    vector<int> build_cover(double alpha, double beta, int topk, double noise, XorShift64& rng) {\n        int C = (int)candRid.size();\n\n        vector<int> seq = {0};\n        vector<char> used(C, 0);\n        used[0] = 1;\n\n        vector<ull> unc = allBits;\n        for (int b = 0; b < B; b++) unc[b] &= ~candBits[0][b];\n\n        repair_cover(seq, used, unc, alpha, beta, topk, noise, rng);\n        return seq;\n    }\n\n    long long cycle_cost(const vector<int>& seq) const {\n        int m = (int)seq.size();\n        if (m <= 1) return 0;\n        long long c = 0;\n        for (int i = 0; i < m; i++) c += edge_cost(seq[i], seq[(i + 1) % m]);\n        return c;\n    }\n\n    void prune_waypoint_cost(vector<int>& seq) {\n        if (seq.size() <= 1) return;\n\n        vector<int> cnt(R, 0);\n        for (int x : seq) for (int rid : candVisList[x]) cnt[rid]++;\n\n        while (true) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestPos = -1;\n            long long bestSave = LLONG_MIN;\n\n            for (int p = 1; p < m; p++) {\n                int x = seq[p];\n\n                bool removable = true;\n                for (int rid : candVisList[x]) {\n                    if (cnt[rid] <= 1) {\n                        removable = false;\n                        break;\n                    }\n                }\n                if (!removable) continue;\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n                long long save =\n                    (long long)edge_cost(pr, x) + edge_cost(x, nx) - edge_cost(pr, nx);\n\n                if (save > bestSave) {\n                    bestSave = save;\n                    bestPos = p;\n                }\n            }\n\n            if (bestPos == -1 || bestSave < 0) break;\n\n            int x = seq[bestPos];\n            for (int rid : candVisList[x]) cnt[rid]--;\n            seq.erase(seq.begin() + bestPos);\n        }\n    }\n\n    bool improve_relocate1(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n\n            int x = seq[i];\n            int p = seq[(i - 1 + m) % m];\n            int n = seq[(i + 1) % m];\n\n            long long rem = -(long long)edge_cost(p, x) - edge_cost(x, n) + edge_cost(p, n);\n\n            for (int j = 0; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n                if (j == i) continue;\n                if (j == (i - 1 + m) % m) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n                long long delta =\n                    rem - (long long)edge_cost(a, b) + edge_cost(a, x) + edge_cost(x, b);\n\n                if (delta < 0) {\n                    int node = seq[i];\n                    seq.erase(seq.begin() + i);\n                    int jj = j;\n                    if (jj > i) jj--;\n                    seq.insert(seq.begin() + jj + 1, node);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool improve_swap(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 2) return false;\n\n        for (int i = 1; i < m; i++) {\n            if (elapsed_ms() > endMs) return false;\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n\n                long long delta = 0;\n                if (i + 1 == j) {\n                    int p = seq[i - 1], a = seq[i], b = seq[j], n = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(p, a) + edge_cost(a, b) + edge_cost(b, n);\n                    long long newc = (long long)edge_cost(p, b) + edge_cost(b, a) + edge_cost(a, n);\n                    delta = newc - oldc;\n                } else {\n                    int pi = seq[i - 1], a = seq[i], ni = seq[(i + 1) % m];\n                    int pj = seq[j - 1], b = seq[j], nj = seq[(j + 1) % m];\n                    long long oldc = (long long)edge_cost(pi, a) + edge_cost(a, ni)\n                                   + (long long)edge_cost(pj, b) + edge_cost(b, nj);\n                    long long newc = (long long)edge_cost(pi, b) + edge_cost(b, ni)\n                                   + (long long)edge_cost(pj, a) + edge_cost(a, nj);\n                    delta = newc - oldc;\n                }\n\n                if (delta < 0) {\n                    swap(seq[i], seq[j]);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool improve_2opt_directed(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 4) return false;\n\n        vector<long long> pf(m, 0), pr(m, 0);\n        for (int k = 0; k < m - 1; k++) {\n            pf[k + 1] = pf[k] + edge_cost(seq[k], seq[k + 1]);\n            pr[k + 1] = pr[k] + edge_cost(seq[k + 1], seq[k]);\n        }\n\n        for (int i = 1; i < m - 1; i++) {\n            if (elapsed_ms() > endMs) return false;\n\n            int a = seq[i - 1];\n            int b = seq[i];\n\n            for (int j = i + 1; j < m; j++) {\n                if ((j & 31) == 0 && elapsed_ms() > endMs) return false;\n\n                int c = seq[j];\n                int d = seq[(j + 1) % m];\n\n                long long forwardInternal = pf[j] - pf[i];\n                long long reverseInternal = pr[j] - pr[i];\n                long long oldBound = (long long)edge_cost(a, b) + edge_cost(c, d);\n                long long newBound = (long long)edge_cost(a, c) + edge_cost(b, d);\n\n                long long delta = newBound + reverseInternal - oldBound - forwardInternal;\n\n                if (delta < 0) {\n                    reverse(seq.begin() + i, seq.begin() + j + 1);\n                    curCost += delta;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    void local_search(vector<int>& seq, long long& curCost, long long endMs) {\n        if (seq.size() <= 2) return;\n\n        int it = 0;\n        while (elapsed_ms() < endMs) {\n            bool imp = false;\n            int ph = it % 3;\n\n            if (ph == 0) {\n                if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_2opt_directed(seq, curCost, endMs)) imp = true;\n                else if (improve_swap(seq, curCost, endMs)) imp = true;\n            } else if (ph == 1) {\n                if (improve_2opt_directed(seq, curCost, endMs)) imp = true;\n                else if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_swap(seq, curCost, endMs)) imp = true;\n            } else {\n                if (improve_swap(seq, curCost, endMs)) imp = true;\n                else if (improve_relocate1(seq, curCost, endMs)) imp = true;\n                else if (improve_2opt_directed(seq, curCost, endMs)) imp = true;\n            }\n\n            if (!imp) break;\n            if ((it & 31) == 31) curCost = cycle_cost(seq);\n            if (++it > 260000) break;\n        }\n        curCost = cycle_cost(seq);\n    }\n\n    bool replace_candidatewise(vector<int>& seq, long long& curCost, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 1) return false;\n        int C = (int)candRid.size();\n\n        vector<int> cnt(R, 0);\n        vector<int> usedCnt(C, 0);\n        for (int x : seq) {\n            usedCnt[x]++;\n            for (int rid : candVisList[x]) cnt[rid]++;\n        }\n\n        vector<ull> uniq(B, 0ULL);\n        bool improvedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            bool improved = false;\n\n            for (int p = 1; p < m; p++) {\n                if ((p & 7) == 0 && elapsed_ms() > endMs) break;\n\n                int old = seq[p];\n\n                fill(uniq.begin(), uniq.end(), 0ULL);\n                for (int rid : candVisList[old]) {\n                    if (cnt[rid] == 1) uniq[rid >> 6] |= (1ULL << (rid & 63));\n                }\n\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n\n                long long bestDelta = 0;\n                int bestQ = -1;\n\n                for (int q = 0; q < C; q++) {\n                    if (usedCnt[q] > 0) continue;\n\n                    bool ok = true;\n                    for (int b = 0; b < B; b++) {\n                        if (uniq[b] & ~candBits[q][b]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) continue;\n\n                    int c1 = edge_cost(pr, q), c2 = edge_cost(q, nx);\n                    if (c1 >= INF / 4 || c2 >= INF / 4) continue;\n\n                    long long delta =\n                        -(long long)edge_cost(pr, old) - edge_cost(old, nx) + c1 + c2;\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestQ = q;\n                    }\n                }\n\n                if (bestQ != -1) {\n                    usedCnt[old]--;\n                    usedCnt[bestQ]++;\n                    for (int rid : candVisList[old]) cnt[rid]--;\n                    for (int rid : candVisList[bestQ]) cnt[rid]++;\n                    seq[p] = bestQ;\n                    curCost += bestDelta;\n                    improved = true;\n                    improvedAny = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        curCost = cycle_cost(seq);\n        return improvedAny;\n    }\n\n    vector<int> ruin_recreate(const vector<int>& base, XorShift64& rng) {\n        vector<int> seq = base;\n        int m = (int)seq.size();\n\n        if (m > 1) {\n            double ratio = 0.12 + 0.30 * rng.next_double();\n            int k = max(1, (int)((m - 1) * ratio));\n            k = min(k, m - 1);\n\n            vector<int> rem;\n            bool informed = (rng.next_double() < 0.70 && m >= 8);\n\n            if (informed) {\n                vector<int> cnt(R, 0);\n                for (int x : seq) for (int rid : candVisList[x]) cnt[rid]++;\n\n                struct Info { double key; int pos; };\n                vector<Info> info;\n                info.reserve(m - 1);\n\n                for (int p = 1; p < m; p++) {\n                    int x = seq[p];\n\n                    int uniq = 0;\n                    for (int rid : candVisList[x]) if (cnt[rid] == 1) uniq++;\n\n                    int pr = seq[(p - 1 + m) % m];\n                    int nx = seq[(p + 1) % m];\n                    long long save = (long long)edge_cost(pr, x) + edge_cost(x, nx) - edge_cost(pr, nx);\n\n                    double key = uniq * 900.0\n                               - 3.5 * max(0LL, save)\n                               + 1.2 * max(0LL, -save)\n                               + 10.0 * rng.next_double();\n\n                    info.push_back({key, p});\n                }\n\n                sort(info.begin(), info.end(), [](const Info& a, const Info& b) {\n                    return a.key < b.key;\n                });\n\n                vector<char> picked(m, 0);\n                int det = min((int)info.size(), max(1, (int)(k * 0.7)));\n\n                for (int i = 0; i < det; i++) {\n                    rem.push_back(info[i].pos);\n                    picked[info[i].pos] = 1;\n                }\n\n                vector<int> rest;\n                for (int i = det; i < (int)info.size(); i++) {\n                    if (!picked[info[i].pos]) rest.push_back(info[i].pos);\n                }\n\n                while ((int)rem.size() < k && !rest.empty()) {\n                    int idx = rng.next_int(0, (int)rest.size() - 1);\n                    rem.push_back(rest[idx]);\n                    rest[idx] = rest.back();\n                    rest.pop_back();\n                }\n            } else {\n                vector<int> pos(m - 1);\n                for (int i = 0; i < m - 1; i++) pos[i] = i + 1;\n                for (int i = (int)pos.size() - 1; i > 0; i--) {\n                    int j = rng.next_int(0, i);\n                    swap(pos[i], pos[j]);\n                }\n                pos.resize(k);\n                rem.swap(pos);\n            }\n\n            sort(rem.begin(), rem.end());\n            rem.erase(unique(rem.begin(), rem.end()), rem.end());\n            sort(rem.rbegin(), rem.rend());\n            for (int p : rem) seq.erase(seq.begin() + p);\n        }\n\n        int C = (int)candRid.size();\n        vector<char> used(C, 0);\n        for (int x : seq) used[x] = 1;\n\n        vector<ull> unc = allBits;\n        for (int x : seq) for (int b = 0; b < B; b++) unc[b] &= ~candBits[x][b];\n\n        static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.3};\n        static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n        static const int KS[] = {1, 2, 3, 4, 6};\n\n        double alpha = AS[rng.next_int(0, 5)];\n        double beta  = BS[rng.next_int(0, 3)];\n        int topk     = KS[rng.next_int(0, 4)];\n        double noise = 0.12;\n\n        repair_cover(seq, used, unc, alpha, beta, topk, noise, rng);\n        return seq;\n    }\n\n    const vector<ull>& get_edge_bits(int a, int b) {\n        int C = (int)candRid.size();\n        int key = a * C + b;\n        int cid = edgeCacheId[key];\n        if (cid != -1) return edgeCacheBits[cid];\n\n        vector<ull> bits(B, 0ULL);\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int bb = 0; bb < B; bb++) bits[bb] |= vb[bb];\n        };\n\n        int src = candRid[a];\n        int dst = candRid[b];\n\n        addRid(src);\n        int cur = dst;\n        while (cur != src) {\n            addRid(cur);\n            int p = prevFrom[a][cur];\n            if (p < 0) break;\n            cur = p;\n        }\n\n        edgeCacheId[key] = (int)edgeCacheBits.size();\n        edgeCacheBits.push_back(move(bits));\n        return edgeCacheBits.back();\n    }\n\n    // Fast route-coverage check of seq after removing up to 2 positions.\n    bool coverage_full_skip(const vector<int>& seq, int rm1 = -1, int rm2 = -1) {\n        int m = (int)seq.size();\n        int remain = m - (rm1 >= 0) - ((rm2 >= 0 && rm2 != rm1) ? 1 : 0);\n        if (remain <= 0) return false;\n\n        copy(allBits.begin(), allBits.end(), workBits.begin());\n        int nonZero = allNonZeroBlocks;\n\n        auto consume_edge = [&](int a, int b) {\n            const auto &eb = get_edge_bits(a, b);\n            for (int k = 0; k < B; k++) {\n                ull before = workBits[k];\n                ull after = before & ~eb[k];\n                if (before && after == 0) nonZero--;\n                workBits[k] = after;\n            }\n        };\n\n        int first = -1, prev = -1;\n        for (int i = 0; i < m; i++) {\n            if (i == rm1 || i == rm2) continue;\n            int c = seq[i];\n            if (first == -1) {\n                first = c;\n                prev = c;\n            } else {\n                consume_edge(prev, c);\n                if (nonZero == 0) return true;\n                prev = c;\n            }\n        }\n\n        consume_edge(prev, first);\n        return nonZero == 0;\n    }\n\n    bool coverage_full_sequence(const vector<int>& seq) {\n        return coverage_full_skip(seq, -1, -1);\n    }\n\n    bool route_aware_prune_combo(vector<int>& seq, long long endMs) {\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            vector<pair<long long, int>> cand; // save, pos\n            cand.reserve(max(0, m - 1));\n\n            for (int p = 1; p < m; p++) {\n                int pr = seq[(p - 1 + m) % m];\n                int cur = seq[p];\n                int nx = seq[(p + 1) % m];\n                long long save =\n                    (long long)edge_cost(pr, cur) + edge_cost(cur, nx) - edge_cost(pr, nx);\n                if (save >= 0) cand.push_back({save, p});\n            }\n            if (cand.empty()) break;\n\n            sort(cand.begin(), cand.end(), [](auto &a, auto &b) { return a.first > b.first; });\n\n            bool changedRound = false;\n\n            int K = min((m > 180 ? 12 : 20), (int)cand.size());\n            for (int i = 0; i < K; i++) {\n                if (elapsed_ms() > endMs) break;\n                int p = cand[i].second;\n                if (coverage_full_skip(seq, p, -1)) {\n                    seq.erase(seq.begin() + p);\n                    changedRound = true;\n                    changedAny = true;\n                    break;\n                }\n            }\n            if (changedRound) continue;\n\n            int M = min((m > 180 ? 8 : 12), (int)cand.size());\n            long long baseCost = cycle_cost(seq);\n            long long bestSave = 0;\n            vector<int> bestTmp;\n\n            for (int i = 0; i < M; i++) {\n                if (elapsed_ms() > endMs) break;\n                for (int j = i + 1; j < M; j++) {\n                    if (elapsed_ms() > endMs) break;\n\n                    int p = cand[i].second;\n                    int q = cand[j].second;\n                    if (p == q) continue;\n\n                    if (!coverage_full_skip(seq, p, q)) continue;\n\n                    vector<int> tmp;\n                    tmp.reserve(m - 2);\n                    for (int idx = 0; idx < m; idx++) {\n                        if (idx == p || idx == q) continue;\n                        tmp.push_back(seq[idx]);\n                    }\n                    if (tmp.empty()) continue;\n\n                    long long newCost = cycle_cost(tmp);\n                    long long save = baseCost - newCost;\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestTmp.swap(tmp);\n                    }\n                }\n            }\n\n            if (bestSave > 0 && !bestTmp.empty()) {\n                seq.swap(bestTmp);\n                changedAny = true;\n                changedRound = true;\n            }\n\n            if (!changedRound) break;\n        }\n\n        return changedAny;\n    }\n\n    // Allow replacement even with already-used candidate (duplicates are legal).\n    bool route_aware_replace(vector<int>& seq, long long endMs) {\n        int m = (int)seq.size();\n        if (m <= 1) return false;\n        int C = (int)candRid.size();\n\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            m = (int)seq.size();\n            if (m <= 1) break;\n\n            vector<pair<int, int>> posOrder; // local old cost, pos\n            posOrder.reserve(max(0, m - 1));\n            for (int p = 1; p < m; p++) {\n                int pr = seq[(p - 1 + m) % m];\n                int cur = seq[p];\n                int nx = seq[(p + 1) % m];\n                int oldL = edge_cost(pr, cur) + edge_cost(cur, nx);\n                posOrder.push_back({oldL, p});\n            }\n            sort(posOrder.begin(), posOrder.end(),\n                 [](const auto& a, const auto& b) { return a.first > b.first; });\n\n            int P = min(14, (int)posOrder.size());\n            bool improved = false;\n\n            for (int ii = 0; ii < P && elapsed_ms() < endMs; ii++) {\n                int p = posOrder[ii].second;\n                int old = seq[p];\n                int pr = seq[(p - 1 + m) % m];\n                int nx = seq[(p + 1) % m];\n                int oldL = edge_cost(pr, old) + edge_cost(old, nx);\n\n                struct Cand { int delta; int q; };\n                vector<Cand> top;\n                const int Q = 8;\n\n                auto push_q = [&](int q, int delta) {\n                    int ins = (int)top.size();\n                    while (ins > 0 && top[ins - 1].delta > delta) ins--;\n                    if ((int)top.size() < Q) {\n                        top.insert(top.begin() + ins, Cand{delta, q});\n                    } else if (ins < Q) {\n                        top.insert(top.begin() + ins, Cand{delta, q});\n                        top.pop_back();\n                    }\n                };\n\n                for (int q = 0; q < C; q++) {\n                    if (q == old) continue;\n                    int d1 = edge_cost(pr, q);\n                    if (d1 >= oldL) continue;\n                    int d2 = edge_cost(q, nx);\n                    if (d2 >= oldL) continue;\n                    int delta = d1 + d2 - oldL;\n                    if (delta >= 0) continue;\n                    push_q(q, delta);\n                }\n\n                for (auto &c : top) {\n                    int q = c.q;\n                    seq[p] = q;\n                    if (coverage_full_sequence(seq)) {\n                        improved = true;\n                        changedAny = true;\n                        break;\n                    }\n                    seq[p] = old;\n                }\n                if (improved) break;\n            }\n\n            if (!improved) break;\n        }\n\n        return changedAny;\n    }\n\n    bool route_aware_2opt(vector<int>& seq, long long endMs) {\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 4) break;\n\n            vector<long long> pf(m, 0), pr(m, 0);\n            for (int k = 0; k < m - 1; k++) {\n                pf[k + 1] = pf[k] + edge_cost(seq[k], seq[k + 1]);\n                pr[k + 1] = pr[k] + edge_cost(seq[k + 1], seq[k]);\n            }\n\n            struct Move { long long delta; int i, j; };\n            vector<Move> top;\n            const int KEEP = (m > 180 ? 10 : 16);\n\n            for (int i = 1; i < m - 1; i++) {\n                if (elapsed_ms() > endMs) break;\n                int a = seq[i - 1];\n                int b = seq[i];\n\n                for (int j = i + 1; j < m; j++) {\n                    if ((j & 63) == 0 && elapsed_ms() > endMs) break;\n\n                    int c = seq[j];\n                    int d = seq[(j + 1) % m];\n\n                    long long forwardInternal = pf[j] - pf[i];\n                    long long reverseInternal = pr[j] - pr[i];\n                    long long oldBound = (long long)edge_cost(a, b) + edge_cost(c, d);\n                    long long newBound = (long long)edge_cost(a, c) + edge_cost(b, d);\n                    long long delta = newBound + reverseInternal - oldBound - forwardInternal;\n                    if (delta >= 0) continue;\n\n                    Move mv{delta, i, j};\n                    if ((int)top.size() < KEEP) {\n                        top.push_back(mv);\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    } else if (mv.delta < top.back().delta) {\n                        top.back() = mv;\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            bool improved = false;\n            for (auto &mv : top) {\n                if (elapsed_ms() > endMs) break;\n                reverse(seq.begin() + mv.i, seq.begin() + mv.j + 1);\n                if (coverage_full_sequence(seq)) {\n                    improved = true;\n                    changedAny = true;\n                    break;\n                }\n                reverse(seq.begin() + mv.i, seq.begin() + mv.j + 1);\n            }\n\n            if (!improved) break;\n        }\n\n        return changedAny;\n    }\n\n    bool route_aware_relocate(vector<int>& seq, long long endMs) {\n        if ((int)seq.size() > 170) return false; // avoid heavy on large tours\n\n        bool changedAny = false;\n\n        while (elapsed_ms() < endMs) {\n            int m = (int)seq.size();\n            if (m <= 2) break;\n\n            struct Move { long long delta; int i, j; };\n            vector<Move> top;\n            const int KEEP = 10;\n\n            for (int i = 1; i < m; i++) {\n                if (elapsed_ms() > endMs) break;\n\n                int x = seq[i];\n                int p = seq[(i - 1 + m) % m];\n                int n = seq[(i + 1) % m];\n\n                long long rem = -(long long)edge_cost(p, x) - edge_cost(x, n) + edge_cost(p, n);\n\n                for (int j = 0; j < m; j++) {\n                    if ((j & 63) == 0 && elapsed_ms() > endMs) break;\n                    if (j == i) continue;\n                    if (j == (i - 1 + m) % m) continue;\n\n                    int a = seq[j];\n                    int b = seq[(j + 1) % m];\n                    long long delta = rem - (long long)edge_cost(a, b) + edge_cost(a, x) + edge_cost(x, b);\n                    if (delta >= 0) continue;\n\n                    Move mv{delta, i, j};\n                    if ((int)top.size() < KEEP) {\n                        top.push_back(mv);\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    } else if (mv.delta < top.back().delta) {\n                        top.back() = mv;\n                        int z = (int)top.size() - 1;\n                        while (z > 0 && top[z].delta < top[z - 1].delta) {\n                            swap(top[z], top[z - 1]);\n                            --z;\n                        }\n                    }\n                }\n            }\n\n            if (top.empty()) break;\n\n            bool improved = false;\n            for (auto &mv : top) {\n                if (elapsed_ms() > endMs) break;\n\n                vector<int> tmp = seq;\n                int i = mv.i, j = mv.j;\n                int node = tmp[i];\n                tmp.erase(tmp.begin() + i);\n                int jj = j;\n                if (jj > i) jj--;\n                tmp.insert(tmp.begin() + jj + 1, node);\n\n                if (coverage_full_sequence(tmp)) {\n                    seq.swap(tmp);\n                    improved = true;\n                    changedAny = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return changedAny;\n    }\n\n    char move_char(int u, int v) const {\n        if (ri[v] == ri[u] - 1 && rj[v] == rj[u]) return 'U';\n        if (ri[v] == ri[u] + 1 && rj[v] == rj[u]) return 'D';\n        if (ri[v] == ri[u] && rj[v] == rj[u] - 1) return 'L';\n        if (ri[v] == ri[u] && rj[v] == rj[u] + 1) return 'R';\n        return '?';\n    }\n\n    string build_answer(const vector<int>& seq) const {\n        string ans;\n        int m = (int)seq.size();\n        if (m <= 1) return ans;\n\n        long long c = cycle_cost(seq);\n        ans.reserve((size_t)(max(1LL, c / 6) + 64));\n\n        vector<int> rev;\n        rev.reserve(256);\n\n        for (int i = 0; i < m; i++) {\n            int sCand = seq[i];\n            int tCand = seq[(i + 1) % m];\n            int src = candRid[sCand];\n            int dst = candRid[tCand];\n            if (src == dst) continue;\n\n            rev.clear();\n            int cur = dst;\n            while (cur != src) {\n                rev.push_back(cur);\n                cur = prevFrom[sCand][cur];\n                if (cur < 0) return \"\";\n            }\n\n            int u = src;\n            for (int k = (int)rev.size() - 1; k >= 0; k--) {\n                int v = rev[k];\n                char ch = move_char(u, v);\n                if (ch == '?') return \"\";\n                ans.push_back(ch);\n                u = v;\n            }\n        }\n\n        return ans;\n    }\n\n    int dir_id(char c) const {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        if (c == 'R') return 3;\n        return -1;\n    }\n\n    bool validate_ans(const string& ans) const {\n        if (startRid < 0) return false;\n\n        vector<ull> cov(B, 0ULL);\n        auto addRid = [&](int rid) {\n            const auto &vb = roadVisBits[rid];\n            for (int b = 0; b < B; b++) cov[b] |= vb[b];\n        };\n\n        int cur = startRid;\n        addRid(cur);\n\n        for (char ch : ans) {\n            int d = dir_id(ch);\n            if (d < 0) return false;\n            int nx = nbr[cur][d];\n            if (nx == -1) return false;\n            cur = nx;\n            addRid(cur);\n        }\n\n        if (cur != startRid) return false;\n        for (int b = 0; b < B; b++) {\n            if ((cov[b] & allBits[b]) != allBits[b]) return false;\n        }\n        return true;\n    }\n\n    string fallback_dfs_tour() const {\n        vector<char> vis(R, 0);\n        string out;\n        out.reserve(max(0, 2 * R + 8));\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            for (int d = 0; d < 4; d++) {\n                int v = nbr[u][d];\n                if (v == -1 || vis[v]) continue;\n                out.push_back(MV[d]);\n                dfs(v);\n                out.push_back(MV[OPP[d]]);\n            }\n        };\n\n        dfs(startRid);\n        return out;\n    }\n\n    uint64_t calc_seed() const {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)si);\n        mix((uint64_t)sj);\n        mix((uint64_t)R);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                mix((uint64_t)(unsigned char)grid[i][j]\n                    + ((uint64_t)i << 8)\n                    + ((uint64_t)j << 16));\n            }\n        }\n        return h;\n    }\n\n    string solve() {\n        t0 = chrono::steady_clock::now();\n\n        build_graph();\n        if (R == 0) return \"\";\n\n        init_bits();\n        build_road_visibility();\n        build_candidates();\n        precompute_shortest_paths();\n\n        XorShift64 rng(calc_seed());\n        const long long TL = 2940;\n\n        vector<int> bestSeq = {0};\n        long long bestCost = (1LL << 60);\n\n        auto update_best = [&](const vector<int>& seq, long long c) {\n            if (seq.empty()) return;\n            if (!candidate_cover_full(seq)) return;\n            if (c < bestCost) {\n                bestCost = c;\n                bestSeq = seq;\n            }\n        };\n\n        // baseline deterministic\n        {\n            auto seq = build_cover(2.0, 1.0, 1, 0.0, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(TL - 30, elapsed_ms() + 150));\n\n            if (elapsed_ms() < TL - 90) {\n                replace_candidatewise(seq, c, min(TL - 70, elapsed_ms() + 35));\n            }\n\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n        }\n\n        // secondary seed\n        if (elapsed_ms() < TL - 600) {\n            auto seq = build_cover(1.4, 1.0, 3, 0.06, rng);\n            prune_waypoint_cost(seq);\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(TL - 350, elapsed_ms() + 90));\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n        }\n\n        vector<int> curSeq = bestSeq;\n        long long curCost = bestCost;\n\n        // dynamic split\n        long long now = elapsed_ms();\n        long long rem = max(0LL, TL - now);\n\n        long long tConstruct = now + rem * 22 / 100;\n        long long tRR        = now + rem * 74 / 100;\n        long long tPolish    = now + rem * 90 / 100;\n        long long tRoute     = TL - 5;\n\n        if (tConstruct > tRR) tConstruct = tRR;\n        if (tRR > tPolish) tRR = tPolish;\n\n        // constructive multi-start\n        while (elapsed_ms() < tConstruct) {\n            static const double AS[] = {1.0, 1.2, 1.4, 1.7, 2.0, 2.3};\n            static const double BS[] = {0.8, 1.0, 1.2, 1.4};\n            static const int KS[] = {1, 2, 3, 4, 6};\n\n            double alpha = AS[rng.next_int(0, 5)];\n            double beta  = BS[rng.next_int(0, 3)];\n            int topk     = KS[rng.next_int(0, 4)];\n            double noise = 0.12;\n\n            auto seq = build_cover(alpha, beta, topk, noise, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(tConstruct, elapsed_ms() + 55));\n\n            if (elapsed_ms() < tConstruct - 20 && rng.next_double() < 0.55) {\n                replace_candidatewise(seq, c, min(tConstruct, elapsed_ms() + 20));\n            }\n\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n        }\n\n        curSeq = bestSeq;\n        curCost = bestCost;\n\n        // ruin & recreate + SA-like acceptance\n        while (elapsed_ms() < tRR) {\n            vector<int> base = (rng.next_double() < 0.65 ? bestSeq : curSeq);\n\n            auto seq = ruin_recreate(base, rng);\n            prune_waypoint_cost(seq);\n\n            long long c = cycle_cost(seq);\n            local_search(seq, c, min(tRR, elapsed_ms() + 75));\n\n            if (elapsed_ms() < tRR - 20 && rng.next_double() < 0.65) {\n                replace_candidatewise(seq, c, min(tRR, elapsed_ms() + 22));\n            }\n\n            prune_waypoint_cost(seq);\n            c = cycle_cost(seq);\n            update_best(seq, c);\n\n            double prog = (double)(elapsed_ms() - tConstruct) / (double)max(1LL, tRR - tConstruct);\n            prog = max(0.0, min(1.0, prog));\n            double temp = 16.0 * (1.0 - prog) + 1.0;\n\n            long long delta = c - curCost;\n            if (delta <= 0 || rng.next_double() < exp(-(double)delta / temp)) {\n                curSeq = seq;\n                curCost = c;\n            }\n        }\n\n        // final candidate-level polish\n        if (elapsed_ms() < tPolish && !bestSeq.empty()) {\n            auto seq = bestSeq;\n            long long c = bestCost;\n\n            while (elapsed_ms() < tPolish) {\n                long long before = c;\n\n                local_search(seq, c, min(tPolish, elapsed_ms() + 65));\n                if (elapsed_ms() < tPolish - 20) {\n                    replace_candidatewise(seq, c, min(tPolish, elapsed_ms() + 25));\n                }\n\n                prune_waypoint_cost(seq);\n                c = cycle_cost(seq);\n\n                if (c < bestCost && candidate_cover_full(seq)) {\n                    bestCost = c;\n                    bestSeq = seq;\n                }\n                if (c >= before) break;\n            }\n        }\n\n        vector<int> finalSeq = bestSeq;\n\n        // route-aware phase\n        if (elapsed_ms() < tRoute && finalSeq.size() > 1) {\n            while (elapsed_ms() < tRoute) {\n                bool changed = false;\n\n                changed |= route_aware_prune_combo(finalSeq, min(tRoute, elapsed_ms() + 65));\n                if (elapsed_ms() < tRoute) changed |= route_aware_replace(finalSeq, min(tRoute, elapsed_ms() + 65));\n                if (elapsed_ms() < tRoute) changed |= route_aware_2opt(finalSeq, min(tRoute, elapsed_ms() + 65));\n                if (elapsed_ms() < tRoute) changed |= route_aware_relocate(finalSeq, min(tRoute, elapsed_ms() + 45));\n\n                if (!changed) break;\n            }\n\n            if (!coverage_full_sequence(finalSeq) || cycle_cost(finalSeq) > bestCost) {\n                finalSeq = bestSeq;\n            }\n        }\n\n        string ans = build_answer(finalSeq);\n\n        // safety fallback\n        if ((finalSeq.size() > 1 && ans.empty()) || !validate_ans(ans)) {\n            string alt = build_answer(bestSeq);\n            if (validate_ans(alt)) {\n                ans = alt;\n            } else {\n                ans = fallback_dfs_tour();\n            }\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    cout << solver.solve() << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\n#include <atcoder/mincostflow>\nusing namespace std;\nusing namespace atcoder;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n\n    int N, M, K, R;\n    vector<vector<int>> d;\n    vector<vector<int>> succ;\n    vector<int> indeg0, indegRem, outdeg;\n    vector<int> sumd;\n    vector<int> lp;          // dynamic remaining longest path (among unfinished tasks)\n    vector<int> descCnt;     // static descendant count\n    vector<int> taskState;   // 0:not started, 1:in progress, 2:done\n\n    vector<int> ready, readyPos, readySince;\n    int day = 1;\n    int stallDays = 0;\n\n    struct Member {\n        bool busy = false;\n        int task = -1;\n        int startDay = 0;\n        vector<int> s;\n        vector<int> histTask;\n        vector<int> histDur;\n        bool dirty = false;\n        int doneCount = 0;\n    };\n    vector<Member> members;\n\n    // ---- parameters ----\n    static constexpr int INIT_SKILL = 8;\n    static constexpr int SKILL_MAX = 80;\n    static constexpr int MAX_HIST = 120;\n\n    static constexpr int MAX_CAND = 180;\n    static constexpr int BASE_CAND = 110;\n    static constexpr int AGE_CAND = 40;\n\n    static constexpr int LP_W = 100;\n    static constexpr int DESC_W = 2;\n    static constexpr int UNLOCK_W = 70;\n    static constexpr int AGE_W = 6;\n\n    static constexpr double PRED_W = 40.0;\n    static constexpr double CRIT_MARGIN = 2.0;\n    static constexpr double CRIT_EXCESS_W = 220.0;\n    static constexpr double NEWBIE_CRIT_PEN = 120.0;\n\n    static constexpr double IDLE_UTILITY = -1800.0;\n    static constexpr long long COST_SHIFT = 1'000'000LL;\n\n    static inline double expected_time_from_w(int w) {\n        if (w <= 0) return 1.0;\n        if (w == 1) return 13.0 / 7.0;\n        if (w == 2) return 17.0 / 7.0;\n        if (w == 3) return 22.0 / 7.0;\n        return (double)w;\n    }\n\n    static inline long long utility_to_cost(double util) {\n        long long u10 = llround(util * 10.0);\n        long long c = COST_SHIFT - u10;\n        if (c < 0) c = 0;\n        return c;\n    }\n\n    double sample_loss(int w, int obs) const {\n        const double pred = expected_time_from_w(w);\n        const double e = pred - (double)obs;\n        const double ae = fabs(e);\n\n        // robust / noise-tolerant loss\n        double l;\n        if (ae <= 2.0) {\n            l = 0.25 * ae * ae;\n        } else {\n            const double z = ae - 2.0;\n            l = 1.0 + z * z;\n        }\n\n        // short tasks are less informative (especially obs=1 due clipping)\n        const double wt = (obs <= 1 ? 0.30 : (obs <= 3 ? 0.70 : 1.00));\n        return wt * l;\n    }\n\n    inline int calc_w(const vector<int>& s, int task) const {\n        int w = 0;\n        for (int k = 0; k < K; k++) {\n            if (d[task][k] > s[k]) w += d[task][k] - s[k];\n        }\n        return w;\n    }\n\n    inline double predict_time_exp(int member, int task) const {\n        int w = calc_w(members[member].s, task);\n        return expected_time_from_w(w);\n    }\n\n    void add_ready(int t, int availDay) {\n        if (t < 0 || t >= N) return;\n        if (taskState[t] != 0) return;\n        if (indegRem[t] != 0) return;\n        if (readyPos[t] != -1) return;\n        readyPos[t] = (int)ready.size();\n        ready.push_back(t);\n        readySince[t] = availDay;\n    }\n\n    void remove_ready(int t) {\n        int p = readyPos[t];\n        if (p == -1) return;\n        int last = ready.back();\n        ready[p] = last;\n        readyPos[last] = p;\n        ready.pop_back();\n        readyPos[t] = -1;\n        readySince[t] = -1;\n    }\n\n    void compute_static_descendants() {\n        descCnt.assign(N, 0);\n        if (N <= MAXN) {\n            vector<bitset<MAXN>> reach(N);\n            for (int i = N - 1; i >= 0; i--) {\n                for (int to : succ[i]) {\n                    reach[i] |= reach[to];\n                    reach[i].set(to);\n                }\n                descCnt[i] = (int)reach[i].count();\n            }\n        } else {\n            // fallback (shouldn't be used in official generator)\n            for (int i = 0; i < N; i++) descCnt[i] = outdeg[i];\n        }\n    }\n\n    void update_remaining_lp() {\n        if ((int)lp.size() != N) lp.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            if (taskState[i] == 2) {\n                lp[i] = 0;\n                continue;\n            }\n            int best = 1;\n            for (int to : succ[i]) {\n                if (taskState[to] != 2) best = max(best, lp[to] + 1);\n            }\n            lp[i] = best;\n        }\n    }\n\n    int task_base(int t) const {\n        int unlock = 0;\n        for (int ch : succ[t]) {\n            if (taskState[ch] == 0 && indegRem[ch] == 1) unlock++;\n        }\n        int age = 0;\n        if (readySince[t] >= 0) age = max(0, day - readySince[t]);\n\n        int base = 0;\n        base += LP_W * lp[t];\n        base += DESC_W * descCnt[t];\n        base += UNLOCK_W * unlock;\n        base += AGE_W * age;\n        base += outdeg[t]; // tiny tie-break\n        return base;\n    }\n\n    vector<int> make_candidates() const {\n        if ((int)ready.size() <= MAX_CAND) return ready;\n\n        vector<pair<int, int>> byBase; // (-base, t)\n        vector<pair<int, int>> byAge;  // (-age, t)\n        byBase.reserve(ready.size());\n        byAge.reserve(ready.size());\n\n        for (int t : ready) {\n            byBase.push_back({-task_base(t), t});\n            int age = max(0, day - readySince[t]);\n            byAge.push_back({-age, t});\n        }\n\n        sort(byBase.begin(), byBase.end());\n        sort(byAge.begin(), byAge.end());\n\n        vector<char> used(N, 0);\n        vector<int> cand;\n        cand.reserve(MAX_CAND);\n\n        int t1 = min(BASE_CAND, (int)byBase.size());\n        for (int i = 0; i < t1; i++) {\n            int t = byBase[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        int t2 = min(AGE_CAND, (int)byAge.size());\n        for (int i = 0; i < t2 && (int)cand.size() < MAX_CAND; i++) {\n            int t = byAge[i].second;\n            if (!used[t]) {\n                used[t] = 1;\n                cand.push_back(t);\n            }\n        }\n\n        if ((int)cand.size() < MAX_CAND) {\n            vector<pair<int, int>> byEasy; // (sumd, t)\n            byEasy.reserve(ready.size());\n            for (int t : ready) {\n                if (!used[t]) byEasy.push_back({sumd[t], t});\n            }\n            sort(byEasy.begin(), byEasy.end());\n            for (auto &p : byEasy) {\n                if ((int)cand.size() >= MAX_CAND) break;\n                cand.push_back(p.second);\n            }\n        }\n        return cand;\n    }\n\n    void optimize_member(int j) {\n        Member &mb = members[j];\n        int total = (int)mb.histTask.size();\n        if (total == 0) {\n            mb.dirty = false;\n            return;\n        }\n\n        int st = max(0, total - MAX_HIST);\n        int h = total - st;\n\n        vector<int> tasks(h), obs(h), w(h);\n        for (int i = 0; i < h; i++) {\n            tasks[i] = mb.histTask[st + i];\n            obs[i] = mb.histDur[st + i];\n        }\n\n        for (int i = 0; i < h; i++) {\n            w[i] = calc_w(mb.s, tasks[i]);\n        }\n\n        const double reg = 0.30 / (h + 3.0); // stronger when data is scarce\n\n        double loss = 0.0;\n        for (int i = 0; i < h; i++) loss += sample_loss(w[i], obs[i]);\n        for (int k = 0; k < K; k++) {\n            double diff = (double)mb.s[k] - INIT_SKILL;\n            loss += reg * diff * diff;\n        }\n\n        static const int deltas_small[] = {-2, -1, 1, 2};\n        static const int deltas_large[] = {-8, -4, -2, -1, 1, 2, 4, 8};\n        const int *deltas = (h < 5 ? deltas_small : deltas_large);\n        int nd = (h < 5 ? 4 : 8);\n\n        int passes = (h < 8 ? 6 : (h < 20 ? 5 : 4));\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            bool improved = false;\n            if (pass & 1) reverse(order.begin(), order.end());\n\n            for (int idx = 0; idx < K; idx++) {\n                int k = order[idx];\n                int curS = mb.s[k];\n                double bestLoss = loss;\n                int bestS = curS;\n\n                for (int di = 0; di < nd; di++) {\n                    int ns = curS + deltas[di];\n                    if (ns < 0 || ns > SKILL_MAX || ns == curS) continue;\n\n                    double newLoss = loss;\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)ns - INIT_SKILL;\n                        newLoss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > ns ? dval - ns : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n\n                        newLoss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                    }\n\n                    if (newLoss + 1e-9 < bestLoss) {\n                        bestLoss = newLoss;\n                        bestS = ns;\n                    }\n                }\n\n                if (bestS != curS) {\n                    {\n                        double oldDiff = (double)curS - INIT_SKILL;\n                        double newDiff = (double)bestS - INIT_SKILL;\n                        loss += reg * (newDiff * newDiff - oldDiff * oldDiff);\n                    }\n\n                    for (int i = 0; i < h; i++) {\n                        int task = tasks[i];\n                        int dval = d[task][k];\n\n                        int oldComp = (dval > curS ? dval - curS : 0);\n                        int newComp = (dval > bestS ? dval - bestS : 0);\n                        if (oldComp == newComp) continue;\n\n                        int ow = w[i];\n                        int nw = ow - oldComp + newComp;\n                        loss += sample_loss(nw, obs[i]) - sample_loss(ow, obs[i]);\n                        w[i] = nw;\n                    }\n\n                    mb.s[k] = bestS;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        mb.dirty = false;\n    }\n\n    vector<pair<int, int>> decide_assignments(bool force) {\n        vector<pair<int, int>> ret;\n\n        vector<int> freeMembers;\n        freeMembers.reserve(M);\n        for (int j = 0; j < M; j++) {\n            if (!members[j].busy) freeMembers.push_back(j);\n        }\n        if (freeMembers.empty() || ready.empty()) return ret;\n\n        vector<int> cand = make_candidates();\n        int F = (int)freeMembers.size();\n        int T = (int)cand.size();\n        if (T == 0) return ret;\n\n        vector<int> base(T);\n        int maxReadyLp = 0, maxReadyDesc = 0;\n        for (int t : ready) {\n            maxReadyLp = max(maxReadyLp, lp[t]);\n            maxReadyDesc = max(maxReadyDesc, descCnt[t]);\n        }\n\n        vector<char> critical(T, 0);\n        for (int ti = 0; ti < T; ti++) {\n            int t = cand[ti];\n            base[ti] = task_base(t);\n            if (lp[t] >= maxReadyLp - 1) critical[ti] = 1;\n            if (descCnt[t] >= maxReadyDesc - 20) critical[ti] = 1;\n        }\n\n        vector<vector<double>> predAll(M, vector<double>(T));\n        vector<double> bestAllPred(T, 1e100);\n        for (int m = 0; m < M; m++) {\n            for (int ti = 0; ti < T; ti++) {\n                double p = predict_time_exp(m, cand[ti]);\n                predAll[m][ti] = p;\n                if (p < bestAllPred[ti]) bestAllPred[ti] = p;\n            }\n        }\n\n        int S = F + T;\n        int G = S + 1;\n        mcf_graph<int, long long> g(G + 1);\n\n        for (int fi = 0; fi < F; fi++) g.add_edge(S, fi, 1, 0);\n        for (int ti = 0; ti < T; ti++) g.add_edge(F + ti, G, 1, 0);\n\n        if (!force) {\n            long long idleCost = utility_to_cost(IDLE_UTILITY);\n            for (int fi = 0; fi < F; fi++) {\n                g.add_edge(fi, G, 1, idleCost);\n            }\n        }\n\n        vector<int> eid(F * T, -1);\n\n        for (int fi = 0; fi < F; fi++) {\n            int m = freeMembers[fi];\n            for (int ti = 0; ti < T; ti++) {\n                double pred = predAll[m][ti];\n                double util = (double)base[ti] - PRED_W * pred;\n\n                if (critical[ti]) {\n                    double excess = pred - bestAllPred[ti];\n                    if (excess > CRIT_MARGIN) {\n                        util -= CRIT_EXCESS_W * (excess - CRIT_MARGIN);\n                    }\n                    if (members[m].doneCount < 2) {\n                        util -= NEWBIE_CRIT_PEN;\n                    }\n                }\n\n                long long cost = utility_to_cost(util);\n                eid[fi * T + ti] = g.add_edge(fi, F + ti, 1, cost);\n            }\n        }\n\n        if (force) {\n            int L = min(T, max(1, F / 2)); // conservative forced progress\n            g.flow(S, G, L);\n        } else {\n            g.flow(S, G, F); // each free member: task or idle\n        }\n\n        for (int fi = 0; fi < F; fi++) {\n            for (int ti = 0; ti < T; ti++) {\n                auto e = g.get_edge(eid[fi * T + ti]);\n                if (e.flow > 0) {\n                    ret.push_back({freeMembers[fi], cand[ti]});\n                }\n            }\n        }\n\n        for (auto [m, t] : ret) {\n            members[m].busy = true;\n            members[m].task = t;\n            members[m].startDay = day;\n\n            taskState[t] = 1;\n            remove_ready(t);\n        }\n\n        return ret;\n    }\n\n    void read_initial() {\n        cin >> N >> M >> K >> R;\n\n        d.assign(N, vector<int>(K));\n        sumd.assign(N, 0);\n        for (int i = 0; i < N; i++) {\n            int s = 0;\n            for (int k = 0; k < K; k++) {\n                cin >> d[i][k];\n                s += d[i][k];\n            }\n            sumd[i] = s;\n        }\n\n        succ.assign(N, {});\n        indeg0.assign(N, 0);\n\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            succ[u].push_back(v);\n            indeg0[v]++;\n        }\n\n        outdeg.assign(N, 0);\n        for (int i = 0; i < N; i++) outdeg[i] = (int)succ[i].size();\n\n        compute_static_descendants();\n\n        indegRem = indeg0;\n        taskState.assign(N, 0);\n\n        ready.clear();\n        readyPos.assign(N, -1);\n        readySince.assign(N, -1);\n\n        day = 1;\n        for (int i = 0; i < N; i++) {\n            if (indegRem[i] == 0) add_ready(i, 1);\n        }\n\n        members.assign(M, Member());\n        for (int j = 0; j < M; j++) {\n            members[j].s.assign(K, INIT_SKILL);\n        }\n\n        lp.assign(N, 1);\n        update_remaining_lp();\n    }\n\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        read_initial();\n\n        while (true) {\n            update_remaining_lp();\n\n            int freeCntBefore = 0;\n            for (int j = 0; j < M; j++) if (!members[j].busy) freeCntBefore++;\n            bool hadReady = !ready.empty();\n\n            bool force = (stallDays >= 2);\n            auto assignments = decide_assignments(force);\n\n            if (hadReady && freeCntBefore > 0 && assignments.empty()) {\n                stallDays++;\n            } else if (!assignments.empty()) {\n                stallDays = 0;\n            } else if (!hadReady || freeCntBefore == 0) {\n                stallDays = 0;\n            }\n\n            cout << assignments.size();\n            for (auto [m, t] : assignments) {\n                cout << ' ' << (m + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int n;\n            if (!(cin >> n)) return;\n            if (n == -1) return;\n\n            vector<int> finished(n);\n            for (int i = 0; i < n; i++) {\n                cin >> finished[i];\n                --finished[i];\n            }\n\n            for (int m : finished) {\n                if (m < 0 || m >= M) continue;\n                Member &mb = members[m];\n                if (!mb.busy) continue;\n\n                int task = mb.task;\n                int duration = day - mb.startDay + 1;\n\n                mb.busy = false;\n                mb.task = -1;\n                mb.doneCount++;\n                mb.histTask.push_back(task);\n                mb.histDur.push_back(duration);\n                mb.dirty = true;\n\n                taskState[task] = 2;\n\n                for (int ch : succ[task]) {\n                    indegRem[ch]--;\n                    if (indegRem[ch] == 0 && taskState[ch] == 0) {\n                        add_ready(ch, day + 1);\n                    }\n                }\n            }\n\n            for (int m : finished) {\n                if (0 <= m && m < M && members[m].dirty) {\n                    optimize_member(m);\n                }\n            }\n\n            day++;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic uint16_t DISTMAT[2001][2001];\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint32_t nextU32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(nextU32() % (uint32_t)n); }\n    double nextDouble() { return (nextU32() + 0.5) / 4294967296.0; }\n};\n\nclass Solver {\n    static constexpr int N = 1000;\n    static constexpr int M = 50;\n    static constexpr int DEP = 2000;\n    static constexpr int TOT = 2001;\n    static constexpr int K_NEAR = 24;\n\n    struct Insertion {\n        int delta;\n        int i, j; // insert pickup at i, delivery at j (after pickup insertion)\n    };\n    struct Cand {\n        int delta;\n        int id;\n        Insertion ins;\n    };\n    struct State {\n        vector<int> route; // pickup [0..999], delivery [1000..1999]\n        vector<int> sel;   // selected order IDs [0..999]\n        array<int, N> pos; // -1 if unselected\n        int len;\n        State() : len(INT_MAX) {\n            route.reserve(2 * M);\n            sel.reserve(M);\n            pos.fill(-1);\n        }\n    };\n\n    int a[N], b[N], c[N], d[N];\n    int nodeX[TOT], nodeY[TOT];\n\n    array<int, N> baseCost{};\n    vector<int> sortedBase;\n\n    int nearOrders[TOT][K_NEAR];\n    array<unsigned char, TOT> nearBuilt{};\n\n    array<int, N> seen{};\n    int seenStamp = 1;\n\n    XorShift rng;\n    chrono::steady_clock::time_point t0;\n    double TL = 1.90;\n\n    vector<int> tmp1, tmp2, ord, candIds;\n    vector<pair<int, int>> gains; // (removal gain, oid), descending\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        tmp1.reserve(2 * M);\n        tmp2.reserve(2 * M);\n        ord.reserve(M);\n        candIds.reserve(900);\n        gains.reserve(M);\n        nearBuilt.fill(0);\n        seen.fill(0);\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline void nextSeenStamp() {\n        ++seenStamp;\n        if (seenStamp == INT_MAX) {\n            seen.fill(0);\n            seenStamp = 1;\n        }\n    }\n\n    template <class T>\n    inline void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    inline int calcLen(const vector<int>& route) const {\n        int prev = DEP, len = 0;\n        for (int v : route) {\n            len += DISTMAT[prev][v];\n            prev = v;\n        }\n        len += DISTMAT[prev][DEP];\n        return len;\n    }\n\n    // O(n) exact best insertion of pair (pickup=oid, delivery=oid+N).\n    Insertion bestInsertPair(const vector<int>& route, int oid) const {\n        const int p = oid;\n        const int q = oid + N;\n        const int n = (int)route.size();\n\n        int U[105], V[105], dQ[105];\n        int sufVal[107], sufIdx[107];\n\n        const uint16_t* rowP = DISTMAT[p];\n        const uint16_t* rowQ = DISTMAT[q];\n        const int pq = rowP[q];\n\n        for (int t = 0; t <= n; ++t) {\n            U[t] = (t == 0 ? DEP : route[t - 1]);\n            V[t] = (t == n ? DEP : route[t]);\n            dQ[t] = (int)DISTMAT[U[t]][q] + (int)rowQ[V[t]] - (int)DISTMAT[U[t]][V[t]];\n        }\n\n        const int INF = 1e9;\n        sufVal[n + 1] = INF;\n        sufIdx[n + 1] = -1;\n        for (int t = n; t >= 0; --t) {\n            if (dQ[t] <= sufVal[t + 1]) {\n                sufVal[t] = dQ[t];\n                sufIdx[t] = t;\n            } else {\n                sufVal[t] = sufVal[t + 1];\n                sufIdx[t] = sufIdx[t + 1];\n            }\n        }\n\n        Insertion best{INF, 0, 1};\n\n        for (int i = 0; i <= n; ++i) {\n            int A = U[i], B = V[i];\n            int baseP = (int)DISTMAT[A][p] + (int)rowP[B] - (int)DISTMAT[A][B];\n\n            int bestExtra = pq + (int)rowQ[B] - (int)rowP[B];\n            int bestJ = i + 1;\n\n            if (i + 1 <= n && sufVal[i + 1] < bestExtra) {\n                bestExtra = sufVal[i + 1];\n                bestJ = sufIdx[i + 1] + 1;\n            }\n\n            int delta = baseP + bestExtra;\n            if (delta < best.delta) best = {delta, i, bestJ};\n        }\n\n        return best;\n    }\n\n    inline void insertPair(vector<int>& route, const Insertion& ins, int oid) const {\n        route.insert(route.begin() + ins.i, oid);\n        route.insert(route.begin() + ins.j, oid + N);\n    }\n\n    inline void removeOrder(const vector<int>& route, int oid, vector<int>& out) const {\n        out.clear();\n        int p = oid, q = oid + N;\n        for (int v : route) {\n            if (v == p || v == q) continue;\n            out.push_back(v);\n        }\n    }\n\n    inline void pushTopCand(vector<Cand>& top, const Cand& c, int lim) const {\n        if ((int)top.size() < lim) {\n            top.push_back(c);\n            for (int i = (int)top.size() - 1; i > 0; --i) {\n                if (top[i].delta < top[i - 1].delta) swap(top[i], top[i - 1]);\n                else break;\n            }\n        } else if (c.delta < top.back().delta) {\n            top.back() = c;\n            for (int i = (int)top.size() - 1; i > 0; --i) {\n                if (top[i].delta < top[i - 1].delta) swap(top[i], top[i - 1]);\n                else break;\n            }\n        }\n    }\n\n    void buildNearForNode(int node) {\n        if (nearBuilt[node]) return;\n\n        static array<pair<int, int>, N> cand;\n        for (int id = 0; id < N; ++id) {\n            int sc = (int)DISTMAT[node][id]\n                   + (int)DISTMAT[id][id + N]\n                   + ((int)DISTMAT[id + N][DEP] >> 2);\n            cand[id] = {sc, id};\n        }\n\n        nth_element(cand.begin(), cand.begin() + K_NEAR, cand.end(),\n                    [](const auto& l, const auto& r) { return l.first < r.first; });\n        sort(cand.begin(), cand.begin() + K_NEAR,\n             [](const auto& l, const auto& r) { return l.first < r.first; });\n\n        for (int k = 0; k < K_NEAR; ++k) nearOrders[node][k] = cand[k].second;\n        nearBuilt[node] = 1;\n    }\n\n    void buildCandidatesForRoute(\n        const State& s,\n        const vector<int>& route,\n        int target,\n        int forbid1,\n        int forbid2,\n        int forbid3,\n        int anchor1,\n        int anchor2,\n        vector<int>& out\n    ) {\n        target = min(target, N);\n        out.clear();\n        nextSeenStamp();\n\n        auto add = [&](int id) {\n            if (id < 0 || id >= N) return;\n            if (id == forbid1 || id == forbid2 || id == forbid3) return;\n            if (s.pos[id] != -1) return;\n            if (seen[id] == seenStamp) return;\n            seen[id] = seenStamp;\n            out.push_back(id);\n        };\n\n        auto addNearNode = [&](int node, int take) {\n            buildNearForNode(node);\n            for (int k = 0; k < take && (int)out.size() < target; ++k) {\n                add(nearOrders[node][k]);\n            }\n        };\n\n        addNearNode(DEP, min(10, K_NEAR));\n\n        auto addAnchor = [&](int x) {\n            if (x < 0 || x >= N) return;\n            addNearNode(x, min(8, K_NEAR));\n            addNearNode(x + N, min(8, K_NEAR));\n        };\n        addAnchor(anchor1);\n        addAnchor(anchor2);\n\n        // longest edges\n        const int EKEEP = 4;\n        int bw[EKEEP], bu[EKEEP], bv[EKEEP];\n        for (int p = 0; p < EKEEP; ++p) {\n            bw[p] = -1;\n            bu[p] = DEP;\n            bv[p] = DEP;\n        }\n        int L = (int)route.size();\n        for (int t = 0; t <= L; ++t) {\n            int u = (t == 0 ? DEP : route[t - 1]);\n            int v = (t == L ? DEP : route[t]);\n            int w = (int)DISTMAT[u][v];\n            int pos = -1;\n            for (int p = 0; p < EKEEP; ++p) {\n                if (w > bw[p]) { pos = p; break; }\n            }\n            if (pos != -1) {\n                for (int q = EKEEP - 1; q > pos; --q) {\n                    bw[q] = bw[q - 1];\n                    bu[q] = bu[q - 1];\n                    bv[q] = bv[q - 1];\n                }\n                bw[pos] = w; bu[pos] = u; bv[pos] = v;\n            }\n        }\n        for (int p = 0; p < EKEEP && (int)out.size() < target; ++p) {\n            if (bw[p] < 0) break;\n            addNearNode(bu[p], 4);\n            addNearNode(bv[p], 4);\n        }\n\n        int nearTarget = target * 3 / 4;\n        int stride = 2 + rng.nextInt(2);\n        int offset = rng.nextInt(stride);\n        int perNode = 4;\n        for (int idx = offset; idx < (int)route.size() && (int)out.size() < nearTarget; idx += stride) {\n            addNearNode(route[idx], perNode);\n        }\n\n        int baseTake = 320;\n        for (int i = 0; i < baseTake && i < N && (int)out.size() < target; ++i) add(sortedBase[i]);\n\n        int tries = 0;\n        while ((int)out.size() < target && tries < 5000) {\n            ++tries;\n            add(rng.nextInt(N));\n        }\n        if ((int)out.size() < target) {\n            for (int id = 0; id < N && (int)out.size() < target; ++id) add(id);\n        }\n    }\n\n    State buildPureGreedyAll() {\n        State s;\n        s.len = 0;\n        for (int step = 0; step < M; ++step) {\n            int bestId = -1;\n            Insertion bestIns{INT_MAX, 0, 1};\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                Insertion ins = bestInsertPair(s.route, id);\n                if (ins.delta < bestIns.delta) {\n                    bestIns = ins;\n                    bestId = id;\n                }\n            }\n            insertPair(s.route, bestIns, bestId);\n            s.len += bestIns.delta;\n            s.pos[bestId] = (int)s.sel.size();\n            s.sel.push_back(bestId);\n        }\n        s.len = calcLen(s.route);\n        return s;\n    }\n\n    State buildGRASP(int rcl, int poolBase, int randExtra) {\n        rcl = max(1, rcl);\n        poolBase = max(80, min(poolBase, N));\n\n        State s;\n        s.len = 0;\n        vector<Cand> top;\n        top.reserve(rcl + 1);\n\n        for (int step = 0; step < M; ++step) {\n            candIds.clear();\n            nextSeenStamp();\n\n            auto addCand = [&](int id) {\n                if (s.pos[id] != -1) return;\n                if (seen[id] == seenStamp) return;\n                seen[id] = seenStamp;\n                candIds.push_back(id);\n            };\n\n            int lim = min(N, poolBase + step * 8);\n            for (int i = 0; i < lim; ++i) addCand(sortedBase[i]);\n\n            int target = min(N, lim + randExtra);\n            int tries = 0;\n            while ((int)candIds.size() < target && tries < 5000) {\n                ++tries;\n                addCand(rng.nextInt(N));\n            }\n            if ((int)candIds.size() < target) {\n                for (int id = 0; id < N && (int)candIds.size() < target; ++id) addCand(id);\n            }\n\n            top.clear();\n            for (int id : candIds) {\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTopCand(top, Cand{ins.delta, id, ins}, rcl);\n            }\n\n            if (top.empty()) {\n                Cand best{INT_MAX, -1, {INT_MAX, 0, 1}};\n                for (int id = 0; id < N; ++id) {\n                    if (s.pos[id] != -1) continue;\n                    Insertion ins = bestInsertPair(s.route, id);\n                    if (ins.delta < best.delta) best = Cand{ins.delta, id, ins};\n                }\n                top.push_back(best);\n            }\n\n            int pick = ((int)top.size() == 1 ? 0 : rng.nextInt((int)top.size()));\n            const Cand& ch = top[pick];\n\n            insertPair(s.route, ch.ins, ch.id);\n            s.len += ch.delta;\n            s.pos[ch.id] = (int)s.sel.size();\n            s.sel.push_back(ch.id);\n        }\n\n        s.len = calcLen(s.route);\n        return s;\n    }\n\n    bool relocateOrder(State& s, int oid) {\n        removeOrder(s.route, oid, tmp1);\n        int base = calcLen(tmp1);\n        Insertion ins = bestInsertPair(tmp1, oid);\n        int nlen = base + ins.delta;\n        if (nlen < s.len) {\n            tmp2 = tmp1;\n            insertPair(tmp2, ins, oid);\n            s.route.swap(tmp2);\n            s.len = nlen;\n            return true;\n        }\n        return false;\n    }\n\n    bool relocateRandomK(State& s, int k) {\n        bool improved = false;\n        for (int t = 0; t < k; ++t) {\n            int oid = s.sel[rng.nextInt(M)];\n            if (relocateOrder(s, oid)) improved = true;\n        }\n        return improved;\n    }\n\n    bool relocatePass(State& s, double deadline) {\n        ord = s.sel;\n        shuffleVec(ord);\n        bool improved = false;\n        for (int oid : ord) {\n            if (elapsed() >= deadline) break;\n            if (relocateOrder(s, oid)) improved = true;\n        }\n        return improved;\n    }\n\n    bool adjacentSwapPass(State& s, int maxPass, double deadline) {\n        bool any = false;\n        int L = (int)s.route.size();\n\n        for (int pass = 0; pass < maxPass && elapsed() < deadline; ++pass) {\n            bool improved = false;\n            for (int i = 0; i + 1 < L; ++i) {\n                if ((i & 63) == 0 && elapsed() >= deadline) break;\n                int x = s.route[i], y = s.route[i + 1];\n                if (x < N && y == x + N) continue;\n\n                int A = (i == 0 ? DEP : s.route[i - 1]);\n                int B = (i + 2 == L ? DEP : s.route[i + 2]);\n\n                int oldC = (int)DISTMAT[A][x] + (int)DISTMAT[x][y] + (int)DISTMAT[y][B];\n                int newC = (int)DISTMAT[A][y] + (int)DISTMAT[y][x] + (int)DISTMAT[x][B];\n                if (newC < oldC) {\n                    swap(s.route[i], s.route[i + 1]);\n                    s.len += (newC - oldC);\n                    improved = true;\n                    any = true;\n                }\n            }\n            if (!improved) break;\n        }\n        return any;\n    }\n\n    bool bestEventSwapLocal(State& s, int maxMoves, double deadline) {\n        bool improvedAny = false;\n        int L = (int)s.route.size();\n\n        for (int mv = 0; mv < maxMoves && elapsed() < deadline; ++mv) {\n            static int ppos[N], dpos[N];\n            fill(ppos, ppos + N, -1);\n            fill(dpos, dpos + N, -1);\n\n            for (int i = 0; i < L; ++i) {\n                int v = s.route[i];\n                if (v < N) ppos[v] = i;\n                else dpos[v - N] = i;\n            }\n\n            int bestDelta = 0, bi = -1, bj = -1;\n\n            for (int i = 0; i + 1 < L; ++i) {\n                if ((i & 31) == 0 && elapsed() >= deadline) break;\n\n                int x = s.route[i];\n                int ox = (x < N ? x : x - N);\n                bool xPick = (x < N);\n\n                for (int j = i + 1; j < L; ++j) {\n                    int y = s.route[j];\n                    int oy = (y < N ? y : y - N);\n                    if (ox == oy) continue;\n                    bool yPick = (y < N);\n\n                    int pox = ppos[ox], dox = dpos[ox];\n                    int poy = ppos[oy], doy = dpos[oy];\n\n                    int npox = pox, ndox = dox;\n                    int npoy = poy, ndoy = doy;\n\n                    if (xPick) npox = j; else ndox = j;\n                    if (yPick) npoy = i; else ndoy = i;\n\n                    if (npox >= ndox || npoy >= ndoy) continue;\n\n                    int delta = 0;\n                    if (j == i + 1) {\n                        int A = (i == 0 ? DEP : s.route[i - 1]);\n                        int D = (j == L - 1 ? DEP : s.route[j + 1]);\n                        int oldC = (int)DISTMAT[A][x] + (int)DISTMAT[x][y] + (int)DISTMAT[y][D];\n                        int newC = (int)DISTMAT[A][y] + (int)DISTMAT[y][x] + (int)DISTMAT[x][D];\n                        delta = newC - oldC;\n                    } else {\n                        int A = (i == 0 ? DEP : s.route[i - 1]);\n                        int B = s.route[i + 1];\n                        int C = s.route[j - 1];\n                        int D = (j == L - 1 ? DEP : s.route[j + 1]);\n\n                        int oldC = (int)DISTMAT[A][x] + (int)DISTMAT[x][B]\n                                 + (int)DISTMAT[C][y] + (int)DISTMAT[y][D];\n                        int newC = (int)DISTMAT[A][y] + (int)DISTMAT[y][B]\n                                 + (int)DISTMAT[C][x] + (int)DISTMAT[x][D];\n                        delta = newC - oldC;\n                    }\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (bestDelta < 0) {\n                swap(s.route[bi], s.route[bj]);\n                s.len += bestDelta;\n                improvedAny = true;\n            } else {\n                break;\n            }\n        }\n\n        return improvedAny;\n    }\n\n    // precedence-safe segment reversal:\n    // valid iff no order has both pickup and delivery inside [i..j].\n    bool reverseSegmentPass(State& s, int maxMoves, double deadline) {\n        bool improvedAny = false;\n        int L = (int)s.route.size();\n\n        static int localId[N];\n        fill(localId, localId + N, -1);\n        for (int i = 0; i < (int)s.sel.size(); ++i) localId[s.sel[i]] = i;\n\n        for (int mv = 0; mv < maxMoves && elapsed() < deadline; ++mv) {\n            int bestDelta = 0, bi = -1, bj = -1;\n\n            for (int i = 0; i + 1 < L; ++i) {\n                if ((i & 15) == 0 && elapsed() >= deadline) break;\n\n                uint64_t pickMask = 0, delMask = 0;\n\n                for (int j = i; j < L; ++j) {\n                    int v = s.route[j];\n                    int oid = (v < N ? v : v - N);\n                    int lid = localId[oid];\n                    if (lid < 0) continue;\n                    uint64_t bit = (1ULL << lid);\n                    if (v < N) pickMask |= bit;\n                    else delMask |= bit;\n\n                    if (j == i) continue;\n                    if ((pickMask & delMask) != 0) continue;\n\n                    int A = (i == 0 ? DEP : s.route[i - 1]);\n                    int B = s.route[i];\n                    int C = s.route[j];\n                    int D = (j == L - 1 ? DEP : s.route[j + 1]);\n\n                    int delta = (int)DISTMAT[A][C] + (int)DISTMAT[B][D]\n                              - (int)DISTMAT[A][B] - (int)DISTMAT[C][D];\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (bestDelta < 0) {\n                reverse(s.route.begin() + bi, s.route.begin() + bj + 1);\n                s.len += bestDelta;\n                improvedAny = true;\n            } else {\n                break;\n            }\n        }\n\n        return improvedAny;\n    }\n\n    void computeRemovalGainsFast(const State& s) {\n        static int posNode[2 * N];\n        fill(posNode, posNode + 2 * N, -1);\n\n        const auto& r = s.route;\n        int L = (int)r.size();\n        for (int i = 0; i < L; ++i) posNode[r[i]] = i;\n\n        gains.clear();\n        gains.reserve(M);\n\n        for (int oid : s.sel) {\n            int p = oid, q = oid + N;\n            int ip = posNode[p], iq = posNode[q];\n            if (ip < 0 || iq < 0) continue;\n\n            int gain = 0;\n            if (iq == ip + 1) {\n                int A = (ip == 0 ? DEP : r[ip - 1]);\n                int B = (iq + 1 == L ? DEP : r[iq + 1]);\n                gain = (int)DISTMAT[A][p] + (int)DISTMAT[p][q] + (int)DISTMAT[q][B] - (int)DISTMAT[A][B];\n            } else {\n                int A = (ip == 0 ? DEP : r[ip - 1]);\n                int B = r[ip + 1];\n                int C = r[iq - 1];\n                int D = (iq + 1 == L ? DEP : r[iq + 1]);\n\n                gain =\n                    ((int)DISTMAT[A][p] + (int)DISTMAT[p][B] - (int)DISTMAT[A][B]) +\n                    ((int)DISTMAT[C][q] + (int)DISTMAT[q][D] - (int)DISTMAT[C][D]);\n            }\n\n            gains.emplace_back(gain, oid);\n        }\n\n        sort(gains.begin(), gains.end(),\n             [](const auto& l, const auto& r) { return l.first > r.first; });\n    }\n\n    bool applyBestPairRelocate(State& s, int topLimit, double deadline) {\n        computeRemovalGainsFast(s);\n        topLimit = min(topLimit, (int)gains.size());\n\n        int bestLen = s.len;\n        int bestOid = -1;\n        Insertion bestIns{INT_MAX, 0, 1};\n\n        for (int t = 0; t < topLimit; ++t) {\n            if ((t & 3) == 0 && elapsed() >= deadline) break;\n\n            int oid = gains[t].second;\n            int base = s.len - gains[t].first;\n\n            removeOrder(s.route, oid, tmp1);\n            Insertion ins = bestInsertPair(tmp1, oid);\n            int nlen = base + ins.delta;\n\n            if (nlen < bestLen) {\n                bestLen = nlen;\n                bestOid = oid;\n                bestIns = ins;\n            }\n        }\n\n        if (bestOid == -1) return false;\n\n        removeOrder(s.route, bestOid, tmp1);\n        tmp2 = tmp1;\n        insertPair(tmp2, bestIns, bestOid);\n\n        s.route.swap(tmp2);\n        s.len = bestLen;\n        return true;\n    }\n\n    int pickGainIndexForSA() {\n        int gs = (int)gains.size();\n        if (gs == 0) return -1;\n        int r = rng.nextInt(100);\n        if (r < 45) return 0;\n        if (r < 75) return rng.nextInt(min(gs, 4));\n        if (r < 93) return rng.nextInt(min(gs, 12));\n        return rng.nextInt(gs);\n    }\n\n    bool tryReplaceSampledSA(State& s, double temp, int candTarget) {\n        computeRemovalGainsFast(s);\n        int gi = pickGainIndexForSA();\n        if (gi < 0) return false;\n\n        int oldGain = gains[gi].first;\n        int oldId = gains[gi].second;\n\n        removeOrder(s.route, oldId, tmp1);\n        int base = s.len - oldGain;\n\n        buildCandidatesForRoute(s, tmp1, candTarget, oldId, -1, -1, oldId, -1, candIds);\n        if (candIds.empty()) return false;\n\n        struct RCand {\n            int nlen;\n            int id;\n            Insertion ins;\n        };\n        array<RCand, 6> top{};\n        int tsz = 0;\n\n        auto pushTop = [&](const RCand& c) {\n            if (tsz < 6) {\n                top[tsz++] = c;\n                for (int i = tsz - 1; i > 0; --i) {\n                    if (top[i].nlen < top[i - 1].nlen) swap(top[i], top[i - 1]);\n                    else break;\n                }\n            } else if (c.nlen < top[tsz - 1].nlen) {\n                top[tsz - 1] = c;\n                for (int i = tsz - 1; i > 0; --i) {\n                    if (top[i].nlen < top[i - 1].nlen) swap(top[i], top[i - 1]);\n                    else break;\n                }\n            }\n        };\n\n        for (int id : candIds) {\n            Insertion ins = bestInsertPair(tmp1, id);\n            int nlen = base + ins.delta;\n            pushTop(RCand{nlen, id, ins});\n        }\n\n        if (tsz == 0) return false;\n\n        int rr = rng.nextInt(100);\n        int choose = 0;\n        if (rr < 65) choose = 0;\n        else if (rr < 90) choose = rng.nextInt(min(tsz, 3));\n        else choose = rng.nextInt(tsz);\n\n        RCand ch = top[choose];\n        int diff = ch.nlen - s.len;\n        if (diff > 0) {\n            double prob = exp(-double(diff) / temp);\n            if (rng.nextDouble() >= prob) return false;\n        }\n\n        tmp2 = tmp1;\n        insertPair(tmp2, ch.ins, ch.id);\n\n        int idx = s.pos[oldId];\n        s.pos[oldId] = -1;\n        s.pos[ch.id] = idx;\n        s.sel[idx] = ch.id;\n\n        s.route.swap(tmp2);\n        s.len = ch.nlen;\n        return true;\n    }\n\n    bool applyBestGlobalReplace(State& s, int topOldLimit, double deadline) {\n        computeRemovalGainsFast(s);\n        topOldLimit = min(topOldLimit, (int)gains.size());\n\n        int globalBestLen = s.len;\n        int bestOld = -1, bestNew = -1;\n        Insertion bestIns{INT_MAX, 0, 1};\n\n        for (int t = 0; t < topOldLimit; ++t) {\n            if ((t & 1) == 0 && elapsed() >= deadline) break;\n\n            int oldId = gains[t].second;\n            int base = s.len - gains[t].first;\n\n            removeOrder(s.route, oldId, tmp1);\n\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                if ((id & 63) == 0 && elapsed() >= deadline) break;\n\n                Insertion ins = bestInsertPair(tmp1, id);\n                int nlen = base + ins.delta;\n                if (nlen < globalBestLen) {\n                    globalBestLen = nlen;\n                    bestOld = oldId;\n                    bestNew = id;\n                    bestIns = ins;\n                }\n            }\n        }\n\n        if (bestOld == -1) return false;\n\n        removeOrder(s.route, bestOld, tmp1);\n        tmp2 = tmp1;\n        insertPair(tmp2, bestIns, bestNew);\n\n        int idx = s.pos[bestOld];\n        s.pos[bestOld] = -1;\n        s.pos[bestNew] = idx;\n        s.sel[idx] = bestNew;\n\n        s.route.swap(tmp2);\n        s.len = globalBestLen;\n        return true;\n    }\n\n    void ruinRecreate(State& s, int k, int rcl, bool targeted) {\n        if (k <= 0) return;\n        rcl = max(1, rcl);\n\n        array<char, N> removed{};\n        removed.fill(0);\n\n        bool doneTargeted = false;\n        if (targeted) {\n            computeRemovalGainsFast(s);\n            int topRange = min((int)gains.size(), k + 12);\n            if (topRange > 0) {\n                int cnt = 0;\n                while (cnt < k) {\n                    int oid;\n                    int rr = rng.nextInt(100);\n                    if (rr < 50) oid = gains[cnt % topRange].second;\n                    else oid = gains[rng.nextInt(topRange)].second;\n\n                    if (removed[oid]) continue;\n                    removed[oid] = 1;\n                    ++cnt;\n                }\n                doneTargeted = true;\n            }\n        }\n\n        if (!doneTargeted) {\n            int cnt = 0;\n            while (cnt < k) {\n                int oid = s.sel[rng.nextInt((int)s.sel.size())];\n                if (removed[oid]) continue;\n                removed[oid] = 1;\n                ++cnt;\n            }\n        }\n\n        // remove\n        tmp1.clear();\n        tmp1.reserve((int)s.route.size() - 2 * k);\n        for (int v : s.route) {\n            int oid = (v < N ? v : v - N);\n            if (!removed[oid]) tmp1.push_back(v);\n        }\n        s.route.swap(tmp1);\n\n        // rebuild selection\n        vector<int> nsel;\n        nsel.reserve(M);\n        s.pos.fill(-1);\n        for (int oid : s.sel) {\n            if (!removed[oid]) {\n                s.pos[oid] = (int)nsel.size();\n                nsel.push_back(oid);\n            }\n        }\n        s.sel.swap(nsel);\n        s.len = calcLen(s.route);\n\n        // reinsert k\n        vector<Cand> top;\n        top.reserve(rcl + 1);\n\n        for (int step = 0; step < k; ++step) {\n            top.clear();\n\n            for (int id = 0; id < N; ++id) {\n                if (s.pos[id] != -1) continue;\n                if (removed[id]) continue;\n                Insertion ins = bestInsertPair(s.route, id);\n                pushTopCand(top, Cand{ins.delta, id, ins}, rcl);\n            }\n\n            if (top.empty()) {\n                for (int id = 0; id < N; ++id) {\n                    if (s.pos[id] == -1) {\n                        Insertion ins = bestInsertPair(s.route, id);\n                        top.push_back(Cand{ins.delta, id, ins});\n                        break;\n                    }\n                }\n            }\n\n            int pick = ((int)top.size() == 1 ? 0 : rng.nextInt((int)top.size()));\n            const Cand& ch = top[pick];\n\n            insertPair(s.route, ch.ins, ch.id);\n            s.len += ch.delta;\n            s.pos[ch.id] = (int)s.sel.size();\n            s.sel.push_back(ch.id);\n        }\n\n        s.len = calcLen(s.route);\n    }\n\n    void intensifyShort(State& s, double deadline) {\n        while (elapsed() < deadline) {\n            bool imp = false;\n            if (reverseSegmentPass(s, 1, deadline)) imp = true;\n            if (adjacentSwapPass(s, 1, deadline)) imp = true;\n            if (applyBestPairRelocate(s, 10, deadline)) imp = true;\n            if (rng.nextInt(100) < 50) {\n                if (relocateRandomK(s, 6)) imp = true;\n            }\n            if (!imp) break;\n        }\n    }\n\n    void finalImprove(State& s, double deadline) {\n        int stall = 0;\n        while (elapsed() < deadline && stall < 5) {\n            bool improved = false;\n\n            double d1 = min(deadline, elapsed() + 0.045);\n            while (elapsed() < d1) {\n                bool imp = false;\n                if (reverseSegmentPass(s, 1, d1)) imp = true;\n                if (adjacentSwapPass(s, 2, d1)) imp = true;\n                if (rng.nextInt(100) < 60 && bestEventSwapLocal(s, 1, d1)) imp = true;\n                if (applyBestPairRelocate(s, 18, d1)) imp = true;\n                if (relocatePass(s, d1)) imp = true;\n                if (!imp) break;\n                improved = true;\n            }\n\n            if (elapsed() < deadline) {\n                if (applyBestGlobalReplace(s, 10, deadline)) {\n                    improved = true;\n                    double d2 = min(deadline, elapsed() + 0.012);\n                    reverseSegmentPass(s, 1, d2);\n                    adjacentSwapPass(s, 2, d2);\n                    relocatePass(s, d2);\n                }\n            }\n\n            if (!improved) ++stall;\n            else stall = 0;\n        }\n\n        s.len = calcLen(s.route);\n    }\n\n    void output(const State& s) const {\n        cout << M;\n        for (int id : s.sel) cout << ' ' << (id + 1);\n        cout << '\\n';\n\n        int n = (int)s.route.size() + 2;\n        cout << n << ' ' << 400 << ' ' << 400;\n        for (int v : s.route) {\n            if (v < N) {\n                cout << ' ' << a[v] << ' ' << b[v];\n            } else {\n                int id = v - N;\n                cout << ' ' << c[id] << ' ' << d[id];\n            }\n        }\n        cout << ' ' << 400 << ' ' << 400 << '\\n';\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        t0 = chrono::steady_clock::now();\n\n        for (int i = 0; i < N; ++i) {\n            if (!(cin >> a[i] >> b[i] >> c[i] >> d[i])) return;\n        }\n\n        for (int i = 0; i < N; ++i) {\n            nodeX[i] = a[i];\n            nodeY[i] = b[i];\n            nodeX[i + N] = c[i];\n            nodeY[i + N] = d[i];\n\n            baseCost[i] =\n                abs(400 - a[i]) + abs(400 - b[i]) +\n                abs(a[i] - c[i]) + abs(b[i] - d[i]) +\n                abs(c[i] - 400) + abs(d[i] - 400);\n        }\n        nodeX[DEP] = 400;\n        nodeY[DEP] = 400;\n\n        for (int i = 0; i < TOT; ++i) {\n            for (int j = 0; j < TOT; ++j) {\n                DISTMAT[i][j] = (uint16_t)(abs(nodeX[i] - nodeX[j]) + abs(nodeY[i] - nodeY[j]));\n            }\n        }\n\n        sortedBase.resize(N);\n        iota(sortedBase.begin(), sortedBase.end(), 0);\n        sort(sortedBase.begin(), sortedBase.end(),\n             [&](int l, int r) { return baseCost[l] < baseCost[r]; });\n\n        buildNearForNode(DEP);\n\n        // ===== Initialization =====\n        State best = buildPureGreedyAll();\n\n        {\n            double d = min(TL * 0.07, elapsed() + 0.07);\n            reverseSegmentPass(best, 1, d);\n            adjacentSwapPass(best, 2, d);\n            applyBestPairRelocate(best, 20, d);\n            best.len = calcLen(best.route);\n        }\n\n        vector<int> rcls = {1, 2, 3, 5, 8};\n        int rp = 0;\n        double initEnd = min(0.32, TL * 0.21);\n\n        while (elapsed() < initEnd) {\n            int rcl = rcls[rp % (int)rcls.size()];\n            ++rp;\n\n            int poolBase = 280 + rng.nextInt(300); // 280..579\n            int randExtra = 32 + rng.nextInt(56);  // 32..87\n\n            State s = buildGRASP(rcl, poolBase, randExtra);\n\n            double d = min(initEnd, elapsed() + 0.015);\n            reverseSegmentPass(s, 1, d);\n            adjacentSwapPass(s, 1, d);\n            applyBestPairRelocate(s, 12, d);\n            relocatePass(s, d);\n\n            if (s.len < best.len) best = std::move(s);\n        }\n\n        State cur = best;\n\n        // ===== Main Search =====\n        int iter = 0, noBest = 0;\n        double mainEnd = TL - 0.20;\n        if (mainEnd < elapsed() + 0.15) mainEnd = TL - 0.10;\n\n        while (elapsed() < mainEnd) {\n            ++iter;\n            if ((iter & 127) == 0) cur.len = calcLen(cur.route);\n\n            double prog = elapsed() / max(0.1, mainEnd);\n            if (prog > 1.0) prog = 1.0;\n\n            double temp = 31.0 * (1.0 - prog) + 0.9;\n            if (noBest > 70) temp *= 1.30;\n\n            bool moved = false;\n            int mv = rng.nextInt(100);\n\n            if (mv < 70) {\n                int candTarget;\n                if (prog < 0.35) candTarget = 170;\n                else if (prog < 0.75) candTarget = 230;\n                else candTarget = 300;\n                if (noBest > 70) candTarget += 40;\n                moved = tryReplaceSampledSA(cur, temp, candTarget);\n            } else if (mv < 84) {\n                moved = relocateOrder(cur, cur.sel[rng.nextInt(M)]);\n            } else if (mv < 92) {\n                double d = min(mainEnd, elapsed() + 0.0018);\n                moved = adjacentSwapPass(cur, 1, d);\n            } else if (mv < 97) {\n                double d = min(mainEnd, elapsed() + 0.0025);\n                moved = bestEventSwapLocal(cur, 1, d);\n            } else {\n                double d = min(mainEnd, elapsed() + 0.0028);\n                moved = reverseSegmentPass(cur, 1, d);\n            }\n\n            if (!moved && rng.nextInt(100) < 25) {\n                relocateRandomK(cur, 2);\n            }\n\n            if ((iter % 52) == 0) {\n                double d = min(mainEnd, elapsed() + 0.010);\n                reverseSegmentPass(cur, 1, d);\n                adjacentSwapPass(cur, 1, d);\n                if (rng.nextInt(100) < 35) bestEventSwapLocal(cur, 1, d);\n                if (rng.nextInt(100) < 45) applyBestPairRelocate(cur, 10, d);\n                relocateRandomK(cur, 6);\n\n                if (prog > 0.84 && rng.nextInt(100) < 20) {\n                    applyBestGlobalReplace(cur, 2, d);\n                }\n            }\n\n            if (prog > 0.80 && (iter % 28) == 0) {\n                double d = min(mainEnd, elapsed() + 0.008);\n                applyBestPairRelocate(cur, 12, d);\n            }\n\n            if (cur.len < best.len) {\n                best = cur;\n                noBest = 0;\n            } else {\n                ++noBest;\n            }\n\n            if (noBest > 95 && elapsed() < mainEnd - 0.05) {\n                bool escaped = false;\n\n                // quick intensify current\n                {\n                    State cand = cur;\n                    double d1 = min(mainEnd, elapsed() + 0.028);\n                    bool imp = false;\n                    if (reverseSegmentPass(cand, 2, d1)) imp = true;\n                    if (adjacentSwapPass(cand, 2, d1)) imp = true;\n                    if (bestEventSwapLocal(cand, 1, d1)) imp = true;\n                    if (applyBestPairRelocate(cand, 16, d1)) imp = true;\n                    if (relocatePass(cand, d1)) imp = true;\n                    if (elapsed() < d1 && rng.nextInt(100) < 40) {\n                        if (applyBestGlobalReplace(cand, 4, d1)) imp = true;\n                    }\n\n                    if (imp && cand.len < cur.len) {\n                        cur = cand;\n                        escaped = true;\n                    }\n                    if (cand.len < best.len) {\n                        best = cand;\n                        escaped = true;\n                    }\n                }\n\n                // targeted ruin/recreate\n                if (!escaped || rng.nextInt(100) < 75) {\n                    State cand = best;\n                    int rr = rng.nextInt(100);\n                    int k = (rr < 70 ? 2 : (rr < 93 ? 3 : 4));\n                    ruinRecreate(cand, k, (k == 2 ? 4 : 3), true);\n\n                    double d = min(mainEnd, elapsed() + 0.042);\n                    intensifyShort(cand, d);\n\n                    if (elapsed() < d) {\n                        if (rng.nextInt(100) < 50) bestEventSwapLocal(cand, 1, d);\n                        applyBestPairRelocate(cand, 14, d);\n                        if (rng.nextInt(100) < 45) applyBestGlobalReplace(cand, 6, d);\n                    }\n\n                    if (cand.len < cur.len || rng.nextInt(100) < 35) cur = cand;\n                    if (cand.len < best.len) best = cand;\n                }\n\n                noBest = 0;\n            }\n\n            if ((iter & 255) == 0 && cur.len > best.len + 340) {\n                cur = best;\n            }\n        }\n\n        // ===== Final Intensification =====\n        State ans = best;\n        double finalEnd = TL - 0.001;\n        finalImprove(ans, finalEnd);\n\n        if (elapsed() < finalEnd - 0.05) {\n            State cand = ans;\n            ruinRecreate(cand, 2, 3, true);\n\n            double d = min(finalEnd, elapsed() + 0.050);\n            intensifyShort(cand, d);\n\n            if (elapsed() < d) {\n                bestEventSwapLocal(cand, 1, d);\n                applyBestPairRelocate(cand, 16, d);\n                applyBestGlobalReplace(cand, 8, d);\n            }\n\n            if (cand.len < ans.len) ans = cand;\n        }\n\n        ans.len = calcLen(ans.route);\n        output(ans);\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\nstatic constexpr int MC = 56;          // best proven family\nstatic constexpr int HALF = MC / 2;\nstatic constexpr int INF = 1e9;\nstatic_assert(MC % 2 == 0);\n\nstruct DSU {\n    int16_t par[N]; // root: -size, else parent\n\n    inline void init() {\n        for (int i = 0; i < N; ++i) par[i] = -1;\n    }\n\n    inline int find(int x) {\n        while (par[x] >= 0) {\n            int p = par[x];\n            if (par[p] >= 0) par[x] = par[p];\n            x = p;\n        }\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n\n    inline bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (par[a] > par[b]) swap(a, b); // more negative => larger\n        par[a] += par[b];\n        par[b] = (int16_t)a;\n        return true;\n    }\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n\n    inline int next_int(int l, int r) { // inclusive\n        return l + (int)(next_u32() % (uint32_t)(r - l + 1));\n    }\n};\n\nint EU[M], EV[M], ED[M];\narray<uint16_t, M> ORDER_D;\narray<array<uint16_t, M>, MC> SC_W, SC_ORD, SC_SW;\n\n// Deterministic bottleneck in d-space over future edges only.\n// If INF => u-v cannot be connected without current edge (mandatory adopt).\ninline int det_bottleneck_d(const DSU& base, int idx, int u, int v) {\n    DSU uf = base;\n    int cu = uf.find(u), cv = uf.find(v);\n\n    for (int k = 0; k < M; ++k) {\n        int eid = ORDER_D[k];\n        if (eid <= idx) continue; // future only\n\n        int a = uf.find(EU[eid]);\n        int b = uf.find(EV[eid]);\n        if (a == b) continue;\n\n        bool touch_u = (a == cu || b == cu);\n        bool touch_v = (a == cv || b == cv);\n\n        if (uf.par[a] > uf.par[b]) swap(a, b);\n        uf.par[a] += uf.par[b];\n        uf.par[b] = (int16_t)a;\n\n        if (touch_u) cu = a;\n        if (touch_v) cv = a;\n\n        if (cu == cv) return ED[eid];\n    }\n    return INF;\n}\n\n// One scenario gain = bottleneck(sampled) - li\ninline int scen_gain(const DSU& base, int idx, int u, int v, int li, int ub, int s) {\n    DSU uf = base;\n    int cu = uf.find(u), cv = uf.find(v);\n\n    const auto& ord = SC_ORD[s];\n    const auto& sw = SC_SW[s];\n    int lim = (int)(upper_bound(sw.begin(), sw.end(), (uint16_t)ub) - sw.begin());\n\n    for (int k = 0; k < lim; ++k) {\n        int eid = ord[k];\n        if (eid <= idx) continue; // future only\n\n        int a = uf.find(EU[eid]);\n        int b = uf.find(EV[eid]);\n        if (a == b) continue;\n\n        bool touch_u = (a == cu || b == cu);\n        bool touch_v = (a == cv || b == cv);\n\n        if (uf.par[a] > uf.par[b]) swap(a, b);\n        uf.par[a] += uf.par[b];\n        uf.par[b] = (int16_t)a;\n\n        if (touch_u) cu = a;\n        if (touch_v) cv = a;\n\n        if (cu == cv) return (int)sw[k] - li;\n    }\n\n    // Rare fallback\n    return ub - li;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int xs[N], ys[N];\n    for (int i = 0; i < N; ++i) {\n        if (!(cin >> xs[i] >> ys[i])) return 0;\n    }\n\n    for (int i = 0; i < M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        EU[i] = u;\n        EV[i] = v;\n        long long dx = (long long)xs[u] - xs[v];\n        long long dy = (long long)ys[u] - ys[v];\n        ED[i] = (int)llround(sqrt((long double)dx * dx + (long double)dy * dy));\n    }\n\n    // Order by d\n    for (int i = 0; i < M; ++i) ORDER_D[i] = (uint16_t)i;\n    sort(ORDER_D.begin(), ORDER_D.end(), [](uint16_t a, uint16_t b) {\n        if (ED[a] != ED[b]) return ED[a] < ED[b];\n        return a < b;\n    });\n\n    // Stratified + antithetic scenario generation\n    XorShift64 rng(0x123456789ABCDEFULL);\n\n    for (int i = 0; i < M; ++i) {\n        int d = ED[i];\n        int n = 2 * d + 1; // offsets in [0, n-1]\n\n        array<int, HALF> q{};\n        for (int t = 0; t < HALF; ++t) {\n            int lo = (int)((1LL * t * n) / HALF);\n            int hi = (int)((1LL * (t + 1) * n) / HALF - 1);\n            if (hi < lo) hi = lo;\n            q[t] = rng.next_int(lo, hi);\n        }\n\n        for (int t = HALF - 1; t >= 1; --t) {\n            int j = (int)(rng.next_u32() % (uint32_t)(t + 1));\n            swap(q[t], q[j]);\n        }\n\n        for (int t = 0; t < HALF; ++t) {\n            int w1 = d + q[t];\n            int w2 = d + (n - 1 - q[t]); // antithetic\n            SC_W[t][i] = (uint16_t)w1;\n            SC_W[t + HALF][i] = (uint16_t)w2;\n        }\n    }\n\n    // Sort each scenario by sampled weight\n    for (int s = 0; s < MC; ++s) {\n        for (int i = 0; i < M; ++i) SC_ORD[s][i] = (uint16_t)i;\n        auto& ord = SC_ORD[s];\n        auto& w = SC_W[s];\n\n        sort(ord.begin(), ord.end(), [&](uint16_t a, uint16_t b) {\n            if (w[a] != w[b]) return w[a] < w[b];\n            return a < b;\n        });\n\n        for (int k = 0; k < M; ++k) SC_SW[s][k] = w[ord[k]];\n    }\n\n    DSU uf;\n    uf.init();\n\n    constexpr long long HARD_TIE_EPS = MC / 2; // as before\n    constexpr double Z_FALLBACK = 0.9;         // confidence threshold\n\n    for (int i = 0; i < M; ++i) {\n        int li;\n        if (!(cin >> li)) return 0;\n\n        int u = EU[i], v = EV[i];\n        int ans = 0;\n\n        // Cycle edge in selected forest is always useless.\n        if (!uf.same(u, v)) {\n            int L = det_bottleneck_d(uf, i, u, v);\n\n            if (L == INF) {\n                ans = 1; // mandatory\n            } else if (li <= L) {\n                ans = 1; // always beneficial\n            } else if (li >= 3 * L) {\n                ans = 0; // always non-beneficial\n            } else {\n                long long sum = 0;\n                long long sq = 0;\n                int ub = 3 * L;\n\n                for (int s = 0; s < MC; ++s) {\n                    int g = scen_gain(uf, i, u, v, li, ub, s);\n                    sum += g;\n                    sq += 1LL * g * g;\n                }\n\n                double mean = (double)sum / MC;\n                double var = (double)sq / MC - mean * mean;\n                if (var < 0.0) var = 0.0;\n                double se = sqrt(var / MC);\n\n                bool low_conf = (se > 1e-12 && fabs(mean) <= Z_FALLBACK * se);\n                if (low_conf || llabs(sum) <= HARD_TIE_EPS) {\n                    ans = (li <= 2 * L) ? 1 : 0;\n                } else {\n                    ans = (sum > 0) ? 1 : 0;\n                }\n            }\n        } else {\n            ans = 0;\n        }\n\n        if (ans == 1) uf.unite(u, v);\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int r, c; };\nbool operator==(const Pos& a, const Pos& b){ return a.r == b.r && a.c == b.c; }\n\nstatic constexpr int BOARD = 30;\nstatic constexpr int BASE = 31;\nstatic constexpr int SZ = BASE * BASE;\nstatic constexpr long long INF64 = (1LL << 60);\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar MOVE_CH[4] = {'U', 'D', 'L', 'R'};\n\ninline bool inBoard(int r, int c){ return 1 <= r && r <= BOARD && 1 <= c && c <= BOARD; }\ninline bool inBoard(const Pos& p){ return inBoard(p.r, p.c); }\ninline int pid(int r, int c){ return r * BASE + c; }\ninline int pid(const Pos& p){ return pid(p.r, p.c); }\nint manhattan(const Pos& a, const Pos& b){ return abs(a.r - b.r) + abs(a.c - b.c); }\n\nint dirFromUpper(char ch){\n    if(ch == 'U') return 0;\n    if(ch == 'D') return 1;\n    if(ch == 'L') return 2;\n    if(ch == 'R') return 3;\n    return -1;\n}\nint dirFromLower(char ch){\n    if(ch == 'u') return 0;\n    if(ch == 'd') return 1;\n    if(ch == 'l') return 2;\n    if(ch == 'r') return 3;\n    return -1;\n}\nchar lowerFromDelta(int dr, int dc){\n    if(dr == -1 && dc == 0) return 'u';\n    if(dr == 1 && dc == 0) return 'd';\n    if(dr == 0 && dc == -1) return 'l';\n    if(dr == 0 && dc == 1) return 'r';\n    return '.';\n}\nPos moved(const Pos& p, int d){ return Pos{p.r + DR[d], p.c + DC[d]}; }\n\nint petWeight(int t){\n    if(t == 1) return 1; // cow\n    if(t == 2) return 2; // pig\n    if(t == 3) return 3; // rabbit\n    if(t == 4) return 2; // dog\n    return 2;            // cat\n}\n\nstruct WallTask {\n    Pos target;\n    Pos standOut;\n    Pos standIn;\n    char buildOut;\n    char buildIn;\n};\n\nstruct RegionPlan {\n    int corner = 0; // 0:TL 1:TR 2:BL 3:BR\n    int s = 6;\n    vector<WallTask> tasks;\n    int gateIdx = 0;\n    Pos safeCell{1,1};\n    Pos decoyCell{30,30};\n\n    bool inRegion(const Pos& p) const {\n        if(corner == 0){\n            return (1 <= p.r && p.r <= s && 1 <= p.c && p.c <= s);\n        }else if(corner == 1){\n            int cL = 31 - s;\n            return (1 <= p.r && p.r <= s && cL <= p.c && p.c <= 30);\n        }else if(corner == 2){\n            int rT = 31 - s;\n            return (rT <= p.r && p.r <= 30 && 1 <= p.c && p.c <= s);\n        }else{\n            int rT = 31 - s;\n            int cL = 31 - s;\n            return (rT <= p.r && p.r <= 30 && cL <= p.c && p.c <= 30);\n        }\n    }\n};\n\nclass Solver {\npublic:\n    void run();\n\nprivate:\n    int N = 0, M = 0;\n    vector<Pos> pets;\n    vector<int> petType;\n    vector<Pos> humans;\n    bool passable[31][31]{};\n\n    RegionPlan plan;\n\n    enum Phase { BUILD, ENTER, CLOSE, DONE };\n    Phase phase = BUILD;\n\n    int gateCloser = -1;\n    int attemptCnt = 0;\n    int lastReplanTurn = -1000;\n    int lastBuiltCnt = 0;\n    int stallTurns = 0;\n    int closeStartTurn = -1;\n    int targetInside = 1;\n\n    // basics\n    void buildCounts(int humanCnt[31][31], int petCnt[31][31]) const;\n    bool canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const;\n\n    // path\n    void runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const;\n    void computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const;\n    char moveToward(int i, const Pos& target,\n                    const vector<array<int,SZ>>& dist,\n                    const vector<array<int,SZ>>& first) const;\n\n    // planning\n    RegionPlan generatePlan(int corner, int s) const;\n    void computeComponents(int compId[31][31], vector<int>& humCompCnt) const;\n    bool reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const;\n    long long evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                const int compId[31][31], const vector<int>& humCompCnt) const;\n    RegionPlan choosePlan(bool emergency, int avoidCorner) const;\n\n    // plan stats\n    int countInsideHumans(const RegionPlan& p) const;\n    int countInsidePets(const RegionPlan& p) const;\n    int builtNonGateWalls(const RegionPlan& p) const;\n    int remainingNonGateWalls(const RegionPlan& p) const;\n\n    // phase / replan\n    bool isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const;\n    int computeTargetInside(int turn, int insidePets, bool pressure) const;\n    void updatePhase(int turn, const int petCnt[31][31]);\n    bool shouldReplan(int turn, const int petCnt[31][31]) const;\n    bool replan(int turn);\n\n    // action generation\n    vector<char> decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]);\n    vector<char> decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]);\n\n    // simulation\n    void sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const;\n    void applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]);\n    void applyPetMoves(const vector<string>& pMoves);\n};\n\nvoid Solver::buildCounts(int humanCnt[31][31], int petCnt[31][31]) const {\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            humanCnt[r][c] = 0;\n            petCnt[r][c] = 0;\n        }\n    }\n    for(const auto& h: humans) humanCnt[h.r][h.c]++;\n    for(const auto& p: pets) petCnt[p.r][p.c]++;\n}\n\nbool Solver::canBuildCell(const Pos& t, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    if(!inBoard(t)) return false;\n    if(humanCnt[t.r][t.c] > 0) return false;\n    if(petCnt[t.r][t.c] > 0) return false;\n    for(int d=0; d<4; d++){\n        int nr = t.r + DR[d], nc = t.c + DC[d];\n        if(!inBoard(nr, nc)) continue;\n        if(petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nvoid Solver::runBFS(const Pos& st, array<int,SZ>& dist, array<int,SZ>& first) const {\n    dist.fill(-1);\n    first.fill(-1);\n    queue<Pos> q;\n    dist[pid(st)] = 0;\n    q.push(st);\n\n    while(!q.empty()){\n        Pos cur = q.front(); q.pop();\n        int cid = pid(cur);\n        for(int d=0; d<4; d++){\n            Pos nx{cur.r + DR[d], cur.c + DC[d]};\n            if(!inBoard(nx)) continue;\n            if(!passable[nx.r][nx.c]) continue;\n            int nid = pid(nx);\n            if(dist[nid] != -1) continue;\n            dist[nid] = dist[cid] + 1;\n            first[nid] = (cur == st ? d : first[cid]);\n            q.push(nx);\n        }\n    }\n}\n\nvoid Solver::computeAllBFS(vector<array<int,SZ>>& dist, vector<array<int,SZ>>& first) const {\n    dist.resize(M);\n    first.resize(M);\n    for(int i=0; i<M; i++) runBFS(humans[i], dist[i], first[i]);\n}\n\nchar Solver::moveToward(int i, const Pos& target,\n                        const vector<array<int,SZ>>& dist,\n                        const vector<array<int,SZ>>& first) const {\n    if(!inBoard(target) || !passable[target.r][target.c]) return '.';\n    if(humans[i] == target) return '.';\n    int d = dist[i][pid(target)];\n    if(d <= 0) return '.';\n    int fd = first[i][pid(target)];\n    if(fd < 0) return '.';\n    return MOVE_CH[fd];\n}\n\nRegionPlan Solver::generatePlan(int corner, int s) const {\n    RegionPlan p;\n    p.corner = corner;\n    p.s = s;\n    p.tasks.clear();\n\n    auto addTask = [&](Pos target, Pos standOut, Pos standIn){\n        WallTask t;\n        t.target = target;\n        t.standOut = standOut;\n        t.standIn = standIn;\n        t.buildOut = lowerFromDelta(target.r - standOut.r, target.c - standOut.c);\n        t.buildIn = lowerFromDelta(target.r - standIn.r, target.c - standIn.c);\n        p.tasks.push_back(t);\n    };\n\n    Pos gate{-1,-1};\n\n    if(corner == 0){\n        for(int c=1; c<=s; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{s+1,1};\n        p.safeCell = Pos{1,1};\n        p.decoyCell = Pos{30,30};\n    }else if(corner == 1){\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{s+1,c}, Pos{s+2,c}, Pos{s,c});\n        for(int r=1; r<=s; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{s+1,30};\n        p.safeCell = Pos{1,30};\n        p.decoyCell = Pos{30,1};\n    }else if(corner == 2){\n        int rT = 30 - s;\n        for(int c=1; c<=s; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,s+1}, Pos{r,s+2}, Pos{r,s});\n        gate = Pos{rT,1};\n        p.safeCell = Pos{30,1};\n        p.decoyCell = Pos{1,30};\n    }else{\n        int rT = 30 - s;\n        int cL = 30 - s;\n        for(int c=31-s; c<=30; c++) addTask(Pos{rT,c}, Pos{rT-1,c}, Pos{rT+1,c});\n        for(int r=31-s; r<=30; r++) addTask(Pos{r,cL}, Pos{r,cL-1}, Pos{r,cL+1});\n        gate = Pos{rT,30};\n        p.safeCell = Pos{30,30};\n        p.decoyCell = Pos{1,1};\n    }\n\n    p.gateIdx = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(p.tasks[i].target == gate){\n            p.gateIdx = i;\n            break;\n        }\n    }\n    return p;\n}\n\nvoid Solver::computeComponents(int compId[31][31], vector<int>& humCompCnt) const {\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) compId[r][c] = 0;\n\n    int cid = 0;\n    queue<Pos> q;\n    for(int r=1; r<=BOARD; r++){\n        for(int c=1; c<=BOARD; c++){\n            if(!passable[r][c] || compId[r][c] != 0) continue;\n            cid++;\n            compId[r][c] = cid;\n            q.push(Pos{r,c});\n            while(!q.empty()){\n                Pos cur = q.front(); q.pop();\n                for(int d=0; d<4; d++){\n                    int nr = cur.r + DR[d], nc = cur.c + DC[d];\n                    if(!inBoard(nr,nc) || !passable[nr][nc] || compId[nr][nc] != 0) continue;\n                    compId[nr][nc] = cid;\n                    q.push(Pos{nr,nc});\n                }\n            }\n        }\n    }\n\n    humCompCnt.assign(cid + 1, 0);\n    for(const auto& h: humans){\n        if(!passable[h.r][h.c]) continue;\n        int id = compId[h.r][h.c];\n        if(id >= 1 && id < (int)humCompCnt.size()) humCompCnt[id]++;\n    }\n}\n\nbool Solver::reachableByHuman(const Pos& p, const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(!inBoard(p) || !passable[p.r][p.c]) return false;\n    int id = compId[p.r][p.c];\n    if(id <= 0 || id >= (int)humCompCnt.size()) return false;\n    return humCompCnt[id] > 0;\n}\n\nlong long Solver::evaluateCandidate(const RegionPlan& p, bool emergency, int avoidCorner,\n                                    const int compId[31][31], const vector<int>& humCompCnt) const {\n    if(p.tasks.empty()) return INF64/2;\n    const WallTask& gate = p.tasks[p.gateIdx];\n\n    if(!inBoard(gate.target) || !passable[gate.target.r][gate.target.c]) return INF64/2;\n    if(!(reachableByHuman(gate.standIn, compId, humCompCnt) ||\n         reachableByHuman(gate.standOut, compId, humCompCnt))) return INF64/2;\n\n    int insidePets = 0, insidePetsW = 0;\n    int nearBoundary = 0, nearGate = 0;\n\n    for(int i=0; i<N; i++){\n        const Pos& pet = pets[i];\n        int w = petWeight(petType[i]);\n\n        if(p.inRegion(pet)){\n            insidePets++;\n            insidePetsW += w;\n        }\n\n        int md = 100;\n        for(const auto& t: p.tasks) md = min(md, manhattan(pet, t.target));\n        if(md <= 1) nearBoundary += 2*w;\n        else if(md == 2) nearBoundary += w;\n\n        if(manhattan(pet, gate.target) <= 2) nearGate += w;\n    }\n\n    int remaining = 0, impossible = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i];\n        if(!passable[t.target.r][t.target.c]) continue;\n        remaining++;\n        bool okOut = reachableByHuman(t.standOut, compId, humCompCnt);\n        bool okIn  = reachableByHuman(t.standIn, compId, humCompCnt);\n        if(!okOut && !okIn) impossible++;\n    }\n\n    int interiorWalls = 0;\n    if(p.corner == 0){\n        for(int r=1; r<=p.s; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 1){\n        int cL = 31 - p.s;\n        for(int r=1; r<=p.s; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }else if(p.corner == 2){\n        int rT = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=1; c<=p.s; c++) if(!passable[r][c]) interiorWalls++;\n    }else{\n        int rT = 31 - p.s, cL = 31 - p.s;\n        for(int r=rT; r<=30; r++) for(int c=cL; c<=30; c++) if(!passable[r][c]) interiorWalls++;\n    }\n\n    long long humDist = 0;\n    for(const auto& h: humans) humDist += manhattan(h, gate.standOut);\n\n    long long score = 0;\n    score += 300000000LL * insidePets;\n    score +=  50000000LL * insidePetsW;\n    score +=    900000LL * nearGate;\n    score +=    250000LL * nearBoundary;\n    score +=  40000000LL * impossible;\n    score +=      4000LL * remaining;\n    score +=       120LL * humDist;\n    score +=    350000LL * interiorWalls;\n    score -= (emergency ? 1700LL : 3000LL) * p.s * p.s;\n\n    if(!passable[p.safeCell.r][p.safeCell.c]) score += 8000000LL;\n    if(avoidCorner >= 0 && p.corner == avoidCorner){\n        score += (emergency ? 300000LL : 1200000LL);\n    }\n    return score;\n}\n\nRegionPlan Solver::choosePlan(bool emergency, int avoidCorner) const {\n    int compId[31][31];\n    vector<int> humCompCnt;\n    computeComponents(compId, humCompCnt);\n\n    int sL = emergency ? 4 : 6;\n    int sR = emergency ? 7 : 10;\n\n    long long bestScore = INF64;\n    RegionPlan bestPlan;\n    bool found = false;\n\n    for(int corner=0; corner<4; corner++){\n        for(int s=sL; s<=sR; s++){\n            RegionPlan cand = generatePlan(corner, s);\n            long long sc = evaluateCandidate(cand, emergency, avoidCorner, compId, humCompCnt);\n            if(sc >= INF64/4) continue;\n            if(!found || sc < bestScore){\n                found = true;\n                bestScore = sc;\n                bestPlan = cand;\n            }\n        }\n    }\n\n    if(found) return bestPlan;\n    if(!plan.tasks.empty()) return plan;\n    return generatePlan(0, emergency ? 4 : 6);\n}\n\nint Solver::countInsideHumans(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& h: humans) if(p.inRegion(h)) cnt++;\n    return cnt;\n}\n\nint Solver::countInsidePets(const RegionPlan& p) const {\n    int cnt = 0;\n    for(const auto& x: pets) if(p.inRegion(x)) cnt++;\n    return cnt;\n}\n\nint Solver::builtNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int b = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(!passable[t.r][t.c]) b++;\n    }\n    return b;\n}\n\nint Solver::remainingNonGateWalls(const RegionPlan& p) const {\n    if(p.tasks.empty()) return 0;\n    int rem = 0;\n    for(int i=0; i<(int)p.tasks.size(); i++){\n        if(i == p.gateIdx) continue;\n        const auto& t = p.tasks[i].target;\n        if(passable[t.r][t.c]) rem++;\n    }\n    return rem;\n}\n\nbool Solver::isGatePressured(const RegionPlan& p, const int petCnt[31][31]) const {\n    const Pos& g = p.tasks[p.gateIdx].target;\n    for(int r=max(1, g.r-2); r<=min(30, g.r+2); r++){\n        for(int c=max(1, g.c-2); c<=min(30, g.c+2); c++){\n            if(abs(r-g.r) + abs(c-g.c) > 2) continue;\n            if(petCnt[r][c] > 0) return true;\n        }\n    }\n    return false;\n}\n\nint Solver::computeTargetInside(int turn, int insidePets, bool pressure) const {\n    int t = max(1, M-1);\n    if(pressure) t = max(1, M-2);\n    if(insidePets >= 1) t = max(1, M-2);\n    if(turn >= 240) t = max(1, M-2);\n    if(turn >= 270) t = max(1, M-3);\n    if(turn >= 290) t = 1;\n    return min(t, M);\n}\n\nvoid Solver::updatePhase(int turn, const int petCnt[31][31]) {\n    if(phase == BUILD){\n        if(remainingNonGateWalls(plan) == 0){\n            phase = ENTER;\n            gateCloser = -1;\n            targetInside = max(1, M-1);\n        }\n    }\n\n    if(phase == ENTER){\n        int insideHum = countInsideHumans(plan);\n        int insidePets = countInsidePets(plan);\n        bool pressure = isGatePressured(plan, petCnt) || (insidePets > 0);\n        targetInside = computeTargetInside(turn, insidePets, pressure);\n\n        if(insideHum >= targetInside || (turn >= 289 && insideHum >= 1)){\n            phase = CLOSE;\n            closeStartTurn = turn;\n        }\n    }\n\n    if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(!passable[gt.r][gt.c]) phase = DONE;\n    }\n}\n\nbool Solver::shouldReplan(int turn, const int petCnt[31][31]) const {\n    if(phase == DONE) return false;\n    if(attemptCnt >= 2) return false;\n    if(turn - lastReplanTurn < 20) return false;\n\n    int rem = remainingNonGateWalls(plan);\n    int insidePets = countInsidePets(plan);\n    bool pressure = isGatePressured(plan, petCnt);\n\n    if(phase == BUILD){\n        if(rem > 0 && turn >= 190) return true;\n        if(rem > 0 && stallTurns >= 30 && turn <= 245) return true;\n        if(insidePets >= 2 && turn <= 175) return true;\n    }else if(phase == ENTER){\n        if(insidePets >= 2 && turn <= 220) return true;\n        if(turn >= 250 && countInsideHumans(plan) < max(1, M-2)) return true;\n    }else if(phase == CLOSE){\n        const Pos& gt = plan.tasks[plan.gateIdx].target;\n        if(passable[gt.r][gt.c] && closeStartTurn >= 0 &&\n           (turn - closeStartTurn) >= 40 && pressure && turn <= 245){\n            return true;\n        }\n    }\n    return false;\n}\n\nbool Solver::replan(int turn) {\n    bool emergency = (turn >= 140 || attemptCnt >= 1);\n    int avoid = plan.corner;\n    RegionPlan np = choosePlan(emergency, avoid);\n\n    if(np.corner == plan.corner && np.s == plan.s){\n        lastReplanTurn = turn; // cooldown\n        return false;\n    }\n\n    plan = np;\n    phase = BUILD;\n    gateCloser = -1;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n\n    attemptCnt++;\n    lastReplanTurn = turn;\n\n    if(remainingNonGateWalls(plan) == 0) phase = ENTER;\n    return true;\n}\n\nvector<char> Solver::decideBuildActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n\n    vector<int> remaining;\n    for(int i=0; i<(int)plan.tasks.size(); i++){\n        if(i == plan.gateIdx) continue;\n        const Pos& t = plan.tasks[i].target;\n        if(passable[t.r][t.c]) remaining.push_back(i);\n    }\n    if(remaining.empty()) return act;\n\n    vector<char> isBuildable(plan.tasks.size(), 0);\n    vector<int> buildable;\n    for(int idx: remaining){\n        if(canBuildCell(plan.tasks[idx].target, humanCnt, petCnt)){\n            isBuildable[idx] = 1;\n            buildable.push_back(idx);\n        }\n    }\n\n    const vector<int>& cand = (!buildable.empty() ? buildable : remaining);\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    bool reserved[31][31]{};\n    vector<int> useCnt(plan.tasks.size(), 0);\n\n    // immediate build\n    for(int i=0; i<M; i++){\n        for(int idx: cand){\n            if(!isBuildable[idx]) continue;\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n\n            if(humans[i] == t.standOut){\n                act[i] = t.buildOut;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n            if(humans[i] == t.standIn){\n                act[i] = t.buildIn;\n                reserved[t.target.r][t.target.c] = true;\n                useCnt[idx]++;\n                break;\n            }\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(act[i] != '.') continue;\n\n        int bestCost = 1e9;\n        int bestIdx = -1, bestMode = 0, bestD = -1;\n\n        for(int idx: cand){\n            const auto& t = plan.tasks[idx];\n            if(reserved[t.target.r][t.target.c]) continue;\n            bool buildNow = isBuildable[idx];\n\n            for(int mode=0; mode<2; mode++){\n                Pos st = (mode == 0 ? t.standOut : t.standIn);\n                if(!inBoard(st) || !passable[st.r][st.c]) continue;\n                int d = dist[i][pid(st)];\n                if(d < 0) continue;\n                if(d == 0 && !buildNow) continue;\n\n                int cost = d*10 + useCnt[idx]*18 + (mode==1 ? 8 : 0) + (buildNow ? 0 : 30);\n                if(cost < bestCost){\n                    bestCost = cost;\n                    bestIdx = idx;\n                    bestMode = mode;\n                    bestD = d;\n                }\n            }\n        }\n\n        if(bestIdx == -1) continue;\n\n        useCnt[bestIdx]++;\n        const auto& t = plan.tasks[bestIdx];\n        bool buildNow = isBuildable[bestIdx];\n\n        if(bestD == 0 && buildNow && !reserved[t.target.r][t.target.c]){\n            act[i] = (bestMode == 0 ? t.buildOut : t.buildIn);\n            reserved[t.target.r][t.target.c] = true;\n        }else if(bestD > 0){\n            Pos st = (bestMode == 0 ? t.standOut : t.standIn);\n            int fd = first[i][pid(st)];\n            if(fd >= 0) act[i] = MOVE_CH[fd];\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideEnterActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)humanCnt;\n    (void)petCnt;\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b){\n        int da = dist[a][pid(gate.standIn)];\n        int db = dist[b][pid(gate.standIn)];\n        bool ra = (da >= 0), rb = (db >= 0);\n        if(ra != rb) return ra > rb;\n\n        bool ia = plan.inRegion(humans[a]);\n        bool ib = plan.inRegion(humans[b]);\n        if(ia != ib) return ia > ib;\n\n        int ka = ra ? da : 1000000;\n        int kb = rb ? db : 1000000;\n        if(ka != kb) return ka < kb;\n        return a < b;\n    });\n\n    vector<char> insideSet(M, 0);\n    int need = max(1, min(targetInside, M));\n    int got = 0;\n    for(int id: ord){\n        int d = dist[id][pid(gate.standIn)];\n        bool can = (d >= 0) || plan.inRegion(humans[id]);\n        if(!can) continue;\n        insideSet[id] = 1;\n        got++;\n        if(got >= need) break;\n    }\n\n    if(got == 0){\n        int fb = -1, best = 1e9;\n        for(int i=0; i<M; i++){\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; fb = i; }\n        }\n        if(fb == -1) fb = 0;\n        insideSet[fb] = 1;\n    }\n\n    gateCloser = -1;\n    int best = 1e9;\n    for(int i=0; i<M; i++){\n        if(!insideSet[i]) continue;\n        int d = dist[i][pid(gate.standIn)];\n        if(d >= 0 && d < best){ best = d; gateCloser = i; }\n    }\n    if(gateCloser == -1){\n        best = 1e9;\n        for(int i=0; i<M; i++){\n            if(!insideSet[i]) continue;\n            int d = dist[i][pid(gate.standOut)];\n            if(d >= 0 && d < best){ best = d; gateCloser = i; }\n        }\n    }\n    if(gateCloser == -1){\n        for(int i=0; i<M; i++) if(insideSet[i]) { gateCloser = i; break; }\n        if(gateCloser == -1) gateCloser = 0;\n    }\n\n    for(int i=0; i<M; i++){\n        if(insideSet[i]){\n            Pos tgt;\n            if(i == gateCloser){\n                tgt = gate.standIn;\n                if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n            }else{\n                if(plan.inRegion(humans[i])) tgt = plan.safeCell;\n                else{\n                    tgt = gate.standIn;\n                    if(dist[i][pid(tgt)] < 0) tgt = gate.standOut;\n                }\n            }\n            act[i] = moveToward(i, tgt, dist, first);\n        }else{\n            act[i] = moveToward(i, plan.decoyCell, dist, first);\n        }\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideCloseActions(const int humanCnt[31][31], const int petCnt[31][31]) {\n    vector<char> act(M, '.');\n    const auto& gate = plan.tasks[plan.gateIdx];\n\n    vector<array<int,SZ>> dist, first;\n    computeAllBFS(dist, first);\n\n    int builder = -1;\n    int buildSide = 0; // 0=in 1=out\n    int bestCost = 1e9;\n\n    for(int i=0; i<M; i++){\n        for(int side=0; side<2; side++){\n            Pos st = (side == 0 ? gate.standIn : gate.standOut);\n            if(!inBoard(st) || !passable[st.r][st.c]) continue;\n            int d = dist[i][pid(st)];\n            if(d < 0) continue;\n\n            int cost = d*10 + (side==1 ? 4 : 0);\n            if(gateCloser >= 0 && i != gateCloser) cost += 2;\n            if(!plan.inRegion(humans[i])) cost += 1;\n            if(d == 0 && canBuildCell(gate.target, humanCnt, petCnt)) cost -= 1000;\n\n            if(cost < bestCost){\n                bestCost = cost;\n                builder = i;\n                buildSide = side;\n            }\n        }\n    }\n\n    if(builder != -1){\n        Pos st = (buildSide == 0 ? gate.standIn : gate.standOut);\n        if(humans[builder] == st){\n            if(canBuildCell(gate.target, humanCnt, petCnt)){\n                act[builder] = (buildSide == 0 ? gate.buildIn : gate.buildOut);\n            }\n        }else{\n            act[builder] = moveToward(builder, st, dist, first);\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        if(i == builder) continue;\n        Pos tgt = plan.inRegion(humans[i]) ? plan.safeCell : plan.decoyCell;\n        act[i] = moveToward(i, tgt, dist, first);\n    }\n\n    return act;\n}\n\nvector<char> Solver::decideActions(int turn, const int humanCnt[31][31], const int petCnt[31][31]) {\n    (void)turn;\n    if(phase == DONE) return vector<char>(M, '.');\n    if(phase == BUILD) return decideBuildActions(humanCnt, petCnt);\n    if(phase == ENTER) return decideEnterActions(humanCnt, petCnt);\n    return decideCloseActions(humanCnt, petCnt);\n}\n\nvoid Solver::sanitizeActions(vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) const {\n    bool buildNow[31][31]{};\n\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }else{\n            act[i] = '.';\n        }\n    }\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to) || !passable[to.r][to.c] || buildNow[to.r][to.c]){\n            act[i] = '.';\n        }\n    }\n}\n\nvoid Solver::applyActions(const vector<char>& act, const int humanCnt[31][31], const int petCnt[31][31]) {\n    bool passBefore[31][31];\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passBefore[r][c] = passable[r][c];\n\n    bool buildNow[31][31]{};\n    for(int i=0; i<M; i++){\n        int d = dirFromLower(act[i]);\n        if(d < 0) continue;\n        Pos t = moved(humans[i], d);\n        if(inBoard(t) && canBuildCell(t, humanCnt, petCnt)){\n            buildNow[t.r][t.c] = true;\n        }\n    }\n\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) if(buildNow[r][c]) passable[r][c] = false;\n\n    for(int i=0; i<M; i++){\n        int d = dirFromUpper(act[i]);\n        if(d < 0) continue;\n        Pos to = moved(humans[i], d);\n        if(!inBoard(to)) continue;\n        if(!passBefore[to.r][to.c]) continue;\n        if(buildNow[to.r][to.c]) continue;\n        humans[i] = to;\n    }\n}\n\nvoid Solver::applyPetMoves(const vector<string>& pMoves) {\n    for(int i=0; i<N; i++){\n        if(pMoves[i] == \".\") continue;\n        for(char ch: pMoves[i]){\n            int d = dirFromUpper(ch);\n            if(d < 0) continue;\n            pets[i].r += DR[d];\n            pets[i].c += DC[d];\n        }\n    }\n}\n\nvoid Solver::run() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if(!(cin >> N)) return;\n    pets.resize(N);\n    petType.resize(N);\n    for(int i=0; i<N; i++) cin >> pets[i].r >> pets[i].c >> petType[i];\n    cin >> M;\n    humans.resize(M);\n    for(int i=0; i<M; i++) cin >> humans[i].r >> humans[i].c;\n\n    for(int r=0; r<=BOARD; r++) for(int c=0; c<=BOARD; c++) passable[r][c] = false;\n    for(int r=1; r<=BOARD; r++) for(int c=1; c<=BOARD; c++) passable[r][c] = true;\n\n    plan = choosePlan(false, -1);\n\n    phase = BUILD;\n    gateCloser = -1;\n    attemptCnt = 0;\n    lastReplanTurn = -1000;\n    lastBuiltCnt = builtNonGateWalls(plan);\n    stallTurns = 0;\n    closeStartTurn = -1;\n    targetInside = max(1, M-1);\n\n    for(int turn=0; turn<300; turn++){\n        int humanCnt[31][31], petCnt[31][31];\n        buildCounts(humanCnt, petCnt);\n\n        if(phase == BUILD){\n            int b = builtNonGateWalls(plan);\n            if(b > lastBuiltCnt){\n                lastBuiltCnt = b;\n                stallTurns = 0;\n            }else{\n                stallTurns++;\n            }\n        }else{\n            stallTurns = 0;\n        }\n\n        updatePhase(turn, petCnt);\n\n        if(shouldReplan(turn, petCnt)){\n            bool changed = replan(turn);\n            if(changed) updatePhase(turn, petCnt);\n        }\n\n        vector<char> actions = decideActions(turn, humanCnt, petCnt);\n        sanitizeActions(actions, humanCnt, petCnt);\n\n        string out;\n        out.reserve(M);\n        for(char ch: actions) out.push_back(ch);\n        cout << out << '\\n';\n        cout.flush();\n\n        applyActions(actions, humanCnt, petCnt);\n\n        vector<string> pMoves(N);\n        for(int i=0; i<N; i++){\n            if(!(cin >> pMoves[i])) return;\n        }\n        applyPetMoves(pMoves);\n    }\n}\n\nint main(){\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    void reseed(uint64_t seed) { x = seed ? seed : 88172645463325252ull; }\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\nclass Solver {\n    static constexpr int H = 20;\n    static constexpr int W = 20;\n    static constexpr int N = 400;\n    static constexpr int L = 200;\n\n    int si, sj, ti, tj;\n    int start, target;\n    double p, q;\n    string h[H], v[H - 1];\n\n    int to_raw[N][4];\n    int to_eval[N][4];\n    double isTar[N];\n\n    vector<array<double, N>> fw, bw, ub;\n    array<double, L + 1> pref{};\n\n    vector<uint8_t> seq, bestSeq;\n    double curScore = -1e100, bestScore = -1e100;\n\n    vector<pair<double, vector<uint8_t>>> elite;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver() : fw(L + 1), bw(L + 1), ub(L + 1), seq(L), bestSeq(L) {}\n\n    void solve() {\n        readInput();\n        buildTransitions();\n        precomputeUB();\n\n        st = chrono::steady_clock::now();\n\n        vector<vector<uint8_t>> cands;\n        buildCandidates(cands);\n\n        elite.clear();\n        bestScore = -1e100;\n\n        for (auto &c : cands) {\n            seq = c;\n            curScore = recompute();\n            addElite(seq, curScore);\n        }\n\n        const double TL = 1.93;\n\n        // Initial refinement on top seeds\n        {\n            int use = min<int>(4, elite.size());\n            for (int i = 0; i < use && now() < 0.95; i++) {\n                seq = elite[i].second;\n                curScore = recompute();\n                updateBest();\n                double dl = min(TL, now() + 0.13);\n                localSearch(dl, 1);\n                if (now() < dl && rng.nextInt(100) < 50) {\n                    int w = 8 + rng.nextInt(8);\n                    int l = rng.nextInt(L - w + 1);\n                    beamPatch(l, w, 30, dl);\n                }\n                addElite(seq, curScore);\n            }\n        }\n\n        // Iterated local search\n        while (now() < TL - 0.08) {\n            int m = min<int>(6, elite.size());\n            int pick = 0;\n            int r = rng.nextInt(100);\n            if (m >= 2) {\n                if (r < 55) pick = 0;\n                else if (r < 85) pick = rng.nextInt(min(3, m));\n                else pick = rng.nextInt(m);\n            }\n\n            seq = elite[pick].second;\n            curScore = recompute();\n            updateBest();\n\n            int op = rng.nextInt(100);\n            if (op < 45) {\n                mutateCurrent();\n                curScore = recompute();\n                updateBest();\n            } else if (op < 75) {\n                int cut = rng.nextInt(L - 2);\n                regrowSuffixFromCut(cut, 0.12);\n                curScore = recompute();\n                updateBest();\n            } else {\n                bool ok = false;\n                for (int z = 0; z < 2 && now() < TL - 0.08; z++) {\n                    int w = 8 + rng.nextInt(9);\n                    int l = rng.nextInt(L - w + 1);\n                    int B = 24 + rng.nextInt(16);\n                    if (beamPatch(l, w, B, TL - 0.05)) {\n                        ok = true;\n                        break;\n                    }\n                }\n                if (!ok) {\n                    mutateCurrent();\n                    curScore = recompute();\n                    updateBest();\n                }\n            }\n\n            double dl = min(TL - 0.03, now() + 0.05);\n            localSearch(dl, 1);\n\n            if (now() < TL - 0.03 && rng.nextInt(100) < 35) {\n                int w = 7 + rng.nextInt(10);\n                int l = rng.nextInt(L - w + 1);\n                beamPatch(l, w, 30, TL - 0.02);\n            }\n\n            addElite(seq, curScore);\n        }\n\n        // Final polish from best\n        seq = bestSeq;\n        curScore = recompute();\n        updateBest();\n\n        while (now() < TL) {\n            bool imp = false;\n            imp |= singleSweep(TL);\n            if (now() < TL) imp |= pairSweep(TL);\n\n            if (!imp) {\n                bool pImp = false;\n                for (int z = 0; z < 3 && now() < TL; z++) {\n                    int w = 7 + rng.nextInt(10);\n                    int l = rng.nextInt(L - w + 1);\n                    if (beamPatch(l, w, 36, TL)) {\n                        pImp = true;\n                        break;\n                    }\n                }\n                if (!pImp) break;\n            }\n        }\n\n        const char mp[4] = {'U', 'D', 'L', 'R'};\n        string ans(L, 'U');\n        for (int i = 0; i < L; i++) ans[i] = mp[bestSeq[i]];\n        cout << ans << '\\n';\n    }\n\nprivate:\n    inline int id(int i, int j) const { return i * W + j; }\n\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    void readInput() {\n        cin >> si >> sj >> ti >> tj >> p;\n        for (int i = 0; i < H; i++) cin >> h[i];\n        for (int i = 0; i < H - 1; i++) cin >> v[i];\n\n        start = id(si, sj);\n        target = id(ti, tj);\n        q = 1.0 - p;\n\n        uint64_t seed = 1469598103934665603ull;\n        auto mix = [&](uint64_t x) {\n            seed ^= x + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n        };\n        mix(si); mix(sj); mix(ti); mix(tj);\n        mix((uint64_t)llround(p * 1000.0));\n        for (int i = 0; i < H; i++) for (char c : h[i]) mix((uint64_t)c);\n        for (int i = 0; i < H - 1; i++) for (char c : v[i]) mix((uint64_t)c);\n        rng.reseed(seed);\n    }\n\n    void buildTransitions() {\n        for (int i = 0; i < H; i++) {\n            for (int j = 0; j < W; j++) {\n                int s = id(i, j);\n\n                // U\n                if (i == 0 || v[i - 1][j] == '1') to_raw[s][0] = s;\n                else to_raw[s][0] = id(i - 1, j);\n\n                // D\n                if (i == H - 1 || v[i][j] == '1') to_raw[s][1] = s;\n                else to_raw[s][1] = id(i + 1, j);\n\n                // L\n                if (j == 0 || h[i][j - 1] == '1') to_raw[s][2] = s;\n                else to_raw[s][2] = id(i, j - 1);\n\n                // R\n                if (j == W - 1 || h[i][j] == '1') to_raw[s][3] = s;\n                else to_raw[s][3] = id(i, j + 1);\n            }\n        }\n\n        for (int s = 0; s < N; s++) {\n            for (int a = 0; a < 4; a++) to_eval[s][a] = to_raw[s][a];\n            isTar[s] = (s == target ? 1.0 : 0.0);\n        }\n        // target absorbing\n        for (int a = 0; a < 4; a++) to_eval[target][a] = target;\n    }\n\n    inline void stepDist(const array<double, N>& cur, int a, array<double, N>& nxt) const {\n        nxt.fill(0.0);\n        for (int s = 0; s < N; s++) {\n            double pr = cur[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            if (n == s) {\n                nxt[s] += pr;\n            } else {\n                double mv = pr * q;\n                nxt[s] += pr - mv;\n                nxt[n] += mv;\n            }\n        }\n    }\n\n    inline double dotDouble(const array<double, N>& x, const array<double, N>& y) const {\n        double r = 0.0;\n        for (int s = 0; s < N; s++) r += x[s] * y[s];\n        return r;\n    }\n\n    inline double dotFloatDouble(const array<float, N>& x, const array<double, N>& y) const {\n        double r = 0.0;\n        for (int s = 0; s < N; s++) r += (double)x[s] * y[s];\n        return r;\n    }\n\n    void precomputeUB() {\n        ub[0].fill(0.0);\n        for (int rem = 1; rem <= L; rem++) {\n            int coef = (rem == 1 ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                double rs = isTar[s] * coef;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double cand;\n                    if (n == s) {\n                        cand = rs + ub[rem - 1][s];\n                    } else {\n                        double rn = isTar[n] * coef;\n                        cand = p * (rs + ub[rem - 1][s]) + q * (rn + ub[rem - 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                ub[rem][s] = best;\n            }\n        }\n    }\n\n    int bestActionUB1(const array<double, N>& dist, int t) const {\n        int rem = L - t;\n        int coef = (t + 1 == L ? 201 : 1);\n        const auto &U = ub[rem - 1];\n\n        int bestA = 0;\n        double bestV = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n            for (int s = 0; s < N; s++) {\n                double pr = dist[s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                double rs = isTar[s] * coef;\n                if (n == s) {\n                    val += pr * (rs + U[s]);\n                } else {\n                    double rn = isTar[n] * coef;\n                    val += pr * (p * (rs + U[s]) + q * (rn + U[n]));\n                }\n            }\n            if (val > bestV) {\n                bestV = val;\n                bestA = a;\n            }\n        }\n        return bestA;\n    }\n\n    int bestActionUB2(const array<double, N>& dist, int t) const {\n        int rem = L - t;\n        if (rem <= 1) return bestActionUB1(dist, t);\n\n        int c1 = (t + 1 == L ? 201 : 1);\n        int c2 = (t + 2 == L ? 201 : 1);\n        const auto &U = ub[rem - 2];\n\n        array<array<double, N>, 4> d1;\n        array<double, 4> v1{};\n        array<double, N> d2;\n\n        for (int a = 0; a < 4; a++) {\n            stepDist(dist, a, d1[a]);\n            v1[a] = c1 * d1[a][target];\n        }\n\n        int bestA = 0;\n        double bestV = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                stepDist(d1[a], b, d2);\n                double val = v1[a] + c2 * d2[target] + dotDouble(d2, U);\n                if (val > bestV) {\n                    bestV = val;\n                    bestA = a;\n                }\n            }\n        }\n        return bestA;\n    }\n\n    vector<int> shortestPath() {\n        vector<int> dist(N, -1), par(N, -1), pdir(N, -1);\n        queue<int> qu;\n        dist[start] = 0;\n        qu.push(start);\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            if (s == target) break;\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (dist[n] != -1) continue;\n                dist[n] = dist[s] + 1;\n                par[n] = s;\n                pdir[n] = a;\n                qu.push(n);\n            }\n        }\n\n        vector<int> path;\n        if (dist[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> weightedPath(double penUL, double noise) {\n        const double INF = 1e100;\n        vector<double> dist(N, INF);\n        vector<int> par(N, -1), pdir(N, -1);\n\n        array<array<double, 4>, N> rnd{};\n        for (int s = 0; s < N; s++) for (int a = 0; a < 4; a++) rnd[s][a] = rng.nextDouble();\n\n        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n        dist[start] = 0.0;\n        pq.push({0.0, start});\n\n        const int ord[4] = {1, 3, 0, 2}; // D,R,U,L\n\n        while (!pq.empty()) {\n            auto [cd, s] = pq.top();\n            pq.pop();\n            if (cd > dist[s] + 1e-15) continue;\n            if (s == target) break;\n\n            for (int z = 0; z < 4; z++) {\n                int a = ord[z];\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                double w = 1.0 + ((a == 0 || a == 2) ? penUL : 0.0) + noise * rnd[s][a];\n                double nd = cd + w;\n                if (nd < dist[n]) {\n                    dist[n] = nd;\n                    par[n] = s;\n                    pdir[n] = a;\n                    pq.push({nd, n});\n                }\n            }\n        }\n\n        vector<int> path;\n        if (par[target] == -1) return path;\n        for (int cur = target; cur != start; cur = par[cur]) path.push_back(pdir[cur]);\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    vector<int> distToTarget() {\n        const int INF = 1e9;\n        vector<int> d(N, INF);\n        queue<int> qu;\n        d[target] = 0;\n        qu.push(target);\n\n        while (!qu.empty()) {\n            int s = qu.front();\n            qu.pop();\n            for (int a = 0; a < 4; a++) {\n                int n = to_raw[s][a];\n                if (n == s) continue;\n                if (d[n] > d[s] + 1) {\n                    d[n] = d[s] + 1;\n                    qu.push(n);\n                }\n            }\n        }\n        return d;\n    }\n\n    vector<uint8_t> seedFromPath(const vector<int>& path, int rep, bool useUB2, double epsRand) {\n        vector<uint8_t> out;\n        out.reserve(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int dir : path) {\n            for (int k = 0; k < rep && (int)out.size() < L; k++) {\n                out.push_back((uint8_t)dir);\n                stepDist(cur, dir, nxt);\n                cur = nxt;\n            }\n            if ((int)out.size() >= L) break;\n        }\n\n        while ((int)out.size() < L) {\n            int t = (int)out.size();\n            int a = useUB2 ? bestActionUB2(cur, t) : bestActionUB1(cur, t);\n            if (epsRand > 0.0 && rng.nextDouble() < epsRand) a = rng.nextInt(4);\n            out.push_back((uint8_t)a);\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n\n        return out;\n    }\n\n    vector<uint8_t> greedyUBSeed(bool useUB2) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int a = useUB2 ? bestActionUB2(cur, t) : bestActionUB1(cur, t);\n            out[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n        return out;\n    }\n\n    vector<uint8_t> greedyStaticSeed(const vector<double>& val) {\n        vector<uint8_t> out(L);\n\n        array<double, N> cur{}, nxt{};\n        cur.fill(0.0);\n        cur[start] = 1.0;\n\n        for (int t = 0; t < L; t++) {\n            int bestA = 0;\n            double bestV = -1e100;\n\n            for (int a = 0; a < 4; a++) {\n                double v = 0.0;\n                for (int s = 0; s < N; s++) {\n                    double pr = cur[s];\n                    if (pr == 0.0) continue;\n                    int n = to_eval[s][a];\n                    if (n == s) v += pr * val[s];\n                    else v += pr * (p * val[s] + q * val[n]);\n                }\n                if (v > bestV) {\n                    bestV = v;\n                    bestA = a;\n                }\n            }\n\n            out[t] = (uint8_t)bestA;\n            stepDist(cur, bestA, nxt);\n            cur = nxt;\n        }\n\n        return out;\n    }\n\n    vector<uint8_t> globalBeamSeed(int B, double noise) {\n        struct Node {\n            array<float, N> dist;\n            double score;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double score;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> beam(1), nxt;\n        beam[0].dist.fill(0.0f);\n        beam[0].dist[start] = 1.0f;\n        beam[0].score = 0.0;\n        beam[0].key = ub[L][start];\n\n        vector<vector<pair<int, uint8_t>>> trace(L + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 8);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            return a.key > b.key;\n        };\n\n        for (int d = 0; d < L; d++) {\n            int coef = (d + 1 == L ? 201 : 1);\n            int rem = L - (d + 1); // remaining after this step\n            cand.clear();\n\n            for (int i = 0; i < (int)beam.size(); i++) {\n                const auto &nd = beam[i];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = i;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    for (int s = 0; s < N; s++) {\n                        float pr = nd.dist[s];\n                        if (pr == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += pr;\n                            if (s == target) inc += (double)pr;\n                        } else {\n                            float ps = (float)(pr * p);\n                            float pn = (float)(pr * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                        }\n                    }\n\n                    ch.score = nd.score + coef * inc;\n                    ch.key = ch.score + dotFloatDouble(ch.dist, ub[rem]);\n                    if (noise > 0.0) ch.key += noise * (rng.nextDouble() - 0.5);\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            nxt.resize(cand.size());\n            trace[d + 1].resize(cand.size());\n            for (int i = 0; i < (int)cand.size(); i++) {\n                nxt[i].dist = std::move(cand[i].dist);\n                nxt[i].score = cand[i].score;\n                nxt[i].key = cand[i].key;\n                trace[d + 1][i] = {cand[i].par, cand[i].act};\n            }\n            beam.swap(nxt);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)beam.size(); i++) {\n            if (beam[i].score > beam[bestIdx].score) bestIdx = i;\n        }\n\n        vector<uint8_t> out(L);\n        int idx = bestIdx;\n        for (int d = L; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            out[d - 1] = act;\n            idx = par;\n        }\n        return out;\n    }\n\n    void buildCandidates(vector<vector<uint8_t>>& cands) {\n        auto sp = shortestPath();\n        int rep0 = (int)llround(1.3 / max(1e-9, q));\n        rep0 = max(1, min(6, rep0));\n\n        vector<int> reps = {1, max(1, rep0 - 1), rep0, min(7, rep0 + 1), min(8, rep0 + 2)};\n        sort(reps.begin(), reps.end());\n        reps.erase(unique(reps.begin(), reps.end()), reps.end());\n\n        if (!sp.empty()) {\n            for (int rep : reps) cands.push_back(seedFromPath(sp, rep, false, 0.0));\n            cands.push_back(seedFromPath(sp, rep0, true, 0.0));\n            cands.push_back(seedFromPath(sp, min(8, rep0 + 1), true, 0.05));\n        }\n\n        vector<pair<double, double>> params = {\n            {0.0, 0.0},\n            {0.4, 0.0},\n            {0.8, 0.0},\n            {0.2, 0.25},\n            {0.6, 0.25}\n        };\n        for (auto [pen, noise] : params) {\n            auto pth = weightedPath(pen, noise);\n            if (pth.empty()) continue;\n            cands.push_back(seedFromPath(pth, rep0, false, 0.0));\n            cands.push_back(seedFromPath(pth, min(8, rep0 + 1), true, 0.02));\n        }\n\n        cands.push_back(greedyUBSeed(false));\n        cands.push_back(greedyUBSeed(true));\n\n        auto d = distToTarget();\n        vector<double> val(N);\n        for (int s = 0; s < N; s++) val[s] = -1.0 * d[s];\n        cands.push_back(greedyStaticSeed(val));\n\n        int Bmain = 120 + (p > 0.35 ? 20 : 0) + (p > 0.45 ? 10 : 0);\n        cands.push_back(globalBeamSeed(Bmain, 0.0));\n        if (now() < 0.70) cands.push_back(globalBeamSeed(70, 0.02));\n\n        // fallback patterns\n        vector<uint8_t> pat(L);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 1 : 3); // D...R...\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = (i < L / 2 ? 3 : 1); // R...D...\n        cands.push_back(pat);\n        for (int i = 0; i < L; i++) pat[i] = ((i & 1) ? 3 : 1);   // D,R,D,R\n        cands.push_back(pat);\n\n        // random fallback\n        vector<uint8_t> rnd(L);\n        for (int i = 0; i < L; i++) rnd[i] = (uint8_t)rng.nextInt(4);\n        cands.push_back(rnd);\n    }\n\n    double recompute() {\n        fw[0].fill(0.0);\n        fw[0][start] = 1.0;\n        pref[0] = 0.0;\n\n        for (int t = 0; t < L; t++) {\n            fw[t + 1].fill(0.0);\n            int a = seq[t];\n            for (int s = 0; s < N; s++) {\n                double pr = fw[t][s];\n                if (pr == 0.0) continue;\n                int n = to_eval[s][a];\n                if (n == s) {\n                    fw[t + 1][s] += pr;\n                } else {\n                    double mv = pr * q;\n                    fw[t + 1][s] += pr - mv;\n                    fw[t + 1][n] += mv;\n                }\n            }\n            int coef = (t + 1 == L ? 201 : 1);\n            pref[t + 1] = pref[t] + coef * fw[t + 1][target];\n        }\n\n        bw[L].fill(0.0);\n        for (int t = L - 1; t >= 0; t--) {\n            int a = seq[t];\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                int n = to_eval[s][a];\n                double rs = isTar[s] * coef;\n                if (n == s) {\n                    bw[t][s] = rs + bw[t + 1][s];\n                } else {\n                    double rn = isTar[n] * coef;\n                    bw[t][s] = p * (rs + bw[t + 1][s]) + q * (rn + bw[t + 1][n]);\n                }\n            }\n        }\n\n        return pref[L];\n    }\n\n    inline void updateBest() {\n        if (curScore > bestScore) {\n            bestScore = curScore;\n            bestSeq = seq;\n        }\n    }\n\n    void addElite(const vector<uint8_t>& s, double sc) {\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestSeq = s;\n        }\n\n        for (auto &e : elite) {\n            if (e.second == s) {\n                if (sc > e.first) e.first = sc;\n                sort(elite.begin(), elite.end(),\n                     [](const auto& a, const auto& b) { return a.first > b.first; });\n                return;\n            }\n        }\n\n        elite.push_back({sc, s});\n        sort(elite.begin(), elite.end(),\n             [](const auto& a, const auto& b) { return a.first > b.first; });\n        if ((int)elite.size() > 8) elite.resize(8);\n    }\n\n    double evalSingle(int pos, int a) const {\n        double total = pref[pos];\n        int coef = (pos + 1 == L ? 201 : 1);\n\n        const auto &dist = fw[pos];\n        const auto &suf = bw[pos + 1];\n\n        for (int s = 0; s < N; s++) {\n            double pr = dist[s];\n            if (pr == 0.0) continue;\n            int n = to_eval[s][a];\n            double rs = isTar[s] * coef;\n            double v;\n            if (n == s) {\n                v = rs + suf[s];\n            } else {\n                double rn = isTar[n] * coef;\n                v = p * (rs + suf[s]) + q * (rn + suf[n]);\n            }\n            total += pr * v;\n        }\n        return total;\n    }\n\n    bool singleSweep(double deadline) {\n        bool improved = false;\n        array<int, L> ord;\n        iota(ord.begin(), ord.end(), 0);\n        for (int i = L - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        for (int ii = 0; ii < L; ii++) {\n            if ((ii & 15) == 0 && now() >= deadline) break;\n            int pos = ord[ii];\n\n            int curA = seq[pos];\n            int bestA = curA;\n            double bestV = curScore;\n\n            for (int a = 0; a < 4; a++) {\n                if (a == curA) continue;\n                double sc = evalSingle(pos, a);\n                if (sc > bestV + 1e-12) {\n                    bestV = sc;\n                    bestA = a;\n                }\n            }\n\n            if (bestA != curA) {\n                seq[pos] = (uint8_t)bestA;\n                curScore = recompute();\n                updateBest();\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    bool pairSweep(double deadline) {\n        bool improved = false;\n        array<int, L - 1> ord;\n        iota(ord.begin(), ord.end(), 0);\n        for (int i = L - 2; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        array<array<double, N>, 4> d1;\n        array<double, 4> base1{};\n        array<double, N> d2;\n\n        for (int ii = 0; ii < L - 1; ii++) {\n            if ((ii & 7) == 0 && now() >= deadline) break;\n            int pos = ord[ii];\n\n            int curA = seq[pos], curB = seq[pos + 1];\n            int bestA = curA, bestB = curB;\n            double bestV = curScore;\n\n            const auto &dist0 = fw[pos];\n            const auto &suf = bw[pos + 2];\n            int c1 = (pos + 1 == L ? 201 : 1);\n            int c2 = (pos + 2 == L ? 201 : 1);\n\n            for (int a = 0; a < 4; a++) {\n                stepDist(dist0, a, d1[a]);\n                base1[a] = pref[pos] + c1 * d1[a][target];\n            }\n\n            for (int a = 0; a < 4; a++) {\n                for (int b = 0; b < 4; b++) {\n                    stepDist(d1[a], b, d2);\n                    double sc = base1[a] + c2 * d2[target];\n                    double tail = 0.0;\n                    for (int s = 0; s < N; s++) tail += d2[s] * suf[s];\n                    sc += tail;\n\n                    if (sc > bestV + 1e-12) {\n                        bestV = sc;\n                        bestA = a;\n                        bestB = b;\n                    }\n                }\n            }\n\n            if (bestA != curA || bestB != curB) {\n                seq[pos] = (uint8_t)bestA;\n                seq[pos + 1] = (uint8_t)bestB;\n                curScore = recompute();\n                updateBest();\n                improved = true;\n            }\n        }\n\n        return improved;\n    }\n\n    bool localSearch(double deadline, int rounds) {\n        bool any = false;\n        for (int r = 0; r < rounds && now() < deadline; r++) {\n            bool imp = false;\n            imp |= singleSweep(deadline);\n            if (now() < deadline) imp |= pairSweep(deadline);\n            any |= imp;\n            if (!imp) break;\n        }\n        return any;\n    }\n\n    void regrowSuffixFromCut(int cut, double epsRand) {\n        array<double, N> cur = fw[cut], nxt;\n        for (int t = cut; t < L; t++) {\n            int a = bestActionUB2(cur, t);\n            if (epsRand > 0.0 && rng.nextDouble() < epsRand) a = rng.nextInt(4);\n            seq[t] = (uint8_t)a;\n            stepDist(cur, a, nxt);\n            cur = nxt;\n        }\n    }\n\n    void mutateCurrent() {\n        int type = rng.nextInt(100);\n\n        if (type < 45) {\n            int m = 1 + rng.nextInt(5);\n            for (int k = 0; k < m; k++) {\n                int pos = rng.nextInt(L);\n                seq[pos] = (uint8_t)rng.nextInt(4);\n            }\n        } else if (type < 75) {\n            int len = 6 + rng.nextInt(24);\n            len = min(len, L);\n            int l = rng.nextInt(L - len + 1);\n            for (int i = 0; i < len; i++) seq[l + i] = (uint8_t)rng.nextInt(4);\n        } else {\n            int cut = rng.nextInt(L - 2);\n            regrowSuffixFromCut(cut, 0.15);\n        }\n    }\n\n    bool beamPatch(int l, int w, int B, double deadline) {\n        if (now() >= deadline) return false;\n        int r = l + w - 1;\n\n        // Adaptive upper bound for this window + fixed suffix\n        vector<array<double, N>> Hh(w + 1);\n        Hh[w] = bw[r + 1];\n        for (int i = w - 1; i >= 0; i--) {\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n            for (int s = 0; s < N; s++) {\n                double best = -1e100;\n                double rs = isTar[s] * coef;\n                for (int a = 0; a < 4; a++) {\n                    int n = to_eval[s][a];\n                    double cand;\n                    if (n == s) {\n                        cand = rs + Hh[i + 1][s];\n                    } else {\n                        double rn = isTar[n] * coef;\n                        cand = p * (rs + Hh[i + 1][s]) + q * (rn + Hh[i + 1][n]);\n                    }\n                    if (cand > best) best = cand;\n                }\n                Hh[i][s] = best;\n            }\n        }\n\n        struct Node {\n            array<float, N> dist;\n            double local;\n            double key;\n        };\n        struct Cand {\n            array<float, N> dist;\n            double local;\n            double key;\n            int par;\n            uint8_t act;\n        };\n\n        vector<Node> cur(1), nxt;\n        cur[0].dist.fill(0.0f);\n        for (int s = 0; s < N; s++) cur[0].dist[s] = (float)fw[l][s];\n        cur[0].local = 0.0;\n        cur[0].key = dotFloatDouble(cur[0].dist, Hh[0]);\n\n        vector<vector<pair<int, uint8_t>>> trace(w + 1);\n        trace[0].push_back({-1, 255});\n\n        vector<Cand> cand;\n        cand.reserve(B * 4 + 8);\n\n        auto cmp = [](const Cand& a, const Cand& b) {\n            return a.key > b.key;\n        };\n\n        for (int i = 0; i < w; i++) {\n            if ((i & 1) == 0 && now() >= deadline) return false;\n\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n\n            cand.clear();\n            for (int bi = 0; bi < (int)cur.size(); bi++) {\n                const auto &nd = cur[bi];\n                for (int a = 0; a < 4; a++) {\n                    Cand ch;\n                    ch.par = bi;\n                    ch.act = (uint8_t)a;\n                    ch.dist.fill(0.0f);\n\n                    double inc = 0.0;\n                    for (int s = 0; s < N; s++) {\n                        float pr = nd.dist[s];\n                        if (pr == 0.0f) continue;\n                        int n = to_eval[s][a];\n                        if (n == s) {\n                            ch.dist[s] += pr;\n                            if (s == target) inc += (double)pr;\n                        } else {\n                            float ps = (float)(pr * p);\n                            float pn = (float)(pr * q);\n                            ch.dist[s] += ps;\n                            ch.dist[n] += pn;\n                            if (n == target) inc += (double)pn;\n                        }\n                    }\n\n                    ch.local = nd.local + coef * inc;\n                    ch.key = ch.local + dotFloatDouble(ch.dist, Hh[i + 1]);\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if (cand.empty()) return false;\n\n            if ((int)cand.size() > B) {\n                nth_element(cand.begin(), cand.begin() + B, cand.end(), cmp);\n                cand.resize(B);\n            }\n            sort(cand.begin(), cand.end(), cmp);\n\n            nxt.resize(cand.size());\n            trace[i + 1].resize(cand.size());\n            for (int j = 0; j < (int)cand.size(); j++) {\n                nxt[j].dist = std::move(cand[j].dist);\n                nxt[j].local = cand[j].local;\n                nxt[j].key = cand[j].key;\n                trace[i + 1][j] = {cand[j].par, cand[j].act};\n            }\n            cur.swap(nxt);\n        }\n\n        const auto &tail = bw[r + 1];\n        int bestIdx = 0;\n        double bestVal = -1e100;\n        for (int i = 0; i < (int)cur.size(); i++) {\n            double val = cur[i].local + dotFloatDouble(cur[i].dist, tail);\n            if (val > bestVal) {\n                bestVal = val;\n                bestIdx = i;\n            }\n        }\n\n        vector<uint8_t> acts(w);\n        int idx = bestIdx;\n        for (int d = w; d >= 1; d--) {\n            auto [par, act] = trace[d][idx];\n            acts[d - 1] = act;\n            idx = par;\n        }\n\n        // Exact score of patched segment\n        array<double, N> dist = fw[l], nxtd;\n        double seg = 0.0;\n        for (int i = 0; i < w; i++) {\n            int t = l + i;\n            int coef = (t + 1 == L ? 201 : 1);\n            stepDist(dist, acts[i], nxtd);\n            seg += coef * nxtd[target];\n            dist = nxtd;\n        }\n        double tailVal = dotDouble(dist, tail);\n        double newScore = pref[l] + seg + tailVal;\n\n        if (newScore > curScore + 1e-12) {\n            for (int i = 0; i < w; i++) seq[l + i] = acts[i];\n            curScore = recompute();\n            updateBest();\n            return true;\n        }\n        return false;\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}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int C = N * N;\nstatic constexpr int S = C * 4;\nusing Board = array<uint8_t, C>;\n\nint 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\nuint8_t SIDE[8] = {\n    (1u << 0) | (1u << 1), // 0\n    (1u << 0) | (1u << 3), // 1\n    (1u << 2) | (1u << 3), // 2\n    (1u << 1) | (1u << 2), // 3\n    0b1111,                // 4\n    0b1111,                // 5\n    (1u << 0) | (1u << 2), // 6\n    (1u << 1) | (1u << 3), // 7\n};\n\nint ROT1[8] = {1, 2, 3, 0, 5, 4, 7, 6};\nint ROT[8][4];\nint NEI[C][4];\nint OPP[4] = {2, 3, 0, 1};\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463393265ull) {\n        x = seed ^ 0x9e3779b97f4a7c15ULL;\n        if (x == 0) x = 88172645463393265ull;\n        for (int i = 0; i < 8; i++) next_u64();\n    }\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline uint32_t next_u32() { return static_cast<uint32_t>(next_u64()); }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Eval {\n    int l1 = 0, l2 = 0, l3 = 0, l4 = 0;\n    int loopCnt = 0;\n    int sumLoop = 0;\n    int matched = 0;\n    long long contest = 0;\n};\n\ninline bool better_best(const Eval& a, const Eval& b) {\n    if (a.contest != b.contest) return a.contest > b.contest;\n    if (a.l2 != b.l2) return a.l2 > b.l2;\n    if (a.l1 != b.l1) return a.l1 > b.l1;\n    if (a.l3 != b.l3) return a.l3 > b.l3;\n    if (a.sumLoop != b.sumLoop) return a.sumLoop > b.sumLoop;\n    return a.matched > b.matched;\n}\n\ninline double elite_key(const Eval& e) {\n    return (double)e.contest + 1.0 * e.l2 + 0.45 * e.l1 + 0.25 * e.l3 + 0.04 * e.sumLoop;\n}\n\n// p: 0 (early) -> 1 (late)\ninline double objective(const Eval& e, double p) {\n    double q = p * p;\n    double v = 0.0;\n    v += q * (double)e.contest;\n    v += (1.0 - q) * (70.0 * e.l1 + 15.0 * e.sumLoop + 40.0 * e.loopCnt);\n    v += 8.0 * e.l2 + 2.0 * e.l3 + 0.10 * e.matched;\n    if (e.loopCnt < 2) v -= (2000.0 + 3000.0 * p);\n    return v;\n}\n\ninline bool better_eval_obj(const Eval& a, double oa, const Eval& b, double ob) {\n    if (better_best(a, b)) return true;\n    if (better_best(b, a)) return false;\n    return oa > ob + 1e-12;\n}\n\ninline double elapsed_sec(const chrono::steady_clock::time_point& st) {\n    return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n}\n\nstruct Evaluator {\n    int nxt[S];\n    int partner[S];\n    int visTag[S];\n    int visPos[S];\n    int stk[S];\n    uint8_t done[S];\n    uint8_t seenCanon[S];\n\n    Eval eval(const Board& board) {\n        uint8_t mask[C];\n        for (int c = 0; c < C; c++) mask[c] = SIDE[board[c]];\n\n        int matched = 0;\n        for (int i = 0; i < N; i++) {\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                int c = base + j;\n                uint8_t m = mask[c];\n                if (j + 1 < N) {\n                    if ((m & (1 << 2)) && (mask[c + 1] & (1 << 0))) matched++;\n                }\n                if (i + 1 < N) {\n                    if ((m & (1 << 3)) && (mask[c + N] & (1 << 1))) matched++;\n                }\n            }\n        }\n\n        for (int c = 0; c < C; c++) {\n            int t = board[c];\n            int c4 = c << 2;\n            for (int d = 0; d < 4; d++) {\n                int s = c4 | d;\n                int d2 = TO[t][d];\n                if (d2 < 0) {\n                    nxt[s] = -1;\n                    partner[s] = -1;\n                    continue;\n                }\n                partner[s] = c4 | d2;\n                int nc = NEI[c][d2];\n                if (nc < 0 || !(mask[nc] & (1 << OPP[d2]))) nxt[s] = -1;\n                else nxt[s] = (nc << 2) | OPP[d2];\n            }\n        }\n\n        memset(done, 0, sizeof(done));\n        memset(visTag, 0, sizeof(visTag));\n        memset(seenCanon, 0, sizeof(seenCanon));\n\n        int iter = 1;\n        int loopCnt = 0, sumLoop = 0;\n        int t0 = 0, t1 = 0, t2 = 0, t3 = 0;\n\n        auto push_len = [&](int len) {\n            if (len > t0) {\n                t3 = t2; t2 = t1; t1 = t0; t0 = len;\n            } else if (len > t1) {\n                t3 = t2; t2 = t1; t1 = len;\n            } else if (len > t2) {\n                t3 = t2; t2 = len;\n            } else if (len > t3) {\n                t3 = len;\n            }\n        };\n\n        for (int s0 = 0; s0 < S; s0++) {\n            if (done[s0]) continue;\n\n            int cur = s0;\n            int top = 0;\n            while (cur != -1 && !done[cur] && visTag[cur] != iter) {\n                visTag[cur] = iter;\n                visPos[cur] = top;\n                stk[top++] = cur;\n                cur = nxt[cur];\n            }\n\n            if (cur != -1 && !done[cur] && visTag[cur] == iter) {\n                int st = visPos[cur];\n                int len = top - st;\n\n                int can = INT_MAX;\n                for (int k = st; k < top; k++) {\n                    int v = stk[k];\n                    int p = partner[v];\n                    int m = (p >= 0 ? min(v, p) : v);\n                    can = min(can, m);\n                }\n\n                if (can >= 0 && can < S && !seenCanon[can]) {\n                    seenCanon[can] = 1;\n                    loopCnt++;\n                    sumLoop += len;\n                    push_len(len);\n                }\n            }\n\n            for (int k = 0; k < top; k++) done[stk[k]] = 1;\n            iter++;\n        }\n\n        Eval e;\n        e.l1 = t0; e.l2 = t1; e.l3 = t2; e.l4 = t3;\n        e.loopCnt = loopCnt;\n        e.sumLoop = sumLoop;\n        e.matched = matched;\n        e.contest = (loopCnt >= 2 ? 1LL * t0 * t1 : 0LL);\n        return e;\n    }\n};\n\ntemplate <class T>\ninline void shuffle_vec(vector<T>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = (int)(rng.next_u32() % (uint32_t)(i + 1));\n        swap(v[i], v[j]);\n    }\n}\n\ninline int cell_badness(int c, const Board& board) {\n    uint8_t m = SIDE[board[c]];\n    int bad = 0;\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) bad += 2;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 != b2) bad += 1;\n        }\n    }\n    return bad;\n}\n\ninline int local_potential(int c, uint8_t cand, const Board& board) {\n    int score = 0;\n    uint8_t m = SIDE[cand];\n\n    for (int d = 0; d < 4; d++) {\n        int b1 = (m >> d) & 1;\n        int nc = NEI[c][d];\n        if (nc < 0) {\n            if (b1) score -= 6;\n        } else {\n            int b2 = (SIDE[board[nc]] >> OPP[d]) & 1;\n            if (b1 && b2) score += 4;\n            else if (b1 ^ b2) score -= 3;\n        }\n    }\n\n    for (int d = 0; d < 4; d++) {\n        int d2 = TO[cand][d];\n        if (d2 < 0) continue;\n        int nc = NEI[c][d2];\n        if (nc >= 0 && (SIDE[board[nc]] & (1 << OPP[d2]))) score += 1;\n        else score -= 1;\n    }\n\n    return score;\n}\n\nint pick_bad_cell(const Board& board, RNG& rng, int samples) {\n    int best = (int)(rng.next_u32() % C), bestB = -1;\n    for (int k = 0; k < samples; k++) {\n        int c = (int)(rng.next_u32() % C);\n        int b = cell_badness(c, board);\n        if (b > bestB) {\n            bestB = b;\n            best = c;\n        }\n    }\n    return best;\n}\n\nint pick_bad_two(const Board& board, const vector<int>& twoCells, RNG& rng, int samples) {\n    if (twoCells.empty()) return (int)(rng.next_u32() % C);\n    int best = twoCells[rng.next_u32() % twoCells.size()], bestB = -1;\n    for (int k = 0; k < samples; k++) {\n        int c = twoCells[rng.next_u32() % twoCells.size()];\n        int b = cell_badness(c, board);\n        if (b > bestB) {\n            bestB = b;\n            best = c;\n        }\n    }\n    return best;\n}\n\ninline uint8_t random_other_state(\n    int c, uint8_t old,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng\n) {\n    if (possCnt[c] == 2) return (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n    int r = (int)(rng.next_u32() & 3);\n    uint8_t nw = poss[c][r];\n    if (nw == old) nw = poss[c][(r + 1) & 3];\n    return nw;\n}\n\nvoid fill_random(\n    Board& b,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng\n) {\n    for (int c = 0; c < C; c++) {\n        b[c] = poss[c][(possCnt[c] == 4) ? (rng.next_u32() & 3) : (rng.next_u32() & 1)];\n    }\n}\n\nvoid improve_connectivity(\n    Board& board,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    RNG& rng,\n    int passes\n) {\n    vector<int> ord(C);\n    iota(ord.begin(), ord.end(), 0);\n\n    for (int p = 0; p < passes; p++) {\n        shuffle_vec(ord, rng);\n        for (int idx = 0; idx < C; idx++) {\n            int c = ord[idx];\n            int bestScore = INT_MIN;\n            uint8_t bestState = board[c];\n\n            for (int k = 0; k < possCnt[c]; k++) {\n                uint8_t cand = poss[c][k];\n                int sc = local_potential(c, cand, board);\n                if (sc > bestScore || (sc == bestScore && (rng.next_u32() & 1))) {\n                    bestScore = sc;\n                    bestState = cand;\n                }\n            }\n            board[c] = bestState;\n        }\n    }\n}\n\nbool block_exhaustive_opt(\n    Board& board,\n    Eval& curEval,\n    double& curObj,\n    int bi, int bj,\n    int comboLimit,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    double p\n) {\n    int c0 = bi * N + bj;\n    int c1 = c0 + 1;\n    int c2 = c0 + N;\n    int c3 = c0 + N + 1;\n\n    int m0 = possCnt[c0], m1 = possCnt[c1], m2 = possCnt[c2], m3 = possCnt[c3];\n    int combos = m0 * m1 * m2 * m3;\n    if (combos > comboLimit) return false;\n\n    uint8_t old0 = board[c0], old1 = board[c1], old2 = board[c2], old3 = board[c3];\n    uint8_t best0 = old0, best1 = old1, best2 = old2, best3 = old3;\n    Eval bestE = curEval;\n    double bestO = curObj;\n\n    for (int a = 0; a < m0; a++) {\n        board[c0] = poss[c0][a];\n        for (int b = 0; b < m1; b++) {\n            board[c1] = poss[c1][b];\n            for (int c = 0; c < m2; c++) {\n                board[c2] = poss[c2][c];\n                for (int d = 0; d < m3; d++) {\n                    board[c3] = poss[c3][d];\n                    Eval ne = evaluator.eval(board);\n                    double o = objective(ne, p);\n\n                    if (better_eval_obj(ne, o, bestE, bestO)) {\n                        bestE = ne;\n                        bestO = o;\n                        best0 = board[c0];\n                        best1 = board[c1];\n                        best2 = board[c2];\n                        best3 = board[c3];\n                    }\n                }\n            }\n        }\n    }\n\n    board[c0] = best0;\n    board[c1] = best1;\n    board[c2] = best2;\n    board[c3] = best3;\n\n    bool improved = !(best0 == old0 && best1 == old1 && best2 == old2 && best3 == old3);\n    if (improved) {\n        curEval = bestE;\n        curObj = bestO;\n    }\n    return improved;\n}\n\nvoid random_block_descent(\n    Board& board,\n    Eval& curEval,\n    double& curObj,\n    int attempts,\n    int comboLimit,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    for (int t = 0; t < attempts; t++) {\n        if ((t & 3) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        int i, j;\n        if ((rng.next_u32() % 100) < 65) {\n            int c = pick_bad_cell(board, rng, 6);\n            i = c / N;\n            j = c % N;\n            if (i == N - 1) i--;\n            if (j == N - 1) j--;\n            if (i > 0 && (rng.next_u32() & 1)) i--;\n            if (j > 0 && (rng.next_u32() & 1)) j--;\n        } else {\n            i = (int)(rng.next_u32() % (N - 1));\n            j = (int)(rng.next_u32() % (N - 1));\n        }\n\n        block_exhaustive_opt(board, curEval, curObj, i, j, comboLimit, poss, possCnt, evaluator, p);\n    }\n}\n\nvoid quick_binary_descent(\n    Board& board,\n    Eval& curEval,\n    const vector<int>& twoCells,\n    const array<array<uint8_t, 4>, C>& poss,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int maxTry,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    if (twoCells.empty() || maxTry <= 0) return;\n    vector<int> ord = twoCells;\n    shuffle_vec(ord, rng);\n\n    double curObj = objective(curEval, p);\n    int tried = 0;\n\n    for (int idx = 0; idx < (int)ord.size() && tried < maxTry; idx++) {\n        if ((tried & 31) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        int c = ord[idx];\n        uint8_t old = board[c];\n        board[c] = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n\n        Eval ne = evaluator.eval(board);\n        double o = objective(ne, p);\n        tried++;\n\n        if (better_best(ne, curEval) || o >= curObj) {\n            curEval = ne;\n            curObj = o;\n        } else {\n            board[c] = old;\n        }\n    }\n}\n\nvoid pair_binary_descent(\n    Board& board,\n    Eval& curEval,\n    double& curObj,\n    const vector<pair<int,int>>& twoPairs,\n    const array<array<uint8_t, 4>, C>& poss,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    int maxTry,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    if (twoPairs.empty() || maxTry <= 0) return;\n\n    for (int t = 0; t < maxTry; t++) {\n        if ((t & 15) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        auto [c1, c2] = twoPairs[rng.next_u32() % twoPairs.size()];\n        uint8_t o1 = board[c1], o2 = board[c2];\n\n        board[c1] = (o1 == poss[c1][0] ? poss[c1][1] : poss[c1][0]);\n        board[c2] = (o2 == poss[c2][0] ? poss[c2][1] : poss[c2][0]);\n\n        Eval ne = evaluator.eval(board);\n        double o = objective(ne, p);\n\n        if (better_best(ne, curEval) || o >= curObj) {\n            curEval = ne;\n            curObj = o;\n        } else {\n            board[c1] = o1;\n            board[c2] = o2;\n        }\n    }\n}\n\nvoid subset_descent(\n    Board& board,\n    Eval& curEval,\n    double& curObj,\n    const vector<int>& cells,\n    int maxCells,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    double p,\n    const chrono::steady_clock::time_point& start,\n    double deadlineSec\n) {\n    if (cells.empty() || maxCells <= 0) return;\n    vector<int> ord = cells;\n    shuffle_vec(ord, rng);\n    int lim = min(maxCells, (int)ord.size());\n\n    for (int ii = 0; ii < lim; ii++) {\n        if ((ii & 15) == 0 && elapsed_sec(start) >= deadlineSec) return;\n\n        int c = ord[ii];\n        uint8_t old = board[c];\n\n        uint8_t bestState = old;\n        Eval bestEval = curEval;\n        double bestObj = curObj;\n\n        for (int k = 0; k < possCnt[c]; k++) {\n            uint8_t cand = poss[c][k];\n            if (cand == old) continue;\n\n            board[c] = cand;\n            Eval ne = evaluator.eval(board);\n            double o = objective(ne, p);\n\n            if (better_eval_obj(ne, o, bestEval, bestObj)) {\n                bestObj = o;\n                bestState = cand;\n                bestEval = ne;\n            }\n        }\n\n        board[c] = bestState;\n        if (bestState != old) {\n            curEval = bestEval;\n            curObj = bestObj;\n        }\n    }\n}\n\nstruct Elite {\n    Board st;\n    Eval ev;\n    double key = -1e100;\n};\n\ninline int hamming_dist(const Board& a, const Board& b) {\n    int d = 0;\n    for (int i = 0; i < C; i++) d += (a[i] != b[i]);\n    return d;\n}\n\nvoid add_elite(vector<Elite>& elites, const Board& st, const Eval& ev) {\n    const int MAX_E = 8;\n    const int MIN_DIST = 18;\n    double key = elite_key(ev);\n\n    for (auto& e : elites) {\n        if (hamming_dist(st, e.st) < MIN_DIST) {\n            if (better_best(ev, e.ev) || (ev.contest == e.ev.contest && key > e.key)) {\n                e.st = st;\n                e.ev = ev;\n                e.key = key;\n            }\n            return;\n        }\n    }\n\n    if ((int)elites.size() < MAX_E) {\n        elites.push_back(Elite{st, ev, key});\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < MAX_E; i++) if (elites[i].key < elites[worst].key) worst = i;\n    if (key > elites[worst].key) elites[worst] = Elite{st, ev, key};\n}\n\nint pick_elite_tournament(const vector<Elite>& elites, RNG& rng) {\n    int n = (int)elites.size();\n    int best = (int)(rng.next_u32() % n);\n    for (int t = 0; t < 3; t++) {\n        int x = (int)(rng.next_u32() % n);\n        if (elites[x].key > elites[best].key) best = x;\n    }\n    return best;\n}\n\nvoid polish_candidate(\n    Board& st,\n    Eval& ev,\n    const vector<int>& allCells,\n    const vector<int>& twoCells,\n    const vector<pair<int,int>>& twoPairs,\n    const array<array<uint8_t, 4>, C>& poss,\n    const array<uint8_t, C>& possCnt,\n    Evaluator& evaluator,\n    RNG& rng,\n    const chrono::steady_clock::time_point& start,\n    double localDeadline\n) {\n    const double pfin = 0.999;\n    double obj = objective(ev, pfin);\n\n    if (elapsed_sec(start) >= localDeadline) return;\n    quick_binary_descent(st, ev, twoCells, poss, evaluator, rng, pfin, 220, start, localDeadline);\n    obj = objective(ev, pfin);\n\n    if (elapsed_sec(start) >= localDeadline) return;\n    pair_binary_descent(st, ev, obj, twoPairs, poss, evaluator, rng, pfin, 180, start, localDeadline);\n\n    if (elapsed_sec(start) < localDeadline) {\n        int attempts = (localDeadline - elapsed_sec(start) > 0.05 ? 10 : 4);\n        random_block_descent(st, ev, obj, attempts, 64, poss, possCnt, evaluator, rng, pfin, start, localDeadline);\n    }\n\n    if (elapsed_sec(start) < localDeadline && !twoCells.empty()) {\n        vector<int> ord2 = twoCells;\n        for (int pass = 0; pass < 3; pass++) {\n            if (elapsed_sec(start) >= localDeadline) break;\n            shuffle_vec(ord2, rng);\n            bool improved = false;\n\n            for (int idx = 0; idx < (int)ord2.size(); idx++) {\n                if ((idx & 31) == 0 && elapsed_sec(start) >= localDeadline) break;\n                int c = ord2[idx];\n                uint8_t old = st[c];\n                st[c] = (old == poss[c][0] ? poss[c][1] : poss[c][0]);\n\n                Eval ne = evaluator.eval(st);\n                double o = objective(ne, pfin);\n\n                if (better_eval_obj(ne, o, ev, obj)) {\n                    ev = ne;\n                    obj = o;\n                    improved = true;\n                } else {\n                    st[c] = old;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    if (elapsed_sec(start) < localDeadline && !twoPairs.empty()) {\n        vector<int> ordp(twoPairs.size());\n        iota(ordp.begin(), ordp.end(), 0);\n\n        for (int pass = 0; pass < 2; pass++) {\n            if (elapsed_sec(start) >= localDeadline) break;\n            shuffle_vec(ordp, rng);\n            bool improved = false;\n\n            for (int ii = 0; ii < (int)ordp.size(); ii++) {\n                if ((ii & 15) == 0 && elapsed_sec(start) >= localDeadline) break;\n                auto [c1, c2] = twoPairs[ordp[ii]];\n                uint8_t o1 = st[c1], o2 = st[c2];\n\n                st[c1] = (o1 == poss[c1][0] ? poss[c1][1] : poss[c1][0]);\n                st[c2] = (o2 == poss[c2][0] ? poss[c2][1] : poss[c2][0]);\n\n                Eval ne = evaluator.eval(st);\n                double o = objective(ne, pfin);\n\n                if (better_eval_obj(ne, o, ev, obj)) {\n                    ev = ne;\n                    obj = o;\n                    improved = true;\n                } else {\n                    st[c1] = o1;\n                    st[c2] = o2;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n\n    if (elapsed_sec(start) < localDeadline) {\n        vector<int> ord = allCells;\n        int passes = (localDeadline - elapsed_sec(start) > 0.05 ? 2 : 1);\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (elapsed_sec(start) >= localDeadline) break;\n            shuffle_vec(ord, rng);\n            bool improved = false;\n\n            double rem = localDeadline - elapsed_sec(start);\n            int lim = C;\n            if (rem < 0.04) lim = 420;\n            if (rem < 0.02) lim = 180;\n\n            for (int ii = 0; ii < lim; ii++) {\n                if ((ii & 15) == 0 && elapsed_sec(start) >= localDeadline) break;\n\n                int c = ord[ii];\n                uint8_t old = st[c];\n\n                uint8_t bestS = old;\n                Eval bestE = ev;\n                double bestO = obj;\n\n                for (int k = 0; k < possCnt[c]; k++) {\n                    uint8_t cand = poss[c][k];\n                    if (cand == old) continue;\n\n                    st[c] = cand;\n                    Eval ne = evaluator.eval(st);\n                    double o = objective(ne, pfin);\n\n                    if (better_eval_obj(ne, o, bestE, bestO)) {\n                        bestS = cand;\n                        bestE = ne;\n                        bestO = o;\n                    }\n                }\n\n                st[c] = bestS;\n                if (bestS != old) {\n                    ev = bestE;\n                    obj = bestO;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int t = 0; t < 8; t++) {\n        ROT[t][0] = t;\n        for (int k = 1; k < 4; k++) ROT[t][k] = ROT1[ROT[t][k - 1]];\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = i * N + j;\n            NEI[c][0] = (j > 0 ? c - 1 : -1);\n            NEI[c][1] = (i > 0 ? c - N : -1);\n            NEI[c][2] = (j + 1 < N ? c + 1 : -1);\n            NEI[c][3] = (i + 1 < N ? c + N : -1);\n        }\n    }\n\n    Board orig{};\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) orig[i * N + j] = (uint8_t)(s[j] - '0');\n    }\n\n    uint64_t seed = 1469598103934665603ULL;\n    for (int c = 0; c < C; c++) {\n        seed ^= (uint64_t)(orig[c] + 1);\n        seed *= 1099511628211ULL;\n    }\n    seed ^= 0x9e3779b97f4a7c15ULL;\n    RNG rng(seed);\n\n    auto start = chrono::steady_clock::now();\n    const double TL = 1.95;\n    const double INIT_END = 0.39;\n    const double SA_END = TL - 0.12;\n\n    array<array<uint8_t, 4>, C> poss{};\n    array<uint8_t, C> possCnt{};\n    vector<int> allCells(C);\n    iota(allCells.begin(), allCells.end(), 0);\n    vector<int> twoCells;\n    array<uint8_t, C> isTwo{};\n    vector<pair<int,int>> twoPairs;\n\n    for (int c = 0; c < C; c++) {\n        int t = orig[c];\n        if (t <= 3) {\n            possCnt[c] = 4;\n            for (int k = 0; k < 4; k++) poss[c][k] = (uint8_t)ROT[t][k];\n        } else if (t <= 5) {\n            possCnt[c] = 2;\n            poss[c][0] = 4;\n            poss[c][1] = 5;\n            twoCells.push_back(c);\n            isTwo[c] = 1;\n        } else {\n            possCnt[c] = 2;\n            poss[c][0] = 6;\n            poss[c][1] = 7;\n            twoCells.push_back(c);\n            isTwo[c] = 1;\n        }\n    }\n\n    for (int c = 0; c < C; c++) {\n        if (!isTwo[c]) continue;\n        int r = NEI[c][2], d = NEI[c][3];\n        if (r >= 0 && isTwo[r]) twoPairs.emplace_back(c, r);\n        if (d >= 0 && isTwo[d]) twoPairs.emplace_back(c, d);\n    }\n\n    Evaluator evaluator;\n\n    Board bestState = orig;\n    Eval bestEval = evaluator.eval(bestState);\n\n    vector<Elite> elites;\n    add_elite(elites, bestState, bestEval);\n\n    // Initialization\n    int trial = 0;\n    while (elapsed_sec(start) < INIT_END && trial < 18) {\n        Board cand{};\n\n        if (trial == 0) {\n            cand = orig;\n        } else if (trial == 1) {\n            fill_random(cand, poss, possCnt, rng);\n        } else if (trial >= 2 && trial <= 5) {\n            for (int i = 0; i < N; i++) {\n                for (int j = 0; j < N; j++) {\n                    int c = i * N + j;\n                    if (possCnt[c] == 2) {\n                        if (trial == 2) cand[c] = poss[c][0];\n                        else if (trial == 3) cand[c] = poss[c][1];\n                        else if (trial == 4) cand[c] = ((i + j) & 1) ? poss[c][0] : poss[c][1];\n                        else cand[c] = (i & 1) ? poss[c][0] : poss[c][1];\n                    } else {\n                        int t = orig[c];\n                        if (trial <= 3) cand[c] = (uint8_t)t;\n                        else if (trial == 4) cand[c] = (uint8_t)ROT[t][(i + j) & 3];\n                        else cand[c] = (uint8_t)ROT[t][(i + 2 * j) & 3];\n                    }\n                }\n            }\n        } else {\n            int mode = trial % 4;\n            if (mode == 0 && !elites.empty()) {\n                cand = elites[pick_elite_tournament(elites, rng)].st;\n                int flips = 12 + (int)(rng.next_u32() % 36);\n                for (int f = 0; f < flips; f++) {\n                    int c = (int)(rng.next_u32() % C);\n                    cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                }\n            } else if (mode == 1 && elites.size() >= 2) {\n                int a = pick_elite_tournament(elites, rng);\n                int b = pick_elite_tournament(elites, rng);\n                while (b == a) b = pick_elite_tournament(elites, rng);\n                for (int c = 0; c < C; c++) {\n                    cand[c] = ((rng.next_u32() & 1) ? elites[a].st[c] : elites[b].st[c]);\n                }\n                int flips = 10 + (int)(rng.next_u32() % 30);\n                for (int f = 0; f < flips; f++) {\n                    int c = (int)(rng.next_u32() % C);\n                    cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                }\n            } else {\n                fill_random(cand, poss, possCnt, rng);\n            }\n        }\n\n        int passes = (trial == 0 ? 8 : (trial < 6 ? 5 : 3));\n        improve_connectivity(cand, poss, possCnt, rng, passes);\n\n        Eval e = evaluator.eval(cand);\n\n        if (elapsed_sec(start) < INIT_END - 0.01) {\n            double p0 = 0.20;\n            int bt = (trial < 8 ? 130 : 70);\n            quick_binary_descent(cand, e, twoCells, poss, evaluator, rng, p0, bt, start, INIT_END);\n\n            double obj = objective(e, p0);\n            int desc = (trial < 5 ? 80 : 40);\n            subset_descent(cand, e, obj, allCells, desc, poss, possCnt, evaluator, rng, p0, start, INIT_END);\n        }\n\n        if (better_best(e, bestEval)) {\n            bestEval = e;\n            bestState = cand;\n        }\n        add_elite(elites, cand, e);\n        trial++;\n    }\n\n    int si = 0;\n    for (int i = 1; i < (int)elites.size(); i++) if (elites[i].key > elites[si].key) si = i;\n\n    Board curState = elites[si].st;\n    Eval curEval = elites[si].ev;\n    if (better_best(curEval, bestEval)) {\n        bestEval = curEval;\n        bestState = curState;\n    }\n\n    auto estimate_T0 = [&](const Board& st, const Eval& ev) {\n        double base = objective(ev, 0.0);\n        Board tmp = st;\n        double sum = 0.0;\n        int cnt = 0;\n        for (int t = 0; t < 40; t++) {\n            int c = (int)(rng.next_u32() % C);\n            uint8_t old = tmp[c];\n            tmp[c] = random_other_state(c, old, poss, possCnt, rng);\n            Eval ne = evaluator.eval(tmp);\n            sum += fabs(objective(ne, 0.0) - base);\n            tmp[c] = old;\n            cnt++;\n        }\n        double avg = (cnt ? sum / cnt : 80.0);\n        double T0 = avg * 3.0;\n        if (T0 < 40.0) T0 = 40.0;\n        if (T0 > 2500.0) T0 = 2500.0;\n        return T0;\n    };\n\n    double T0 = estimate_T0(curState, curEval);\n    double T1 = max(0.03, T0 * 0.0007);\n\n    long long iter = 0;\n    double lastBestSec = elapsed_sec(start);\n    double lastRestartSec = lastBestSec;\n    double lastIntenseSec = lastBestSec;\n    bool forcedDiv = false;\n\n    double progress = min(1.0, elapsed_sec(start) / TL);\n    double temp = T0 * pow(T1 / T0, progress);\n    double curObj = objective(curEval, progress);\n\n    auto diversify_block = [&](double durationSec, int flipL, int flipR) {\n        double now = elapsed_sec(start);\n        double dl = min(SA_END, now + durationSec);\n\n        for (int it = 0; it < 8 && elapsed_sec(start) < dl; it++) {\n            Board cand{};\n            if (elites.size() >= 2 && (rng.next_u32() % 100) < 50) {\n                int a = pick_elite_tournament(elites, rng);\n                int b = pick_elite_tournament(elites, rng);\n                while (b == a) b = pick_elite_tournament(elites, rng);\n                for (int c = 0; c < C; c++) {\n                    cand[c] = ((rng.next_u32() & 1) ? elites[a].st[c] : elites[b].st[c]);\n                }\n            } else if (!elites.empty()) {\n                cand = elites[pick_elite_tournament(elites, rng)].st;\n            } else {\n                fill_random(cand, poss, possCnt, rng);\n            }\n\n            int flips = flipL + (int)(rng.next_u32() % (uint32_t)(max(1, flipR - flipL + 1)));\n            for (int f = 0; f < flips; f++) {\n                int c = (int)(rng.next_u32() % C);\n                cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n            }\n\n            if ((rng.next_u32() % 100) < 70) improve_connectivity(cand, poss, possCnt, rng, 1);\n            Eval e = evaluator.eval(cand);\n\n            if (elapsed_sec(start) < dl - 0.004) {\n                double pnow = min(1.0, elapsed_sec(start) / TL);\n                quick_binary_descent(cand, e, twoCells, poss, evaluator, rng, pnow, 45, start, dl);\n            }\n\n            double o = objective(e, min(1.0, elapsed_sec(start) / TL));\n            if (o > curObj) {\n                curState = cand;\n                curEval = e;\n                curObj = o;\n            }\n\n            if (better_best(e, bestEval)) {\n                bestEval = e;\n                bestState = cand;\n                lastBestSec = elapsed_sec(start);\n            }\n            add_elite(elites, cand, e);\n        }\n    };\n\n    while (true) {\n        if ((iter & 127LL) == 0) {\n            double now = elapsed_sec(start);\n            if (now >= SA_END) break;\n\n            progress = min(1.0, now / TL);\n            temp = T0 * pow(T1 / T0, progress);\n            curObj = objective(curEval, progress);\n\n            if (now - lastBestSec > 0.22 && now - lastRestartSec > 0.08 && !elites.empty()) {\n                Board cand{};\n                bool doCross = (elites.size() >= 2 && (rng.next_u32() % 100) < 35);\n\n                if (doCross) {\n                    int a = pick_elite_tournament(elites, rng);\n                    int b = pick_elite_tournament(elites, rng);\n                    while (b == a) b = pick_elite_tournament(elites, rng);\n                    for (int c = 0; c < C; c++) {\n                        cand[c] = ((rng.next_u32() & 1) ? elites[a].st[c] : elites[b].st[c]);\n                    }\n                } else {\n                    cand = elites[pick_elite_tournament(elites, rng)].st;\n                }\n\n                int maxFlip = 12 + (int)((1.0 - progress) * 38.0);\n                int flips = 6 + (int)(rng.next_u32() % (uint32_t)(maxFlip + 1));\n                for (int f = 0; f < flips; f++) {\n                    int c = ((rng.next_u32() % 100) < 60) ? pick_bad_cell(cand, rng, 4)\n                                                          : (int)(rng.next_u32() % C);\n                    cand[c] = random_other_state(c, cand[c], poss, possCnt, rng);\n                }\n\n                if (progress < 0.75 && (rng.next_u32() % 100) < 70) {\n                    improve_connectivity(cand, poss, possCnt, rng, 1);\n                }\n\n                curState = cand;\n                curEval = evaluator.eval(curState);\n                curObj = objective(curEval, progress);\n                add_elite(elites, curState, curEval);\n\n                if (better_best(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    add_elite(elites, bestState, bestEval);\n                    lastBestSec = now;\n                }\n                lastRestartSec = now;\n            }\n\n            if (!forcedDiv && progress > 0.62 && bestEval.contest < 5500 && now < SA_END - 0.10) {\n                diversify_block(0.032, 24, 72);\n                forcedDiv = true;\n            }\n\n            if (now - lastIntenseSec > 0.11 && progress < 0.93 && now < SA_END - 0.015) {\n                double dl = min(SA_END, now + 0.010);\n                double pnow = max(0.20, progress);\n\n                quick_binary_descent(curState, curEval, twoCells, poss, evaluator, rng, pnow, 60, start, dl);\n                curObj = objective(curEval, progress);\n\n                pair_binary_descent(curState, curEval, curObj, twoPairs, poss, evaluator, rng, pnow, 35, start, dl);\n                subset_descent(curState, curEval, curObj, allCells, 35, poss, possCnt, evaluator, rng, pnow, start, dl);\n\n                if (better_best(curEval, bestEval)) {\n                    bestEval = curEval;\n                    bestState = curState;\n                    add_elite(elites, bestState, bestEval);\n                    lastBestSec = elapsed_sec(start);\n                }\n                add_elite(elites, curState, curEval);\n                lastIntenseSec = now;\n            }\n\n            if (progress > 0.90 && (iter & 2047LL) == 0) {\n                curState = bestState;\n                curEval = bestEval;\n                curObj = objective(curEval, progress);\n            }\n        }\n\n        int changedIdx[16];\n        uint8_t oldVal[16];\n        int changed = 0;\n\n        int mt = (int)(rng.next_u32() % 100);\n        int th1, th2, th3, th4, th5;\n        if (progress < 0.55) {\n            th1 = 45; th2 = 65; th3 = 78; th4 = 88; th5 = 97;\n        } else if (progress < 0.82) {\n            th1 = 50; th2 = 73; th3 = 84; th4 = 93; th5 = 99;\n        } else {\n            th1 = 56; th2 = 80; th3 = 89; th4 = 97; th5 = 100;\n        }\n\n        if (mt < th1) {\n            int c = ((rng.next_u32() % 100) < 72) ? pick_bad_cell(curState, rng, 6)\n                                                  : (int)(rng.next_u32() % C);\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changed = 1;\n\n            if (possCnt[c] == 4 && (rng.next_u32() & 1)) {\n                uint8_t old = curState[c];\n                int bestSc = INT_MIN;\n                uint8_t bestSt = old;\n                for (int k = 0; k < 4; k++) {\n                    uint8_t cand = poss[c][k];\n                    int sc = local_potential(c, cand, curState);\n                    if (sc > bestSc || (sc == bestSc && (rng.next_u32() & 1))) {\n                        bestSc = sc;\n                        bestSt = cand;\n                    }\n                }\n                if (bestSt == old) bestSt = random_other_state(c, old, poss, possCnt, rng);\n                curState[c] = bestSt;\n            } else {\n                curState[c] = random_other_state(c, curState[c], poss, possCnt, rng);\n            }\n        } else if (mt < th2 && !twoCells.empty()) {\n            int c = pick_bad_two(curState, twoCells, rng, 6);\n            changedIdx[0] = c;\n            oldVal[0] = curState[c];\n            changed = 1;\n            curState[c] = (curState[c] == poss[c][0] ? poss[c][1] : poss[c][0]);\n        } else if (mt < th3) {\n            int c1 = pick_bad_cell(curState, rng, 5);\n            int c2 = -1;\n            int d0 = (int)(rng.next_u32() & 3);\n            for (int tt = 0; tt < 4; tt++) {\n                int d = (d0 + tt) & 3;\n                if (NEI[c1][d] >= 0) {\n                    c2 = NEI[c1][d];\n                    break;\n                }\n            }\n            if (c2 < 0) c2 = (int)(rng.next_u32() % C);\n            if (c2 == c1) c2 = (c1 + 1) % C;\n\n            changedIdx[0] = c1; oldVal[0] = curState[c1];\n            changedIdx[1] = c2; oldVal[1] = curState[c2];\n            changed = 2;\n\n            curState[c1] = random_other_state(c1, curState[c1], poss, possCnt, rng);\n            curState[c2] = random_other_state(c2, curState[c2], poss, possCnt, rng);\n        } else if (mt < th4 && !twoPairs.empty()) {\n            auto [c1, c2] = twoPairs[rng.next_u32() % twoPairs.size()];\n            changedIdx[0] = c1; oldVal[0] = curState[c1];\n            changedIdx[1] = c2; oldVal[1] = curState[c2];\n            changed = 2;\n            curState[c1] = (curState[c1] == poss[c1][0] ? poss[c1][1] : poss[c1][0]);\n            curState[c2] = (curState[c2] == poss[c2][0] ? poss[c2][1] : poss[c2][0]);\n        } else if (mt < th5) {\n            int i = (int)(rng.next_u32() % (N - 1));\n            int j = (int)(rng.next_u32() % (N - 1));\n            int c0 = i * N + j;\n            int cells[4] = {c0, c0 + 1, c0 + N, c0 + N + 1};\n            int delta = (rng.next_u32() & 1) ? 1 : 3;\n\n            changed = 4;\n            for (int k = 0; k < 4; k++) {\n                int c = cells[k];\n                changedIdx[k] = c;\n                oldVal[k] = curState[c];\n                curState[c] = (uint8_t)ROT[curState[c]][delta];\n            }\n        } else {\n            int i = (int)(rng.next_u32() % (N - 2));\n            int j = (int)(rng.next_u32() % (N - 2));\n            changed = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    int c = (i + di) * N + (j + dj);\n                    changedIdx[changed] = c;\n                    oldVal[changed] = curState[c];\n                    changed++;\n                    curState[c] = poss[c][(possCnt[c] == 4) ? (rng.next_u32() & 3) : (rng.next_u32() & 1)];\n                }\n            }\n        }\n\n        Eval ne = evaluator.eval(curState);\n        double newObj = objective(ne, progress);\n\n        bool accept = false;\n        if (better_best(ne, curEval)) {\n            accept = true;\n        } else {\n            double diff = newObj - curObj;\n            if (diff >= 0.0) accept = true;\n            else if (rng.next_double() < exp(diff / max(1e-9, temp))) accept = true;\n        }\n\n        if (accept) {\n            curEval = ne;\n            curObj = newObj;\n\n            if (better_best(curEval, bestEval)) {\n                bestEval = curEval;\n                bestState = curState;\n                add_elite(elites, bestState, bestEval);\n                lastBestSec = elapsed_sec(start);\n            } else if ((iter & 2047LL) == 0 && (rng.next_u32() % 100) < 15) {\n                add_elite(elites, curState, curEval);\n            }\n        } else {\n            for (int k = 0; k < changed; k++) curState[changedIdx[k]] = oldVal[k];\n        }\n\n        iter++;\n    }\n\n    // Final polish\n    double deadline = TL - 0.002;\n\n    Board finState = bestState;\n    Eval finEval = bestEval;\n\n    double now = elapsed_sec(start);\n    bool weak = (bestEval.contest < 6500);\n    int altIdx = -1;\n\n    if (weak && elites.size() >= 2) {\n        vector<int> ordE(elites.size());\n        iota(ordE.begin(), ordE.end(), 0);\n        sort(ordE.begin(), ordE.end(), [&](int a, int b) {\n            if (better_best(elites[a].ev, elites[b].ev)) return true;\n            if (better_best(elites[b].ev, elites[a].ev)) return false;\n            return elites[a].key > elites[b].key;\n        });\n        for (int id : ordE) {\n            if (hamming_dist(elites[id].st, finState) > 20) {\n                altIdx = id;\n                break;\n            }\n        }\n    }\n\n    if (altIdx >= 0 && deadline - now > 0.06) {\n        double split = now + 0.58 * (deadline - now);\n\n        Board s1 = finState;\n        Eval e1 = finEval;\n        polish_candidate(s1, e1, allCells, twoCells, twoPairs, poss, possCnt, evaluator, rng, start, split);\n\n        Board s2 = elites[altIdx].st;\n        Eval e2 = elites[altIdx].ev;\n        polish_candidate(s2, e2, allCells, twoCells, twoPairs, poss, possCnt, evaluator, rng, start, deadline);\n\n        if (better_best(e2, e1) || (!better_best(e1, e2) && elite_key(e2) > elite_key(e1))) {\n            finState = s2;\n            finEval = e2;\n        } else {\n            finState = s1;\n            finEval = e1;\n            if (elapsed_sec(start) < deadline) {\n                polish_candidate(finState, finEval, allCells, twoCells, twoPairs, poss, possCnt, evaluator, rng, start, deadline);\n            }\n        }\n    } else {\n        polish_candidate(finState, finEval, allCells, twoCells, twoPairs, poss, possCnt, evaluator, rng, start, deadline);\n    }\n\n    if (better_best(finEval, bestEval) ||\n        (!better_best(bestEval, finEval) && elite_key(finEval) > elite_key(bestEval))) {\n        bestEval = finEval;\n        bestState = finState;\n    }\n\n    string ans(C, '0');\n    for (int c = 0; c < C; c++) {\n        int o = orig[c], f = bestState[c];\n        int rot = 0;\n        for (; rot < 4; rot++) if (ROT[o][rot] == f) break;\n        if (rot == 4) rot = 0;\n        ans[c] = char('0' + rot);\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N_global, T_global, NN_global, FULLV;\nint NEI[100][4];\nuint64_t zobrist[100][16];\nbool CONN[2][16][16]; // 0: horizontal right-left, 1: vertical down-up\n\nconst int OPP[4] = {1, 0, 3, 2};\nconst char OPCH[4] = {'U', 'D', 'L', 'R'};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ULL) : x(seed) {}\n    inline uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n};\n\nstatic inline uint64_t splitmix64_seed(uint64_t &x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\nstatic inline uint64_t splitmix64_stat(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\nstruct FastHash {\n    size_t operator()(uint64_t x) const noexcept {\n        static const uint64_t FIXED_RANDOM =\n            (uint64_t)chrono::steady_clock::now().time_since_epoch().count();\n        return (size_t)splitmix64_stat(x + FIXED_RANDOM);\n    }\n};\n\nusing Board = array<uint8_t, 100>;\n\nstruct AdjEdge {\n    uint8_t u, v;\n    uint8_t typ; // 0 horizontal, 1 vertical\n};\nvector<AdjEdge> g_edges;\n\ninline int uf_find(int x, int parent[]) {\n    while (parent[x] != x) {\n        parent[x] = parent[parent[x]];\n        x = parent[x];\n    }\n    return x;\n}\n\nstruct EvalInfo {\n    int S = 0;         // largest tree component\n    int cmax = 0;      // largest connected component\n    int cmaxEx = 0;    // cycle excess of largest connected component\n    int totalEx = 0;   // sum of cycle excesses\n    int totalEdges = 0;\n    int compCnt = 0;\n\n    int pot4 = 0;      // max(v - 4*ex)\n    int pot7 = 0;      // max(v - 7*ex)\n    int near1 = 0;     // max v with ex <= 1\n    int treeSum = 0;   // sum of v for ex==0 components\n};\n\ninline EvalInfo evaluate_state(const Board &b) {\n    int parent[100];\n    int sz[100];\n    int ed[100];\n\n    for (int i = 0; i < NN_global; i++) {\n        if (b[i] != 0) {\n            parent[i] = i;\n            sz[i] = 1;\n            ed[i] = 0;\n        } else {\n            parent[i] = -1;\n        }\n    }\n\n    for (const auto &e : g_edges) {\n        uint8_t a = b[e.u];\n        uint8_t c = b[e.v];\n        if (a != 0 && c != 0 && CONN[e.typ][a][c]) {\n            int ra = uf_find((int)e.u, parent);\n            int rb = uf_find((int)e.v, parent);\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\n    EvalInfo out;\n    bool first = true;\n    for (int i = 0; i < NN_global; i++) {\n        if (parent[i] == i) {\n            out.compCnt++;\n            int v = sz[i];\n            int e = ed[i];\n            int ex = e - (v - 1);\n\n            if (ex == 0) {\n                out.S = max(out.S, v);\n                out.treeSum += v;\n            }\n            if (ex <= 1) out.near1 = max(out.near1, v);\n\n            out.pot4 = max(out.pot4, v - 4 * ex);\n            out.pot7 = max(out.pot7, v - 7 * ex);\n\n            out.totalEx += ex;\n            out.totalEdges += e;\n\n            if (first || v > out.cmax || (v == out.cmax && ex < out.cmaxEx)) {\n                out.cmax = v;\n                out.cmaxEx = ex;\n                first = false;\n            }\n        }\n    }\n\n    if (out.S < 1) out.S = 1;\n    if (out.cmax < 1) out.cmax = 1;\n    if (out.pot4 < 0) out.pot4 = 0;\n    if (out.pot7 < 0) out.pot7 = 0;\n    return out;\n}\n\ninline long long calc_key(const EvalInfo &e, int depth, int mode) {\n    int r = (T_global > 0 ? depth * 1000 / T_global : 1000);\n    int edgeGap = abs(e.totalEdges - (FULLV - 1));\n    int compGap = max(0, e.compCnt - 1);\n\n    if (mode == 0) { // connect-first\n        if (r < 300) {\n            return 4200000LL * e.cmax\n                 + 2700000LL * e.pot4\n                 + 1000000LL * e.S\n                 +  500000LL * e.near1\n                 +  120000LL * e.treeSum\n                 - 1100000LL * e.cmaxEx\n                 -   50000LL * e.totalEx\n                 -  150000LL * compGap\n                 -   12000LL * edgeGap;\n        } else if (r < 700) {\n            return 3000000LL * e.cmax\n                 + 3200000LL * e.pot4\n                 + 2400000LL * e.S\n                 +  900000LL * e.near1\n                 +  220000LL * e.treeSum\n                 - 1700000LL * e.cmaxEx\n                 -   75000LL * e.totalEx\n                 -  220000LL * compGap\n                 -   18000LL * edgeGap;\n        } else {\n            return 5600000LL * e.S\n                 + 2600000LL * e.pot4\n                 + 1300000LL * e.near1\n                 +  900000LL * e.cmax\n                 +  320000LL * e.treeSum\n                 - 2300000LL * e.cmaxEx\n                 -  110000LL * e.totalEx\n                 -  260000LL * compGap\n                 -   24000LL * edgeGap;\n        }\n    } else if (mode == 1) { // balanced\n        if (r < 250) {\n            return 3800000LL * e.cmax\n                 + 2500000LL * e.pot4\n                 + 1700000LL * e.S\n                 +  650000LL * e.near1\n                 +  120000LL * e.treeSum\n                 - 1300000LL * e.cmaxEx\n                 -   55000LL * e.totalEx\n                 -  180000LL * compGap\n                 -   15000LL * edgeGap;\n        } else if (r < 700) {\n            return 4200000LL * e.pot4\n                 + 4000000LL * e.S\n                 + 1700000LL * e.cmax\n                 + 1200000LL * e.near1\n                 +  320000LL * e.treeSum\n                 - 2000000LL * e.cmaxEx\n                 -   90000LL * e.totalEx\n                 -  240000LL * compGap\n                 -   22000LL * edgeGap;\n        } else {\n            return 7000000LL * e.S\n                 + 2100000LL * e.near1\n                 + 1900000LL * e.pot7\n                 +  750000LL * e.cmax\n                 +  420000LL * e.treeSum\n                 - 2500000LL * e.cmaxEx\n                 -  130000LL * e.totalEx\n                 -  280000LL * compGap\n                 -   26000LL * edgeGap;\n        }\n    } else { // mode 2: cycle-break / endgame\n        if (r < 500) {\n            return 7700000LL * e.S\n                 + 3400000LL * e.near1\n                 + 2500000LL * e.pot7\n                 +  900000LL * e.treeSum\n                 +  500000LL * e.cmax\n                 - 2900000LL * e.cmaxEx\n                 -  170000LL * e.totalEx\n                 -  260000LL * compGap\n                 -   21000LL * edgeGap;\n        } else {\n            return 9500000LL * e.S\n                 + 4000000LL * e.near1\n                 + 3000000LL * e.pot7\n                 + 1200000LL * e.treeSum\n                 +  420000LL * e.cmax\n                 - 3400000LL * e.cmaxEx\n                 -  220000LL * e.totalEx\n                 -  320000LL * compGap\n                 -   28000LL * edgeGap;\n        }\n    }\n}\n\ninline long long calc_div_score(const EvalInfo &e) {\n    return 3700000LL * e.pot4\n         + 3000000LL * e.near1\n         + 2700000LL * e.S\n         +  800000LL * e.cmax\n         - 1300000LL * e.cmaxEx\n         -   80000LL * e.totalEx\n         -  120000LL * max(0, e.compCnt - 1);\n}\n\ninline uint64_t compute_hash(const Board &b) {\n    uint64_t h = 0;\n    for (int i = 0; i < NN_global; i++) h ^= zobrist[i][b[i]];\n    return h;\n}\ninline uint64_t state_key(uint64_t rawHash, uint8_t lastDir) {\n    return rawHash ^ (0x9e3779b97f4a7c15ULL * (uint64_t)(lastDir + 1));\n}\n\nstruct SearchResult {\n    string path;\n    Board board{};\n    int blank = 0;\n    int lastDir = 4;\n    int S = 0;\n    int cmax = 0;\n    int cEx = 0;\n    long long key = LLONG_MIN;\n    long long divScore = LLONG_MIN;\n    uint64_t hk = 0;\n};\n\ninline void fill_result_metrics(SearchResult &r, const EvalInfo &e, int mode) {\n    r.S = e.S;\n    r.cmax = e.cmax;\n    r.cEx = e.cmaxEx;\n    r.key = calc_key(e, (int)r.path.size(), mode);\n    r.divScore = calc_div_score(e);\n    uint64_t h = compute_hash(r.board);\n    r.hk = state_key(h, (uint8_t)r.lastDir);\n}\n\ninline bool better_result(const SearchResult &a, const SearchResult &b) {\n    if (a.S != b.S) return a.S > b.S;\n    if (a.S == FULLV && a.path.size() != b.path.size()) return a.path.size() < b.path.size();\n    if (a.cmax != b.cmax) return a.cmax > b.cmax;\n    if (a.cEx != b.cEx) return a.cEx < b.cEx;\n    if (a.divScore != b.divScore) return a.divScore > b.divScore;\n    return a.path.size() < b.path.size();\n}\ninline bool better_div(const SearchResult &a, const SearchResult &b) {\n    if (a.divScore != b.divScore) return a.divScore > b.divScore;\n    if (a.S != b.S) return a.S > b.S;\n    if (a.cmax != b.cmax) return a.cmax > b.cmax;\n    if (a.cEx != b.cEx) return a.cEx < b.cEx;\n    return a.path.size() < b.path.size();\n}\ninline bool better_tuple(int S, int cmax, int cEx, int len, const SearchResult &best) {\n    if (S != best.S) return S > best.S;\n    if (S == FULLV && len != (int)best.path.size()) return len < (int)best.path.size();\n    if (cmax != best.cmax) return cmax > best.cmax;\n    if (cEx != best.cEx) return cEx < best.cEx;\n    return len < (int)best.path.size();\n}\n\nstruct Node {\n    Board b{};\n    uint8_t blank = 0;\n    uint16_t depth = 0;\n    int parent = -1;\n    uint8_t lastDir = 4;\n    char mv = '?';\n    uint64_t hash = 0;\n\n    int S = 0, cmax = 0, cEx = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN;\n};\n\nstruct Cand {\n    int parent = -1;\n    uint8_t nb = 0;\n    uint8_t lastDir = 4;\n    char mv = '?';\n    uint16_t depth = 0;\n    uint64_t hash = 0;\n    uint64_t sk = 0;\n\n    int S = 0, cmax = 0, cEx = 0;\n    long long key = LLONG_MIN;\n    long long pri = LLONG_MIN;\n};\n\nstruct BeamOutput {\n    SearchResult objBest;\n    SearchResult keyBest;\n};\n\nSearchResult make_result_from_node(const SearchResult &start, const vector<Node> &nodes, int nid, int mode) {\n    SearchResult r;\n    string suffix;\n    for (int cur = nid; nodes[cur].parent != -1; cur = nodes[cur].parent) {\n        suffix.push_back(nodes[cur].mv);\n    }\n    reverse(suffix.begin(), suffix.end());\n\n    r.path = start.path + suffix;\n    r.board = nodes[nid].b;\n    r.blank = nodes[nid].blank;\n    r.lastDir = nodes[nid].lastDir;\n    r.S = nodes[nid].S;\n    r.cmax = nodes[nid].cmax;\n    r.cEx = nodes[nid].cEx;\n    r.key = nodes[nid].key;\n\n    EvalInfo e = evaluate_state(r.board);\n    r.divScore = calc_div_score(e);\n    r.hk = state_key(nodes[nid].hash, (uint8_t)r.lastDir);\n    (void)mode;\n    return r;\n}\n\nBeamOutput run_beam(\n    const SearchResult &start,\n    int width,\n    int mode,\n    int depthLimit,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng,\n    unordered_map<uint64_t, uint16_t, FastHash> *globalVisit = nullptr\n) {\n    BeamOutput out;\n    out.objBest = start;\n    out.keyBest = start;\n\n    int startDepth = (int)start.path.size();\n    if (width <= 0 || startDepth >= depthLimit) {\n        EvalInfo e = evaluate_state(start.board);\n        SearchResult s = start;\n        fill_result_metrics(s, e, mode);\n        out.objBest = s;\n        out.keyBest = s;\n        return out;\n    }\n\n    const int NODE_LIMIT = 280000;\n\n    vector<Node> nodes;\n    size_t est = (size_t)(depthLimit - startDepth + 1) * (size_t)width + 2048ULL;\n    if (est > (size_t)NODE_LIMIT) est = (size_t)NODE_LIMIT;\n    nodes.reserve(est);\n\n    Node root;\n    root.b = start.board;\n    root.blank = (uint8_t)start.blank;\n    root.depth = (uint16_t)startDepth;\n    root.parent = -1;\n    root.lastDir = (uint8_t)start.lastDir;\n    root.mv = '?';\n    root.hash = compute_hash(root.b);\n    {\n        EvalInfo e0 = evaluate_state(root.b);\n        root.S = e0.S;\n        root.cmax = e0.cmax;\n        root.cEx = e0.cmaxEx;\n        root.key = calc_key(e0, startDepth, mode);\n        root.pri = root.key;\n    }\n    nodes.push_back(root);\n\n    auto better_node_obj = [&](int a, int b) -> bool {\n        const Node &x = nodes[a];\n        const Node &y = nodes[b];\n        if (x.S != y.S) return x.S > y.S;\n        if (x.S == FULLV && x.depth != y.depth) return x.depth < y.depth;\n        if (x.cmax != y.cmax) return x.cmax > y.cmax;\n        if (x.cEx != y.cEx) return x.cEx < y.cEx;\n        if (x.key != y.key) return x.key > y.key;\n        return x.depth < y.depth;\n    };\n    auto better_cand_obj = [&](const Cand &x, const Cand &y) -> bool {\n        if (x.S != y.S) return x.S > y.S;\n        if (x.cmax != y.cmax) return x.cmax > y.cmax;\n        if (x.cEx != y.cEx) return x.cEx < y.cEx;\n        return x.key > y.key;\n    };\n\n    int bestObjId = 0;\n    int bestKeyId = 0;\n\n    vector<int> beam, nextBeam;\n    beam.reserve(width + 8);\n    nextBeam.reserve(width + 8);\n    beam.push_back(0);\n\n    unordered_map<uint64_t, uint16_t, FastHash> seenDepth;\n    seenDepth.max_load_factor(0.7f);\n    seenDepth.reserve((size_t)width * 64 + 512ULL);\n    seenDepth[state_key(root.hash, root.lastDir)] = root.depth;\n\n    vector<Cand> cands;\n    cands.reserve((size_t)width * 4 + 64);\n    unordered_map<uint64_t, int, FastHash> localPos;\n    localPos.max_load_factor(0.7f);\n    localPos.reserve((size_t)width * 6 + 128);\n\n    const long long VISIT_PENALTY = 240000LL;\n\n    for (int dep = startDepth; dep < depthLimit; dep++) {\n        if ((dep & 3) == 0 && chrono::steady_clock::now() >= deadline) break;\n        if ((int)nodes.size() >= NODE_LIMIT) break;\n\n        cands.clear();\n        localPos.clear();\n\n        bool timeout = false;\n        for (int bi = 0; bi < (int)beam.size(); bi++) {\n            if ((bi & 31) == 0 && chrono::steady_clock::now() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int id = beam[bi];\n\n            Board base = nodes[id].b;\n            uint8_t curBlank = nodes[id].blank;\n            uint8_t curLast = nodes[id].lastDir;\n            uint16_t childDepth = (uint16_t)(nodes[id].depth + 1);\n            uint64_t curHash = nodes[id].hash;\n\n            for (int d = 0; d < 4; d++) {\n                if (curLast < 4 && d == OPP[curLast]) continue;\n                int nb = NEI[curBlank][d];\n                if (nb < 0) continue;\n\n                uint8_t tile = base[nb];\n                base[curBlank] = tile;\n                base[nb] = 0;\n\n                uint64_t ch = curHash\n                            ^ zobrist[curBlank][0]\n                            ^ zobrist[curBlank][tile]\n                            ^ zobrist[nb][tile]\n                            ^ zobrist[nb][0];\n                uint64_t sk = state_key(ch, (uint8_t)d);\n\n                auto itg = seenDepth.find(sk);\n                if (itg != seenDepth.end() && itg->second <= childDepth) {\n                    base[nb] = tile;\n                    base[curBlank] = 0;\n                    continue;\n                }\n\n                EvalInfo ec = evaluate_state(base);\n\n                Cand cd;\n                cd.parent = id;\n                cd.nb = (uint8_t)nb;\n                cd.lastDir = (uint8_t)d;\n                cd.mv = OPCH[d];\n                cd.depth = childDepth;\n                cd.hash = ch;\n                cd.sk = sk;\n\n                cd.S = ec.S;\n                cd.cmax = ec.cmax;\n                cd.cEx = ec.cmaxEx;\n                cd.key = calc_key(ec, childDepth, mode);\n\n                long long pri = cd.key * 1024LL + (long long)(rng.next() & 1023ULL);\n                if (globalVisit) {\n                    auto itv = globalVisit->find(sk);\n                    if (itv != globalVisit->end()) {\n                        pri -= VISIT_PENALTY * (long long)itv->second;\n                    }\n                }\n                cd.pri = pri;\n\n                auto itl = localPos.find(sk);\n                if (itl == localPos.end()) {\n                    localPos[sk] = (int)cands.size();\n                    cands.push_back(cd);\n                } else {\n                    int idx = itl->second;\n                    const Cand &old = cands[idx];\n                    if (cd.pri > old.pri || (cd.pri == old.pri && cd.key > old.key)) {\n                        cands[idx] = cd;\n                    }\n                }\n\n                base[nb] = tile;\n                base[curBlank] = 0;\n            }\n        }\n\n        if (timeout || cands.empty()) break;\n\n        int bestObjCandIdx = 0, bestKeyCandIdx = 0;\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (better_cand_obj(cands[i], cands[bestObjCandIdx])) bestObjCandIdx = i;\n            if (cands[i].key > cands[bestKeyCandIdx].key) bestKeyCandIdx = i;\n        }\n\n        int maxAdd = NODE_LIMIT - (int)nodes.size();\n        int take = min(width, (int)cands.size());\n        take = min(take, maxAdd);\n        if (take <= 0) break;\n\n        vector<int> ord((int)cands.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmpPri = [&](int a, int b) -> bool {\n            const Cand &x = cands[a];\n            const Cand &y = cands[b];\n            if (x.pri != y.pri) return x.pri > y.pri;\n            if (x.S != y.S) return x.S > y.S;\n            if (x.cmax != y.cmax) return x.cmax > y.cmax;\n            if (x.cEx != y.cEx) return x.cEx < y.cEx;\n            if (x.key != y.key) return x.key > y.key;\n            return a < b;\n        };\n\n        if ((int)ord.size() > take) {\n            nth_element(ord.begin(), ord.begin() + take, ord.end(), cmpPri);\n            ord.resize(take);\n\n            auto contains = [&](int idx) -> bool {\n                for (int v : ord) if (v == idx) return true;\n                return false;\n            };\n            auto replace_worst_with = [&](int idx) {\n                if (contains(idx) || ord.empty()) return;\n                int w = 0;\n                for (int i = 1; i < (int)ord.size(); i++) {\n                    if (cmpPri(ord[w], ord[i])) w = i; // ord[i] is worse\n                }\n                ord[w] = idx;\n            };\n            replace_worst_with(bestObjCandIdx);\n            if (bestKeyCandIdx != bestObjCandIdx) replace_worst_with(bestKeyCandIdx);\n        }\n\n        sort(ord.begin(), ord.end(), cmpPri);\n        ord.erase(unique(ord.begin(), ord.end()), ord.end());\n        if ((int)ord.size() > take) ord.resize(take);\n\n        nextBeam.clear();\n        for (int idx : ord) {\n            const Cand &c = cands[idx];\n\n            Board pb = nodes[c.parent].b;\n            uint8_t pblank = nodes[c.parent].blank;\n            uint8_t tile = pb[c.nb];\n            pb[pblank] = tile;\n            pb[c.nb] = 0;\n\n            Node child;\n            child.b = std::move(pb);\n            child.blank = c.nb;\n            child.depth = c.depth;\n            child.parent = c.parent;\n            child.lastDir = c.lastDir;\n            child.mv = c.mv;\n            child.hash = c.hash;\n            child.S = c.S;\n            child.cmax = c.cmax;\n            child.cEx = c.cEx;\n            child.key = c.key;\n            child.pri = c.pri;\n\n            nodes.push_back(std::move(child));\n            int nid = (int)nodes.size() - 1;\n            nextBeam.push_back(nid);\n\n            auto it = seenDepth.find(c.sk);\n            if (it == seenDepth.end() || it->second > c.depth) seenDepth[c.sk] = c.depth;\n\n            if (better_node_obj(nid, bestObjId)) bestObjId = nid;\n            if (nodes[nid].key > nodes[bestKeyId].key ||\n                (nodes[nid].key == nodes[bestKeyId].key && better_node_obj(nid, bestKeyId))) {\n                bestKeyId = nid;\n            }\n        }\n\n        if (nextBeam.empty()) break;\n        beam.swap(nextBeam);\n\n        if (nodes[bestObjId].S == FULLV) break;\n    }\n\n    out.objBest = make_result_from_node(start, nodes, bestObjId, mode);\n    out.keyBest = make_result_from_node(start, nodes, bestKeyId, mode);\n    return out;\n}\n\nstruct WalkOutput {\n    SearchResult bestObj;\n    SearchResult bestKey;\n};\n\nWalkOutput guided_walk(\n    const SearchResult &start,\n    int mode,\n    int greedPermille,\n    bool look2,\n    int depthLimit,\n    chrono::steady_clock::time_point deadline,\n    XorShift64 &rng,\n    unordered_map<uint64_t, uint16_t, FastHash> *globalVisit = nullptr\n) {\n    WalkOutput out;\n    int startDepth = (int)start.path.size();\n    out.bestObj = start;\n    out.bestKey = start;\n\n    if (startDepth >= depthLimit) {\n        EvalInfo e0 = evaluate_state(start.board);\n        fill_result_metrics(out.bestObj, e0, mode);\n        out.bestKey = out.bestObj;\n        return out;\n    }\n\n    Board board = start.board;\n    int blank = start.blank;\n    int lastDir = start.lastDir;\n    string path = start.path;\n\n    uint64_t hash = compute_hash(board);\n    EvalInfo curEval = evaluate_state(board);\n    long long curKey = calc_key(curEval, startDepth, mode);\n\n    out.bestObj.path = path;\n    out.bestObj.board = board;\n    out.bestObj.blank = blank;\n    out.bestObj.lastDir = lastDir;\n    out.bestObj.S = curEval.S;\n    out.bestObj.cmax = curEval.cmax;\n    out.bestObj.cEx = curEval.cmaxEx;\n    out.bestObj.key = curKey;\n    out.bestObj.divScore = calc_div_score(curEval);\n    out.bestObj.hk = state_key(hash, (uint8_t)lastDir);\n    out.bestKey = out.bestObj;\n\n    deque<uint64_t> recent;\n    recent.push_back(hash);\n    const int RECENT_WINDOW = 18;\n    const long long LOOP_PENALTY = 17000000LL;\n    const long long VISIT_PENALTY = 200000LL;\n\n    struct GCand {\n        int d = 0;\n        int nb = 0;\n        Board b{};\n        uint64_t h = 0;\n        uint64_t sk = 0;\n        EvalInfo e;\n        long long key = LLONG_MIN;\n        long long val = LLONG_MIN;\n    };\n\n    for (int step = startDepth; step < depthLimit; step++) {\n        if ((step & 15) == 0 && chrono::steady_clock::now() >= deadline) break;\n\n        GCand cs[4];\n        int m = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n            int nb = NEI[blank][d];\n            if (nb < 0) continue;\n\n            GCand c;\n            c.d = d;\n            c.nb = nb;\n            c.b = board;\n\n            uint8_t tile = c.b[nb];\n            c.b[blank] = tile;\n            c.b[nb] = 0;\n\n            c.h = hash\n                ^ zobrist[blank][0]\n                ^ zobrist[blank][tile]\n                ^ zobrist[nb][tile]\n                ^ zobrist[nb][0];\n            c.sk = state_key(c.h, (uint8_t)d);\n\n            c.e = evaluate_state(c.b);\n            c.key = calc_key(c.e, step + 1, mode);\n\n            for (uint64_t h0 : recent) {\n                if (h0 == c.h) {\n                    c.key -= LOOP_PENALTY;\n                    break;\n                }\n            }\n            if (globalVisit) {\n                auto itv = globalVisit->find(c.sk);\n                if (itv != globalVisit->end()) c.key -= VISIT_PENALTY * (long long)itv->second;\n            }\n\n            c.val = c.key;\n\n            if (look2 && step + 1 < depthLimit) {\n                long long best2 = LLONG_MIN / 4;\n                for (int d2 = 0; d2 < 4; d2++) {\n                    if (d2 == OPP[d]) continue;\n                    int nb2 = NEI[nb][d2];\n                    if (nb2 < 0) continue;\n\n                    Board b2 = c.b;\n                    uint8_t t2 = b2[nb2];\n                    b2[nb] = t2;\n                    b2[nb2] = 0;\n\n                    EvalInfo e2 = evaluate_state(b2);\n                    long long k2 = calc_key(e2, step + 2, mode);\n                    if (k2 > best2) best2 = k2;\n                }\n                if (best2 > LLONG_MIN / 8) c.val = c.key * 4 + best2;\n            }\n\n            cs[m++] = std::move(c);\n        }\n\n        if (m == 0) break;\n\n        sort(cs, cs + m, [](const GCand &a, const GCand &b) {\n            if (a.val != b.val) return a.val > b.val;\n            return a.key > b.key;\n        });\n\n        int pick = 0;\n        uint64_t rr = rng.next() % 1000ULL;\n        if (m >= 2 && rr > (uint64_t)greedPermille) {\n            pick = (m == 2) ? 1 : (1 + (int)(rng.next() % (uint64_t)(m - 1)));\n        }\n\n        const GCand &ch = cs[pick];\n\n        board = ch.b;\n        blank = ch.nb;\n        lastDir = ch.d;\n        hash = ch.h;\n        curEval = ch.e;\n        curKey = ch.key;\n        path.push_back(OPCH[ch.d]);\n\n        if (better_tuple(curEval.S, curEval.cmax, curEval.cmaxEx, (int)path.size(), out.bestObj)) {\n            out.bestObj.path = path;\n            out.bestObj.board = board;\n            out.bestObj.blank = blank;\n            out.bestObj.lastDir = lastDir;\n            out.bestObj.S = curEval.S;\n            out.bestObj.cmax = curEval.cmax;\n            out.bestObj.cEx = curEval.cmaxEx;\n            out.bestObj.key = curKey;\n            out.bestObj.divScore = calc_div_score(curEval);\n            out.bestObj.hk = state_key(hash, (uint8_t)lastDir);\n            if (out.bestObj.S == FULLV) break;\n        }\n\n        if (curKey > out.bestKey.key) {\n            out.bestKey.path = path;\n            out.bestKey.board = board;\n            out.bestKey.blank = blank;\n            out.bestKey.lastDir = lastDir;\n            out.bestKey.S = curEval.S;\n            out.bestKey.cmax = curEval.cmax;\n            out.bestKey.cEx = curEval.cmaxEx;\n            out.bestKey.key = curKey;\n            out.bestKey.divScore = calc_div_score(curEval);\n            out.bestKey.hk = state_key(hash, (uint8_t)lastDir);\n        }\n\n        recent.push_back(hash);\n        if ((int)recent.size() > RECENT_WINDOW) recent.pop_front();\n    }\n\n    return out;\n}\n\nSearchResult random_perturb(\n    const SearchResult &start,\n    int steps,\n    int mode,\n    int greedPermille,\n    XorShift64 &rng\n) {\n    SearchResult cur = start;\n    int startDepth = (int)start.path.size();\n    if (startDepth >= T_global || steps <= 0) return cur;\n\n    Board board = start.board;\n    int blank = start.blank;\n    int lastDir = start.lastDir;\n    string path = start.path;\n\n    int lim = min(T_global, startDepth + steps);\n\n    struct PCand {\n        int d = 0;\n        int nb = 0;\n        Board b{};\n        EvalInfo e;\n        long long key = LLONG_MIN;\n    };\n\n    for (int step = startDepth; step < lim; step++) {\n        PCand cs[4];\n        int m = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (lastDir < 4 && d == OPP[lastDir]) continue;\n            int nb = NEI[blank][d];\n            if (nb < 0) continue;\n\n            PCand c;\n            c.d = d;\n            c.nb = nb;\n            c.b = board;\n\n            uint8_t tile = c.b[nb];\n            c.b[blank] = tile;\n            c.b[nb] = 0;\n\n            c.e = evaluate_state(c.b);\n            c.key = calc_key(c.e, step + 1, mode);\n            cs[m++] = std::move(c);\n        }\n\n        if (m == 0) break;\n\n        sort(cs, cs + m, [](const PCand &a, const PCand &b) {\n            if (a.key != b.key) return a.key > b.key;\n            return a.d < b.d;\n        });\n\n        int pick = 0;\n        uint64_t rr = rng.next() % 1000ULL;\n        if (m >= 2 && rr > (uint64_t)greedPermille) {\n            pick = (m == 2) ? 1 : (int)(rng.next() % (uint64_t)m);\n        }\n\n        board = cs[pick].b;\n        blank = cs[pick].nb;\n        lastDir = cs[pick].d;\n        path.push_back(OPCH[cs[pick].d]);\n    }\n\n    EvalInfo ef = evaluate_state(board);\n    cur.path = std::move(path);\n    cur.board = board;\n    cur.blank = blank;\n    cur.lastDir = lastDir;\n    fill_result_metrics(cur, ef, mode);\n    return cur;\n}\n\nint dir_from_char(char c) {\n    if (c == 'U') return 0;\n    if (c == 'D') return 1;\n    if (c == 'L') return 2;\n    if (c == 'R') return 3;\n    return -1;\n}\n\nSearchResult make_prefix_state(\n    const SearchResult &src,\n    int prefLen,\n    const Board &init,\n    int initBlank\n) {\n    SearchResult r;\n    r.path.clear();\n    r.board = init;\n    r.blank = initBlank;\n    r.lastDir = 4;\n\n    int lim = min(prefLen, (int)src.path.size());\n    r.path.reserve(lim);\n\n    for (int i = 0; i < lim; i++) {\n        int d = dir_from_char(src.path[i]);\n        if (d < 0) break;\n        int nb = NEI[r.blank][d];\n        if (nb < 0) break;\n        uint8_t tile = r.board[nb];\n        r.board[r.blank] = tile;\n        r.board[nb] = 0;\n        r.blank = nb;\n        r.lastDir = d;\n        r.path.push_back(src.path[i]);\n    }\n\n    EvalInfo e = evaluate_state(r.board);\n    fill_result_metrics(r, e, 1);\n    return r;\n}\n\nstring best_legal_prefix(const string &path, const Board &init, int initBlank) {\n    Board b = init;\n    int blank = initBlank;\n\n    string cur, best;\n    cur.reserve(min((int)path.size(), T_global));\n    best.reserve(min((int)path.size(), T_global));\n\n    EvalInfo e0 = evaluate_state(b);\n    int bestS = e0.S;\n    int bestLen = (bestS == FULLV ? 0 : INT_MAX);\n\n    auto better_obj = [&](int S, int len) -> bool {\n        if (S != bestS) return S > bestS;\n        if (S == FULLV) return len < bestLen;\n        return false;\n    };\n\n    for (char c : path) {\n        if ((int)cur.size() >= T_global) break;\n        int d = dir_from_char(c);\n        if (d < 0) break;\n        int nb = NEI[blank][d];\n        if (nb < 0) break; // illegal -> truncate\n\n        uint8_t tile = b[nb];\n        b[blank] = tile;\n        b[nb] = 0;\n        blank = nb;\n        cur.push_back(c);\n\n        EvalInfo e = evaluate_state(b);\n        int S = e.S;\n        int len = (int)cur.size();\n        if (better_obj(S, len)) {\n            bestS = S;\n            bestLen = len;\n            best = cur;\n        }\n    }\n\n    return best;\n}\n\ntemplate<class Comp>\nvoid insert_pool(vector<SearchResult> &pool, const SearchResult &r, int limitSize, Comp comp) {\n    for (auto &x : pool) {\n        if (x.hk == r.hk) {\n            if (comp(r, x)) x = r;\n            sort(pool.begin(), pool.end(), comp);\n            if ((int)pool.size() > limitSize) pool.resize(limitSize);\n            return;\n        }\n    }\n    pool.push_back(r);\n    sort(pool.begin(), pool.end(), comp);\n    if ((int)pool.size() > limitSize) pool.resize(limitSize);\n}\n\nconst SearchResult* pick_pool(const vector<SearchResult> &pool, XorShift64 &rng) {\n    if (pool.empty()) return nullptr;\n    int k = min((int)pool.size(), 6);\n    uint64_t r = rng.next() % 100ULL;\n    int idx;\n    if (r < 45ULL) idx = 0;\n    else if (r < 70ULL && k >= 2) idx = 1;\n    else if (r < 85ULL && k >= 3) idx = 2;\n    else idx = (int)(rng.next() % (uint64_t)k);\n    return &pool[idx];\n}\n\nint hex_to_int(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    if ('a' <= c && c <= 'f') return 10 + (c - 'a');\n    return 10 + (c - 'A');\n}\ninline int rnd_int(XorShift64 &rng, int l, int r) {\n    if (l >= r) return l;\n    return l + (int)(rng.next() % (uint64_t)(r - l + 1));\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N_global >> T_global;\n    NN_global = N_global * N_global;\n    FULLV = NN_global - 1;\n\n    Board init{};\n    int initBlank = -1;\n\n    for (int i = 0; i < N_global; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N_global; j++) {\n            int v = hex_to_int(s[j]);\n            init[i * N_global + j] = (uint8_t)v;\n            if (v == 0) initBlank = i * N_global + j;\n        }\n    }\n\n    for (int p = 0; p < NN_global; p++) {\n        int r = p / N_global;\n        int c = p % N_global;\n        NEI[p][0] = (r > 0) ? (p - N_global) : -1;            // U\n        NEI[p][1] = (r + 1 < N_global) ? (p + N_global) : -1; // D\n        NEI[p][2] = (c > 0) ? (p - 1) : -1;                   // L\n        NEI[p][3] = (c + 1 < N_global) ? (p + 1) : -1;        // R\n    }\n\n    for (int a = 0; a < 16; a++) {\n        for (int b = 0; b < 16; b++) {\n            CONN[0][a][b] = ((a & 4) && (b & 1)); // right-left\n            CONN[1][a][b] = ((a & 8) && (b & 2)); // down-up\n        }\n    }\n\n    g_edges.clear();\n    g_edges.reserve(2 * N_global * (N_global - 1));\n    for (int i = 0; i < N_global; i++) {\n        for (int j = 0; j < N_global; j++) {\n            int id = i * N_global + j;\n            if (j + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + 1), 0});\n            if (i + 1 < N_global) g_edges.push_back(AdjEdge{(uint8_t)id, (uint8_t)(id + N_global), 1});\n        }\n    }\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n    for (int i = 0; i < NN_global; i++) {\n        seed ^= (uint64_t)init[i] + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    }\n\n    uint64_t zseed = seed ^ 0xdeadbeefcafebabeULL;\n    for (int i = 0; i < 100; i++) {\n        for (int v = 0; v < 16; v++) {\n            zobrist[i][v] = splitmix64_seed(zseed);\n        }\n    }\n\n    XorShift64 rng(seed ^ 0x517cc1b727220a95ULL);\n\n    SearchResult initRes;\n    initRes.path = \"\";\n    initRes.board = init;\n    initRes.blank = initBlank;\n    initRes.lastDir = 4;\n    {\n        EvalInfo e0 = evaluate_state(initRes.board);\n        fill_result_metrics(initRes, e0, 0);\n    }\n\n    SearchResult best = initRes;\n    int depthLimit = T_global;\n\n    vector<SearchResult> poolObj, poolPot;\n    poolObj.reserve(16);\n    poolPot.reserve(16);\n\n    unordered_map<uint64_t, uint16_t, FastHash> visitCnt;\n    visitCnt.max_load_factor(0.7f);\n    visitCnt.reserve(1 << 15);\n\n    auto touch_visit = [&](const SearchResult &r) {\n        auto &x = visitCnt[r.hk];\n        if (x < 60) x++;\n    };\n\n    auto consider = [&](const SearchResult &r, bool updateBest = true) {\n        if (updateBest && better_result(r, best)) best = r;\n        insert_pool(poolObj, r, 12, better_result);\n        insert_pool(poolPot, r, 12, better_div);\n        touch_visit(r);\n\n        if (best.S == FULLV) {\n            depthLimit = min(depthLimit, (int)best.path.size() - 1);\n            if (depthLimit < 0) depthLimit = 0;\n        }\n    };\n\n    consider(initRes, true);\n\n    auto choose_start = [&](bool exploratory, bool preferPot) -> const SearchResult* {\n        const SearchResult *p = nullptr;\n        if (preferPot) {\n            p = pick_pool(poolPot, rng);\n            if (!p && exploratory) p = pick_pool(poolObj, rng);\n        } else if (!exploratory) {\n            p = pick_pool(poolObj, rng);\n            if (!p) p = pick_pool(poolPot, rng);\n        } else {\n            if ((rng.next() & 1ULL) == 0ULL) p = pick_pool(poolObj, rng);\n            else p = pick_pool(poolPot, rng);\n            if (!p) p = pick_pool(poolObj, rng);\n            if (!p) p = pick_pool(poolPot, rng);\n        }\n\n        if (!p) p = &initRes;\n        if ((int)p->path.size() >= depthLimit) {\n            const SearchResult *q = pick_pool(poolObj, rng);\n            if (q && (int)q->path.size() < depthLimit) p = q;\n            else p = &initRes;\n        }\n        return p;\n    };\n\n    auto startTime = chrono::steady_clock::now();\n    const int TIME_LIMIT_MS = 2760;\n    auto globalDeadline = startTime + chrono::milliseconds(TIME_LIMIT_MS);\n\n    auto P1 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 20 / 100);\n    auto P2 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 35 / 100);\n    auto P3 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 50 / 100);\n    auto P4 = startTime + chrono::milliseconds(TIME_LIMIT_MS * 68 / 100);\n    if (P1 > globalDeadline) P1 = globalDeadline;\n    if (P2 > globalDeadline) P2 = globalDeadline;\n    if (P3 > globalDeadline) P3 = globalDeadline;\n    if (P4 > globalDeadline) P4 = globalDeadline;\n\n    int wMain = clamp(1250000 / max(1, 2 * T_global), 160, 700);\n    if (N_global <= 7) wMain += 40;\n    if (N_global >= 10) wMain -= 20;\n    wMain = clamp(wMain, 160, 720);\n    int wMid = max(90, wMain * 3 / 4);\n    int wSmall = max(70, wMain / 2);\n\n    int Hlong = max(180, T_global / 3);\n    int Hmid = max(110, T_global / 6);\n    int Hshort = max(60, T_global / 12);\n    int Hend = max(140, T_global / 5);\n\n    // Phase 1\n    if (chrono::steady_clock::now() < P1 && depthLimit > 0) {\n        int local = min(depthLimit, Hlong);\n        if (local > 0) {\n            BeamOutput bo = run_beam(initRes, wMain, 0, local, P1, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, true);\n        }\n    }\n\n    // Phase 2\n    if (chrono::steady_clock::now() < P2 && depthLimit > 0) {\n        int local = min(depthLimit, Hlong + Hmid);\n        if (local > 0) {\n            BeamOutput bo = run_beam(initRes, wMid, 1, local, P2, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, true);\n        }\n    }\n\n    // Phase 3\n    if (chrono::steady_clock::now() < P3 && depthLimit > 0) {\n        const SearchResult *st = choose_start(true, true);\n        int local = min(depthLimit, (int)st->path.size() + Hlong);\n        if (local > (int)st->path.size()) {\n            BeamOutput bo = run_beam(*st, wMid, 2, local, P3, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, true);\n        }\n    }\n\n    // Phase 4 seed walk\n    if (chrono::steady_clock::now() < P4 && depthLimit > 0) {\n        const SearchResult *st = choose_start(true, false);\n        int local = min(depthLimit, (int)st->path.size() + Hlong);\n        auto dl = min(P4, chrono::steady_clock::now() + chrono::milliseconds(65));\n        WalkOutput wo = guided_walk(*st, 1, 860, true, local, dl, rng, &visitCnt);\n        consider(wo.bestObj, true);\n        consider(wo.bestKey, true);\n    }\n\n    int nearThr = max(2, N_global / 2);\n    int iter = 0;\n\n    while (chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n        auto now = chrono::steady_clock::now();\n\n        if (best.S == FULLV) {\n            // minimize K\n            auto dl = min(now + chrono::milliseconds(38), globalDeadline);\n            BeamOutput bo = run_beam(initRes, wSmall, 2, depthLimit, dl, rng, &visitCnt);\n            consider(bo.objBest, true);\n            consider(bo.keyBest, false);\n            continue;\n        }\n\n        if (best.S >= FULLV - nearThr) {\n            const SearchResult *st = &best;\n\n            auto dl1 = min(chrono::steady_clock::now() + chrono::milliseconds(58), globalDeadline);\n            int local1 = min(depthLimit, (int)st->path.size() + Hend);\n            if (local1 > (int)st->path.size()) {\n                BeamOutput bo = run_beam(*st, wMain, 2, local1, dl1, rng, &visitCnt);\n                consider(bo.objBest, true);\n                consider(bo.keyBest, true);\n            }\n\n            if (chrono::steady_clock::now() < globalDeadline) {\n                auto dl2 = min(chrono::steady_clock::now() + chrono::milliseconds(34), globalDeadline);\n                WalkOutput wo = guided_walk(*st, 2, 905, true, depthLimit, dl2, rng, &visitCnt);\n                consider(wo.bestObj, true);\n                consider(wo.bestKey, false);\n            }\n\n            iter++;\n            continue;\n        }\n\n        uint64_t act = rng.next() % 100ULL;\n\n        if (act < 20ULL) {\n            // long rollout from diversity pool\n            const SearchResult *st = choose_start(true, true);\n            auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(66), globalDeadline);\n            int mode = 1 + (int)(rng.next() % 2ULL); // 1 or 2\n            int greed = rnd_int(rng, 820, 940);\n            WalkOutput wo = guided_walk(*st, mode, greed, false, depthLimit, dl, rng, &visitCnt);\n            consider(wo.bestObj, true);\n            consider(wo.bestKey, false);\n\n        } else if (act < 40ULL) {\n            // local guided\n            const SearchResult *st = choose_start(true, false);\n            int horizon = min(depthLimit, (int)st->path.size() + Hmid + rnd_int(rng, 0, Hshort));\n            if (horizon > (int)st->path.size()) {\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(46), globalDeadline);\n                int mode = (int)(rng.next() % 3ULL);\n                int greed = rnd_int(rng, 760, 930);\n                bool look2 = ((rng.next() & 3ULL) == 0ULL);\n                WalkOutput wo = guided_walk(*st, mode, greed, look2, horizon, dl, rng, &visitCnt);\n                consider(wo.bestObj, true);\n                consider(wo.bestKey, false);\n            }\n\n        } else if (act < 62ULL) {\n            // perturb then short beam\n            const SearchResult *st = choose_start(true, true);\n            int steps = Hshort / 2 + rnd_int(rng, 0, Hshort);\n            int pMode = (int)(rng.next() % 2ULL);\n            int greed = rnd_int(rng, 700, 900);\n            SearchResult rp = random_perturb(*st, steps, pMode, greed, rng);\n            consider(rp, true);\n\n            if (chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n                int local = min(depthLimit, (int)rp.path.size() + Hmid + rnd_int(rng, 0, Hshort / 2));\n                if (local > (int)rp.path.size()) {\n                    auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(48), globalDeadline);\n                    BeamOutput bo = run_beam(rp, wSmall, 2, local, dl, rng, &visitCnt);\n                    consider(bo.objBest, true);\n                    consider(bo.keyBest, false);\n                }\n            }\n\n        } else if (act < 84ULL) {\n            // local beam\n            bool preferPot = ((rng.next() & 1ULL) == 0ULL);\n            const SearchResult *st = choose_start(true, preferPot);\n            int local = min(depthLimit, (int)st->path.size() + Hmid + rnd_int(rng, 0, Hshort));\n            if (local > (int)st->path.size()) {\n                int w = rnd_int(rng, wSmall, wMid);\n                int mode = (int)(rng.next() % 3ULL);\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(52), globalDeadline);\n                BeamOutput bo = run_beam(*st, w, mode, local, dl, rng, &visitCnt);\n                consider(bo.objBest, true);\n                consider(bo.keyBest, true);\n            }\n\n        } else {\n            // prefix restart from best\n            if ((int)best.path.size() >= 24) {\n                int back = min((int)best.path.size() - 1, Hmid + Hshort / 2);\n                int pref = (int)best.path.size() - rnd_int(rng, 8, max(8, back));\n                if (pref < 0) pref = 0;\n\n                SearchResult pre = make_prefix_state(best, pref, init, initBlank);\n                consider(pre, false);\n\n                int local = min(depthLimit, (int)pre.path.size() + Hmid + rnd_int(rng, 0, Hshort / 2));\n                if (local > (int)pre.path.size()) {\n                    auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(42), globalDeadline);\n                    BeamOutput bo = run_beam(pre, wSmall, 1 + (int)(rng.next() % 2ULL), local, dl, rng, &visitCnt);\n                    consider(bo.objBest, true);\n                    consider(bo.keyBest, true);\n                }\n            } else {\n                const SearchResult *st = choose_start(true, false);\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(42), globalDeadline);\n                int local = min(depthLimit, (int)st->path.size() + Hshort + rnd_int(rng, 0, Hshort));\n                WalkOutput wo = guided_walk(*st, 1, 860, false, local, dl, rng, &visitCnt);\n                consider(wo.bestObj, true);\n                consider(wo.bestKey, false);\n            }\n        }\n\n        if ((iter % 5 == 2) && chrono::steady_clock::now() < globalDeadline && depthLimit > 0) {\n            const SearchResult *top = pick_pool(poolObj, rng);\n            if (top && (int)top->path.size() < depthLimit) {\n                int local = min(depthLimit, (int)top->path.size() + Hshort);\n                auto dl = min(chrono::steady_clock::now() + chrono::milliseconds(26), globalDeadline);\n                BeamOutput bo = run_beam(*top, wSmall, 2, local, dl, rng, &visitCnt);\n                consider(bo.objBest, true);\n                consider(bo.keyBest, false);\n            }\n        }\n\n        iter++;\n    }\n\n    string out = best_legal_prefix(best.path, init, initBlank);\n    if ((int)out.size() > T_global) out.resize(T_global);\n    cout << out << '\\n';\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int x, y; };\n\nstruct Line {\n    long long x1, y1, x2, y2;\n    long long dx, dy;\n};\n\nstruct EvalKey {\n    int F = 0;\n    int def2 = 0;\n    int active = 0;\n    int waste = 0;\n    long long over = 0;\n};\n\nstatic inline bool betterKey(const EvalKey& a, const EvalKey& b) {\n    if (a.F != b.F) return a.F > b.F;\n    if (a.def2 != b.def2) return a.def2 < b.def2;\n    if (a.active != b.active) return a.active > b.active;\n    if (a.waste != b.waste) return a.waste < b.waste;\n    return a.over < b.over;\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) {\n        x = seed ? seed : 88172645463325252ull;\n    }\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    int nextInt(int l, int r) {\n        return l + (int)(nextU64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstruct State {\n    vector<vector<int>> pieces;\n    vector<int> pieceSize;\n    vector<int> pieceOf;     // -1 deleted\n    vector<int> active;\n    array<int, 11> h{};\n    int F = 0;\n    int def2 = 0;\n    int waste = 0;\n    long long over = 0;\n    vector<Line> lines;\n};\n\nstruct RunResult {\n    vector<Line> lines;\n    EvalKey key;\n};\n\nclass Solver {\n    static constexpr double PI = 3.1415926535897932384626433832795;\n    static constexpr long long BIG = (1LL << 62);\n\n    int N, K;\n    array<int, 11> a{};\n    vector<Point> pts;\n    int totalA = 0;\n    vector<long long> pen;\n\n    chrono::steady_clock::time_point t0;\n    const double TL = 2.82;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    inline long long orient(const Line& ln, const Point& p) const {\n        return ln.dx * ((long long)p.y - ln.y1) - ln.dy * ((long long)p.x - ln.x1);\n    }\n\n    inline int calcF(const array<int, 11>& h) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) s += min(a[d], h[d]);\n        return s;\n    }\n\n    inline int calcDef2(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int sat = min(a[d], h[d]);\n            int def = a[d] - sat;\n            v += def * def;\n        }\n        return v;\n    }\n\n    inline int calcWaste(const array<int, 11>& h) const {\n        int v = 0;\n        for (int d = 1; d <= 10; d++) {\n            int ex = max(0, h[d] - a[d]);\n            v += ex * ex;\n        }\n        return v;\n    }\n\n    inline EvalKey stateKey(const State& st) const {\n        return EvalKey{st.F, st.def2, (int)st.active.size(), st.waste, st.over};\n    }\n\n    inline void addPart(array<int, 11>& h, long long& over, int t, int delta) const {\n        if (t <= 0) return;\n        if (t <= 10) h[t] += delta;\n        over += (long long)delta * pen[t];\n    }\n\n    inline void addPieceState(array<int, 11>& h, long long& over, int s, int l, int delta) const {\n        if (l <= 0 || l >= s) {\n            addPart(h, over, s, delta);\n        } else {\n            addPart(h, over, l, delta);\n            addPart(h, over, s - l, delta);\n        }\n    }\n\n    inline double normTheta(double th) const {\n        while (th < 0) th += PI;\n        while (th >= PI) th -= PI;\n        return th;\n    }\n\n    Line makeLineFromNormal(double nx, double ny, double c) const {\n        const double S = 8.8e8;\n        double dx = -ny, dy = nx;\n        double cx = nx * c, cy = ny * c;\n\n        long long x1 = llround(cx + dx * S);\n        long long y1 = llround(cy + dy * S);\n        long long x2 = llround(cx - dx * S);\n        long long y2 = llround(cy - dy * S);\n\n        if (x1 == x2 && y1 == y2) x2++;\n\n        Line ln;\n        ln.x1 = x1; ln.y1 = y1;\n        ln.x2 = x2; ln.y2 = y2;\n        ln.dx = ln.x2 - ln.x1;\n        ln.dy = ln.y2 - ln.y1;\n        if (ln.dx == 0 && ln.dy == 0) {\n            ln.x2++;\n            ln.dx = 1;\n        }\n        return ln;\n    }\n\n    Line makeLine(double theta, double c) const {\n        return makeLineFromNormal(cos(theta), sin(theta), c);\n    }\n\n    Line randomGlobalLine(XorShift64& rng) const {\n        double theta = rng.nextDouble() * PI;\n        double c = (rng.nextDouble() * 2.0 - 1.0) * 9200.0;\n        return makeLine(theta, c);\n    }\n\n    EvalKey evalLine(const State& st, const Line& ln, vector<int>& L, vector<int>& R) const {\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) {\n            L[i] = 0;\n            R[i] = 0;\n        }\n\n        for (int idx : st.active) {\n            int pid = st.pieceOf[idx];\n            long long v = orient(ln, pts[idx]);\n            if (v > 0) L[pid]++;\n            else if (v < 0) R[pid]++;\n        }\n\n        array<int, 11> h2 = st.h;\n        long long over2 = st.over;\n        int removed = 0;\n\n        for (int pid = 0; pid < P; pid++) {\n            int s = st.pieceSize[pid];\n            int l = L[pid];\n            int r = R[pid];\n\n            if (l == s || r == s) continue;\n\n            removed += s - l - r;\n            over2 -= pen[s];\n            if (l > 0) over2 += pen[l];\n            if (r > 0) over2 += pen[r];\n\n            if (1 <= s && s <= 10) h2[s]--;\n            if (1 <= l && l <= 10) h2[l]++;\n            if (1 <= r && r <= 10) h2[r]++;\n        }\n\n        EvalKey key;\n        key.F = calcF(h2);\n        key.def2 = calcDef2(h2);\n        key.active = (int)st.active.size() - removed;\n        key.waste = calcWaste(h2);\n        key.over = over2;\n        return key;\n    }\n\n    void rebuildMetrics(State& st) const {\n        st.h.fill(0);\n        st.over = 0;\n        for (int s : st.pieceSize) {\n            if (1 <= s && s <= 10) st.h[s]++;\n            st.over += pen[s];\n        }\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n    }\n\n    void applyLine(State& st, const Line& ln) const {\n        vector<vector<int>> newPieces;\n        vector<int> newSizes;\n        vector<int> newActive;\n\n        newPieces.reserve(st.pieces.size() * 2 + 2);\n        newSizes.reserve(st.pieces.size() * 2 + 2);\n        newActive.reserve(st.active.size());\n\n        fill(st.pieceOf.begin(), st.pieceOf.end(), -1);\n\n        for (const auto& pc : st.pieces) {\n            vector<int> left, right;\n            left.reserve(pc.size());\n            right.reserve(pc.size());\n\n            for (int idx : pc) {\n                long long v = orient(ln, pts[idx]);\n                if (v > 0) left.push_back(idx);\n                else if (v < 0) right.push_back(idx);\n            }\n\n            if (!left.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : left) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)left.size());\n                newPieces.push_back(move(left));\n            }\n            if (!right.empty()) {\n                int id = (int)newPieces.size();\n                for (int idx : right) {\n                    st.pieceOf[idx] = id;\n                    newActive.push_back(idx);\n                }\n                newSizes.push_back((int)right.size());\n                newPieces.push_back(move(right));\n            }\n        }\n\n        st.pieces.swap(newPieces);\n        st.pieceSize.swap(newSizes);\n        st.active.swap(newActive);\n        st.lines.push_back(ln);\n        rebuildMetrics(st);\n    }\n\n    bool bestCutForTheta(const State& st, double theta, double& bestC, EvalKey& pred,\n                         vector<pair<double, int>>& ord, vector<int>& cntLeft) const {\n        int M = (int)st.active.size();\n        if (M < 2) return false;\n\n        double nx = cos(theta), ny = sin(theta);\n        ord.resize(M);\n        for (int i = 0; i < M; i++) {\n            int idx = st.active[i];\n            ord[i] = {nx * pts[idx].x + ny * pts[idx].y, idx};\n        }\n        sort(ord.begin(), ord.end(),\n             [](const auto& a, const auto& b) { return a.first < b.first; });\n\n        int P = (int)st.pieces.size();\n        for (int i = 0; i < P; i++) cntLeft[i] = 0;\n\n        array<int, 11> hcur = st.h;\n        long long overcur = st.over;\n\n        bool found = false;\n        EvalKey bestLocal{};\n        double cLocal = 0.0;\n\n        const double EPS = 1e-12;\n        int i = 0;\n        while (i < M) {\n            int j = i + 1;\n            while (j < M && fabs(ord[j].first - ord[i].first) <= EPS) j++;\n\n            for (int k = i; k < j; k++) {\n                int idx = ord[k].second;\n                int pid = st.pieceOf[idx];\n                int s = st.pieceSize[pid];\n                int oldL = cntLeft[pid];\n                int newL = oldL + 1;\n\n                addPieceState(hcur, overcur, s, oldL, -1);\n                addPieceState(hcur, overcur, s, newL, +1);\n                cntLeft[pid] = newL;\n            }\n\n            if (j < M) {\n                double lv = ord[j - 1].first;\n                double rv = ord[j].first;\n                if (rv - lv > EPS) {\n                    EvalKey key;\n                    key.F = calcF(hcur);\n                    key.def2 = calcDef2(hcur);\n                    key.active = M;\n                    key.waste = calcWaste(hcur);\n                    key.over = overcur;\n                    if (!found || betterKey(key, bestLocal)) {\n                        found = true;\n                        bestLocal = key;\n                        cLocal = (lv + rv) * 0.5;\n                    }\n                }\n            }\n            i = j;\n        }\n\n        if (!found) return false;\n        bestC = cLocal;\n        pred = bestLocal;\n        return true;\n    }\n\n    pair<Line, EvalKey> realizeThetaC(const State& st, double theta, double c,\n                                      vector<int>& L, vector<int>& R) const {\n        Line bestLn = makeLine(theta, c);\n        EvalKey bestEv = evalLine(st, bestLn, L, R);\n\n        int curAct = (int)st.active.size();\n        if (bestEv.active == curAct) return {bestLn, bestEv};\n\n        static const double off[6] = {1e-4, -1e-4, 5e-4, -5e-4, 2e-3, -2e-3};\n        for (double d : off) {\n            Line ln = makeLine(theta, c + d);\n            EvalKey ev = evalLine(st, ln, L, R);\n            if (betterKey(ev, bestEv)) {\n                bestEv = ev;\n                bestLn = ln;\n            }\n        }\n        return {bestLn, bestEv};\n    }\n\n    int pickPieceRandom(const State& st, XorShift64& rng, int minSize) const {\n        if (st.active.empty()) return -1;\n        int S = (int)st.active.size();\n        for (int t = 0; t < 30; t++) {\n            int idx = st.active[rng.nextInt(0, S - 1)];\n            int pid = st.pieceOf[idx];\n            if (st.pieceSize[pid] >= minSize) return pid;\n        }\n        int best = -1, bestSize = 0;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s >= minSize && s > bestSize) {\n                bestSize = s;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int chooseTargetPiece(const State& st) const {\n        int best = -1;\n        long long bestScore = -1;\n        for (int pid = 0; pid < (int)st.pieceSize.size(); pid++) {\n            int s = st.pieceSize[pid];\n            if (s < 2) continue;\n\n            long long score;\n            if (s > 10) {\n                score = 1000000LL + 1000LL * s;\n            } else {\n                int overSup = max(0, st.h[s] - a[s]);\n                score = (long long)overSup * 10000LL + s;\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = pid;\n            }\n        }\n        return best;\n    }\n\n    int pickDeficitSize(const State& st, XorShift64& rng) const {\n        int w[11];\n        int sumW = 0;\n        for (int d = 1; d <= 10; d++) {\n            int def = max(0, a[d] - st.h[d]);\n            int wt = 1 + def * def * 3;\n            w[d] = wt;\n            sumW += wt;\n        }\n        int r = rng.nextInt(1, sumW);\n        for (int d = 1; d <= 10; d++) {\n            if (r <= w[d]) return d;\n            r -= w[d];\n        }\n        return 1;\n    }\n\n    bool calcPCA(const State& st, int pid, double& th1, double& th2) const {\n        const auto& pc = st.pieces[pid];\n        int s = (int)pc.size();\n        if (s < 2) return false;\n\n        long double mx = 0, my = 0;\n        for (int idx : pc) {\n            mx += pts[idx].x;\n            my += pts[idx].y;\n        }\n        mx /= s;\n        my /= s;\n\n        long double cxx = 0, cyy = 0, cxy = 0;\n        for (int idx : pc) {\n            long double dx = pts[idx].x - mx;\n            long double dy = pts[idx].y - my;\n            cxx += dx * dx;\n            cyy += dy * dy;\n            cxy += dx * dy;\n        }\n        if ((double)(cxx + cyy) < 1e-9) return false;\n\n        double ang = 0.5 * atan2((double)(2 * cxy), (double)(cxx - cyy));\n        th1 = normTheta(ang);\n        th2 = normTheta(ang + PI * 0.5);\n        return true;\n    }\n\n    Line lineByQuantile(const State& st, int pid, double theta, int t, vector<double>& buf) const {\n        const auto& vec = st.pieces[pid];\n        int s = (int)vec.size();\n        t = max(1, min(s - 1, t));\n\n        double nx = cos(theta), ny = sin(theta);\n        buf.clear();\n        buf.reserve(s);\n        for (int idx : vec) {\n            buf.push_back(nx * pts[idx].x + ny * pts[idx].y);\n        }\n\n        sort(buf.begin(), buf.end());\n        double l = buf[t - 1], r = buf[t];\n        double c = (l + r) * 0.5;\n        if (fabs(r - l) < 1e-12) c += 1e-6;\n        return makeLine(theta, c);\n    }\n\n    RunResult runOne(uint64_t seed, int runId, double runEnd) {\n        XorShift64 rng(seed);\n\n        State st;\n        st.pieceOf.assign(N, 0);\n        st.pieces.assign(1, {});\n        st.pieces[0].resize(N);\n        iota(st.pieces[0].begin(), st.pieces[0].end(), 0);\n        st.pieceSize.assign(1, N);\n        st.active = st.pieces[0];\n        st.h.fill(0);\n        if (1 <= N && N <= 10) st.h[N] = 1;\n        st.over = pen[N];\n        st.F = calcF(st.h);\n        st.def2 = calcDef2(st.h);\n        st.waste = calcWaste(st.h);\n\n        int oriBase;\n        if (N >= 4500) oriBase = 8;\n        else if (N >= 3000) oriBase = 10;\n        else if (N >= 1800) oriBase = 12;\n        else oriBase = 14;\n\n        int qBase = (N >= 3500 ? 3 : 4);\n        int noImpLimit = (runId == 0 ? 13 : 10);\n        if (runId == 0) oriBase += 2;\n        if (runId >= 3) oriBase = max(6, oriBase - 2);\n\n        vector<int> L(max(1, N), 0), R(max(1, N), 0), cntLeft(max(1, N), 0);\n        vector<pair<double, int>> ord;\n        ord.reserve(max(1, N));\n        vector<double> projBuf;\n        projBuf.reserve(max(1, N));\n\n        int noImprove = 0;\n        double runBudget = runEnd - elapsed();\n\n        for (int iter = 0; iter < K * 3 && (int)st.lines.size() < K; iter++) {\n            if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n            if (st.active.empty()) break;\n            if (st.F >= totalA) break;\n\n            int step = (int)st.lines.size();\n            EvalKey cur = stateKey(st);\n\n            int targetPid = chooseTargetPiece(st);\n            bool hasPCA = false;\n            double pca1 = 0.0, pca2 = 0.0;\n            if (targetPid >= 0) hasPCA = calcPCA(st, targetPid, pca1, pca2);\n\n            double remRun = runEnd - elapsed();\n            int oriCnt = oriBase;\n            if (step < 6) oriCnt += 2;\n            if (noImprove >= 3) oriCnt += 3;\n            if (runBudget < 0.35 || remRun < 0.22) oriCnt = max(4, oriCnt - 4);\n            if (remRun < 0.12) oriCnt = max(3, oriCnt / 2);\n\n            int qCnt = qBase;\n            if (noImprove >= 3) qCnt += 1;\n            if (runBudget < 0.35 || remRun < 0.22) qCnt = max(1, qCnt - 2);\n            if (remRun < 0.12) qCnt = 1;\n\n            vector<double> thetas;\n            thetas.reserve(oriCnt + 10);\n\n            auto addTheta = [&](double th) {\n                thetas.push_back(normTheta(th));\n            };\n\n            if (hasPCA) {\n                addTheta(pca1);\n                addTheta(pca2);\n                addTheta(pca1 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n                addTheta(pca2 + (rng.nextDouble() * 2.0 - 1.0) * 0.18);\n            }\n\n            int prevUse = min((int)st.lines.size(), 2);\n            for (int i = 0; i < prevUse; i++) {\n                const Line& pl = st.lines[(int)st.lines.size() - 1 - i];\n                double th = atan2((double)pl.dx, (double)(-pl.dy));\n                addTheta(th + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n                addTheta(th + PI * 0.5 + (rng.nextDouble() * 2.0 - 1.0) * 0.12);\n            }\n\n            while ((int)thetas.size() < oriCnt) {\n                addTheta(rng.nextDouble() * PI);\n            }\n            if ((int)thetas.size() > 24) thetas.resize(24);\n\n            EvalKey bestEv{-1, INT_MAX, -1, INT_MAX, BIG};\n            Line bestLn{};\n            bool found = false;\n\n            for (double th : thetas) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                double c = 0.0;\n                EvalKey pred;\n                if (!bestCutForTheta(st, th, c, pred, ord, cntLeft)) continue;\n                auto [ln, ev] = realizeThetaC(st, th, c, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int qi = 0; qi < qCnt; qi++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n\n                int pid = -1;\n                if (targetPid >= 0 && st.pieceSize[targetPid] >= 2 && rng.nextDouble() < 0.65) {\n                    pid = targetPid;\n                } else {\n                    pid = pickPieceRandom(st, rng, 2);\n                }\n                if (pid < 0) continue;\n\n                int s = st.pieceSize[pid];\n                if (s <= 1) continue;\n\n                int d = pickDeficitSize(st, rng);\n                vector<int> candT;\n                if (1 <= d && d < s) candT.push_back(d);\n                if (1 <= s - d && s - d < s) candT.push_back(s - d);\n\n                int mid = s / 2;\n                if (1 <= mid && mid < s) candT.push_back(mid);\n\n                int w = max(1, s / 6);\n                int tr = mid + rng.nextInt(-w, w);\n                tr = max(1, min(s - 1, tr));\n                candT.push_back(tr);\n\n                int t = candT[rng.nextInt(0, (int)candT.size() - 1)];\n\n                double th;\n                if (hasPCA && rng.nextDouble() < 0.55) {\n                    th = (rng.nextDouble() < 0.5 ? pca1 : pca2)\n                       + (rng.nextDouble() * 2.0 - 1.0) * 0.28;\n                } else {\n                    th = rng.nextDouble() * PI;\n                }\n                th = normTheta(th);\n\n                Line ln = lineByQuantile(st, pid, th, t, projBuf);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (elapsed() > runEnd || elapsed() > TL - 0.01) break;\n                Line ln = randomGlobalLine(rng);\n                EvalKey ev = evalLine(st, ln, L, R);\n                if (!found || betterKey(ev, bestEv)) {\n                    found = true;\n                    bestEv = ev;\n                    bestLn = ln;\n                }\n            }\n\n            if (!found) break;\n\n            bool accept = betterKey(bestEv, cur);\n            if (!accept && noImprove >= 5) {\n                if (bestEv.F == cur.F &&\n                    bestEv.active == cur.active &&\n                    bestEv.def2 <= cur.def2 + 1 &&\n                    (bestEv.waste < cur.waste || bestEv.over < cur.over)) {\n                    accept = true;\n                }\n            }\n\n            if (accept) {\n                applyLine(st, bestLn);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= noImpLimit) break;\n            }\n        }\n\n        RunResult rr;\n        rr.lines = move(st.lines);\n        rr.key = stateKey(st);\n        return rr;\n    }\n\npublic:\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> K;\n        a.fill(0);\n        totalA = 0;\n        for (int d = 1; d <= 10; d++) {\n            cin >> a[d];\n            totalA += a[d];\n        }\n\n        pts.resize(N);\n        for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n        pen.assign(N + 1, 0);\n        for (int s = 0; s <= N; s++) {\n            if (s > 10) {\n                long long t = s - 10;\n                pen[s] = t * t;\n            }\n        }\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        uint64_t seedBase = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            v += 0x9e3779b97f4a7c15ULL;\n            v = (v ^ (v >> 30)) * 0xbf58476d1ce4e5b9ULL;\n            v = (v ^ (v >> 27)) * 0x94d049bb133111ebULL;\n            v ^= (v >> 31);\n            seedBase ^= v + 0x9e3779b97f4a7c15ULL + (seedBase << 6) + (seedBase >> 2);\n        };\n\n        mix((uint64_t)N);\n        mix((uint64_t)K);\n        for (int d = 1; d <= 10; d++) mix((uint64_t)a[d]);\n        for (const auto& p : pts) {\n            uint64_t v = ((uint64_t)(p.x + 20000) << 20) ^ (uint64_t)(p.y + 20000);\n            mix(v);\n        }\n\n        EvalKey bestKey{-1, INT_MAX, -1, INT_MAX, BIG};\n        vector<Line> bestLines;\n\n        int runId = 0;\n        while (true) {\n            double rem = TL - elapsed();\n            if (rem < 0.08) break;\n\n            double factor = (runId == 0 ? 0.58 : (runId < 3 ? 0.62 : 0.70));\n            double budget = rem * factor;\n            budget = max(0.14, budget);\n            budget = min(budget, rem - 0.03);\n            if (budget <= 0.02) break;\n\n            double runEnd = elapsed() + budget;\n            uint64_t seed = seedBase + 0x9e3779b97f4a7c15ULL * (uint64_t)(runId + 1);\n\n            RunResult rr = runOne(seed, runId, runEnd);\n            if (bestLines.empty() || betterKey(rr.key, bestKey)) {\n                bestKey = rr.key;\n                bestLines = move(rr.lines);\n            }\n\n            runId++;\n            if (bestKey.F >= totalA) break;\n        }\n\n        if (bestLines.empty()) {\n            cout << 0 << '\\n';\n            return;\n        }\n\n        cout << bestLines.size() << '\\n';\n        for (const auto& ln : bestLines) {\n            cout << ln.x1 << ' ' << ln.y1 << ' ' << ln.x2 << ' ' << ln.y2 << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(next() % (uint64_t)n); } // n > 0\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nclass Solver {\n    using Clock = chrono::steady_clock;\n\n    static constexpr int MAXN = 61;\n    static constexpr int MAXD = 121;\n\n    struct Point {\n        int x, y;\n    };\n    struct Move {\n        int x1, y1, x2, y2, x3, y3, x4, y4;\n    };\n    struct Candidate {\n        Move mv;\n        double val;\n        int w;\n        int L;\n    };\n    struct Core {\n        array<uint64_t, MAXN> row{}, col{}, usedH{}, usedV{};\n        array<uint64_t, MAXD> diagPos{}, diagNeg{}, usedPos{}, usedNeg{};\n        array<uint8_t, MAXN> segH{}, segV{};\n        array<uint8_t, MAXD> segPos{}, segNeg{};\n        long long sumW = 0;\n        int dotCount = 0;\n    };\n\n    struct HeuParam {\n        // val = w - m*(a*L + b*L^2 + c*cong) + m*g*conn\n        double a0, a1;\n        double b0, b1;\n        double c0, c1;\n        double g0, g1;\n        double m0, m1;\n\n        bool stochastic;\n        int pickK;\n        int keep;\n    };\n\n    struct RunConfig {\n        HeuParam h;\n\n        bool lookahead;\n        int laSteps;\n        int laBranch;\n        int laDepth;   // 1 or 2\n        double laCoef;\n        double laDecay;\n        double laWmix; // rollout blend: (1-laWmix)*val + laWmix*w\n    };\n\n    struct RunResult {\n        long long sumW;\n        vector<Move> ops;\n    };\n\n    struct EliteRun {\n        long long sumW;\n        RunConfig cfg;\n        vector<Move> ops;\n    };\n\n    int N = 0, M = 0;\n    int off = 0;\n    int diagCnt = 0;\n    double density = 0.0;\n    double invHV = 1.0;\n\n    vector<pair<int, int>> initDots;\n    int W[MAXN][MAXN]{};\n    vector<pair<int, int>> cellsByWeight;\n    uint64_t rangeMask[MAXN + 1][MAXN + 1]{};\n\n    double invDiagPos[MAXD]{}, invDiagNeg[MAXD]{};\n\n    static inline constexpr array<int, 8> pairU = {0, 1, 2, 3, 4, 5, 6, 7};\n    static inline constexpr array<int, 8> pairV = {1, 2, 3, 0, 5, 6, 7, 4};\n\n    static inline int ctz64(uint64_t v) { return __builtin_ctzll(v); }\n    static inline int msb64(uint64_t v) { return 63 - __builtin_clzll(v); }\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    double randRange(XorShift64 &rng, double lo, double hi) const {\n        return lo + (hi - lo) * rng.nextDouble();\n    }\n\n    // approx mean 0\n    double normalish(XorShift64 &rng) const {\n        double z = 0.0;\n        for (int i = 0; i < 6; i++) z += rng.nextDouble();\n        return z - 3.0;\n    }\n\n    void buildTables() {\n        off = N - 1;\n        diagCnt = 2 * N - 1;\n        invHV = 1.0 / (double)max(1, N - 1);\n\n        int c = (N - 1) / 2;\n        cellsByWeight.clear();\n        cellsByWeight.reserve(N * N);\n\n        for (int y = 0; y < N; y++) {\n            for (int x = 0; x < N; x++) {\n                int dx = x - c;\n                int dy = y - c;\n                W[y][x] = dx * dx + dy * dy + 1;\n                cellsByWeight.emplace_back(x, y);\n            }\n        }\n\n        sort(cellsByWeight.begin(), cellsByWeight.end(), [&](const auto &a, const auto &b) {\n            int wa = W[a.second][a.first];\n            int wb = W[b.second][b.first];\n            if (wa != wb) return wa > wb;\n            if (a.second != b.second) return a.second < b.second;\n            return a.first < b.first;\n        });\n\n        for (int l = 0; l <= N; l++) for (int r = 0; r <= N; r++) rangeMask[l][r] = 0;\n        for (int l = 0; l <= N; l++) {\n            uint64_t m = 0;\n            for (int r = l + 1; r <= N; r++) {\n                m |= (1ULL << (r - 1)); // [l, r)\n                rangeMask[l][r] = m;\n            }\n        }\n\n        for (int d = 0; d < diagCnt; d++) {\n            int k = d - off;\n            int len = N - abs(k);\n            int seg = max(1, len - 1);\n            invDiagPos[d] = 1.0 / (double)seg;\n        }\n        for (int s = 0; s < diagCnt; s++) {\n            int len = (s < N ? s + 1 : 2 * N - 1 - s);\n            int seg = max(1, len - 1);\n            invDiagNeg[s] = 1.0 / (double)seg;\n        }\n    }\n\n    inline bool hasDot(const Core &st, int x, int y) const {\n        return ((st.row[y] >> x) & 1ULL) != 0ULL;\n    }\n\n    inline void addDot(Core &st, int x, int y) const {\n        uint64_t bx = 1ULL << x;\n        st.row[y] |= bx;\n        st.col[x] |= (1ULL << y);\n        st.diagPos[x - y + off] |= bx;\n        st.diagNeg[x + y] |= bx;\n        st.dotCount++;\n    }\n\n    Point nearestDot(const Core &st, int x, int y, int dir) const {\n        uint64_t m = 0;\n        switch (dir) {\n            case 0: // E\n                m = st.row[y] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                return {ctz64(m), y};\n            case 1: // N\n                m = st.col[x] & (~0ULL << (y + 1));\n                if (!m) return {-1, -1};\n                return {x, ctz64(m)};\n            case 2: // W\n                m = st.row[y] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                return {msb64(m), y};\n            case 3: // S\n                m = st.col[x] & ((1ULL << y) - 1);\n                if (!m) return {-1, -1};\n                return {x, msb64(m)};\n            case 4: { // NE\n                int d = x - y + off;\n                m = st.diagPos[d] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                int k = d - off;\n                return {nx, nx - k};\n            }\n            case 5: { // NW\n                int s = x + y;\n                m = st.diagNeg[s] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                return {nx, s - nx};\n            }\n            case 6: { // SW\n                int d = x - y + off;\n                m = st.diagPos[d] & ((1ULL << x) - 1);\n                if (!m) return {-1, -1};\n                int nx = msb64(m);\n                int k = d - off;\n                return {nx, nx - k};\n            }\n            default: { // 7: SE\n                int s = x + y;\n                m = st.diagNeg[s] & (~0ULL << (x + 1));\n                if (!m) return {-1, -1};\n                int nx = ctz64(m);\n                return {nx, s - nx};\n            }\n        }\n    }\n\n    inline bool edgeFree(const Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) {\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            return (st.usedV[x] & rangeMask[l][r]) == 0ULL;\n        }\n        if (y1 == y2) {\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedH[y] & rangeMask[l][r]) == 0ULL;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (st.usedPos[d] & rangeMask[l][r]) == 0ULL;\n        }\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        return (st.usedNeg[s] & rangeMask[l][r]) == 0ULL;\n    }\n\n    inline void useEdge(Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) {\n            int x = x1;\n            int l = min(y1, y2), r = max(y1, y2);\n            st.usedV[x] |= rangeMask[l][r];\n            st.segV[x] = (uint8_t)(st.segV[x] + (uint8_t)(r - l));\n            return;\n        }\n        if (y1 == y2) {\n            int y = y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedH[y] |= rangeMask[l][r];\n            st.segH[y] = (uint8_t)(st.segH[y] + (uint8_t)(r - l));\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            int l = min(x1, x2), r = max(x1, x2);\n            st.usedPos[d] |= rangeMask[l][r];\n            st.segPos[d] = (uint8_t)(st.segPos[d] + (uint8_t)(r - l));\n            return;\n        }\n        int s = x1 + y1;\n        int l = min(x1, x2), r = max(x1, x2);\n        st.usedNeg[s] |= rangeMask[l][r];\n        st.segNeg[s] = (uint8_t)(st.segNeg[s] + (uint8_t)(r - l));\n    }\n\n    inline void applyMove(Core &st, const Move &mv) const {\n        useEdge(st, mv.x1, mv.y1, mv.x2, mv.y2);\n        useEdge(st, mv.x2, mv.y2, mv.x3, mv.y3);\n        useEdge(st, mv.x3, mv.y3, mv.x4, mv.y4);\n        useEdge(st, mv.x4, mv.y4, mv.x1, mv.y1);\n        addDot(st, mv.x1, mv.y1);\n        st.sumW += W[mv.y1][mv.x1];\n    }\n\n    Core makeBaseState() const {\n        Core st;\n        for (auto [x, y] : initDots) {\n            if (!hasDot(st, x, y)) {\n                addDot(st, x, y);\n                st.sumW += W[y][x];\n            }\n        }\n        return st;\n    }\n\n    inline void evalCoeffs(const HeuParam &h, double progress,\n                           double &a, double &b, double &c, double &g, double &m) const {\n        a = h.a0 + (h.a1 - h.a0) * progress;\n        b = h.b0 + (h.b1 - h.b0) * progress;\n        c = h.c0 + (h.c1 - h.c0) * progress;\n        g = h.g0 + (h.g1 - h.g0) * progress;\n        m = h.m0 + (h.m1 - h.m0) * progress;\n\n        if (a < 0.0) a = 0.0;\n        if (b < 0.0) b = 0.0;\n        if (c < 0.0) c = 0.0;\n        if (g < 0.0) g = 0.0;\n        m = clampD(m, 0.0, 1.5);\n    }\n\n    inline bool betterCand(const Candidate &A, const Candidate &B) const {\n        if (A.val > B.val + 1e-9) return true;\n        if (A.val + 1e-9 < B.val) return false;\n        if (A.w != B.w) return A.w > B.w;\n        return A.L < B.L;\n    }\n\n    inline double edgeOcc(const Core &st, int x1, int y1, int x2, int y2) const {\n        if (x1 == x2) return (double)st.segV[x1] * invHV;\n        if (y1 == y2) return (double)st.segH[y1] * invHV;\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + off;\n            return (double)st.segPos[d] * invDiagPos[d];\n        }\n        int s = x1 + y1;\n        return (double)st.segNeg[s] * invDiagNeg[s];\n    }\n\n    void findTopCandidates(const Core &st, double a, double b, double c, double g, double m,\n                           int keep, vector<Candidate> &out) const {\n        out.clear();\n        if (keep <= 0) return;\n        if ((int)out.capacity() < keep + 1) out.reserve(keep + 1);\n\n        array<Point, 8> near{};\n\n        bool useCong = (c > 1e-12);\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n            if ((int)out.size() == keep) {\n                double ub = (double)w - m * (a * 2.0 + b * 4.0) + m * g * 8.0;\n                if (ub + 1e-9 < out.back().val) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n            if (conn < 2) continue;\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du], p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double cong = 0.0;\n                if (useCong) {\n                    double o12 = edgeOcc(st, x, y, p2.x, p2.y);\n                    double o23 = edgeOcc(st, p2.x, p2.y, x3, y3);\n                    double o34 = edgeOcc(st, x3, y3, p4.x, p4.y);\n                    double o41 = edgeOcc(st, p4.x, p4.y, x, y);\n                    cong = len1 * (o12 + o34) + len2 * (o23 + o41);\n                }\n\n                double val = (double)w - m * (a * (double)L + b * (double)L * (double)L + c * cong)\n                           + m * g * (double)conn;\n\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                int pos = 0;\n                while (pos < (int)out.size() && !betterCand(cand, out[pos])) pos++;\n                if (pos >= keep) continue;\n\n                out.insert(out.begin() + pos, cand);\n                if ((int)out.size() > keep) out.pop_back();\n            }\n        }\n    }\n\n    bool findBestCandidate(const Core &st, double a, double b, double c, double g, double m,\n                           Candidate &best) const {\n        bool found = false;\n        array<Point, 8> near{};\n\n        bool useCong = (c > 1e-12);\n\n        for (const auto &cell : cellsByWeight) {\n            int x = cell.first, y = cell.second;\n            if (hasDot(st, x, y)) continue;\n\n            int w = W[y][x];\n            if (found) {\n                double ub = (double)w - m * (a * 2.0 + b * 4.0) + m * g * 8.0;\n                if (ub + 1e-9 < best.val) break;\n            }\n\n            int conn = 0;\n            for (int d = 0; d < 8; d++) {\n                near[d] = nearestDot(st, x, y, d);\n                conn += (near[d].x >= 0);\n            }\n            if (conn < 2) continue;\n\n            for (int i = 0; i < 8; i++) {\n                int du = pairU[i], dv = pairV[i];\n                Point p2 = near[du], p4 = near[dv];\n                if (p2.x < 0 || p4.x < 0) continue;\n\n                int x3 = p2.x + p4.x - x;\n                int y3 = p2.y + p4.y - y;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n                if (!hasDot(st, x3, y3)) continue;\n\n                Point q = nearestDot(st, p2.x, p2.y, dv);\n                if (q.x != x3 || q.y != y3) continue;\n                q = nearestDot(st, p4.x, p4.y, du);\n                if (q.x != x3 || q.y != y3) continue;\n\n                if (!edgeFree(st, x, y, p2.x, p2.y)) continue;\n                if (!edgeFree(st, p2.x, p2.y, x3, y3)) continue;\n                if (!edgeFree(st, x3, y3, p4.x, p4.y)) continue;\n                if (!edgeFree(st, p4.x, p4.y, x, y)) continue;\n\n                int len1 = max(abs(p2.x - x), abs(p2.y - y));\n                int len2 = max(abs(p4.x - x), abs(p4.y - y));\n                int L = len1 + len2;\n\n                double cong = 0.0;\n                if (useCong) {\n                    double o12 = edgeOcc(st, x, y, p2.x, p2.y);\n                    double o23 = edgeOcc(st, p2.x, p2.y, x3, y3);\n                    double o34 = edgeOcc(st, x3, y3, p4.x, p4.y);\n                    double o41 = edgeOcc(st, p4.x, p4.y, x, y);\n                    cong = len1 * (o12 + o34) + len2 * (o23 + o41);\n                }\n\n                double val = (double)w - m * (a * (double)L + b * (double)L * (double)L + c * cong)\n                           + m * g * (double)conn;\n                Candidate cand{{x, y, p2.x, p2.y, x3, y3, p4.x, p4.y}, val, w, L};\n\n                if (!found || betterCand(cand, best)) {\n                    best = cand;\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    int pickRankedIndex(int k, XorShift64 &rng) const {\n        if (k <= 1) return 0;\n        int total = k * (k + 1) / 2;\n        int r = rng.nextInt(total);\n        for (int i = 0; i < k; i++) {\n            int wt = k - i;\n            if (r < wt) return i;\n            r -= wt;\n        }\n        return k - 1;\n    }\n\n    int pickByCandVal(const vector<Candidate> &cands, int k, double temp, double progress, XorShift64 &rng) const {\n        int n = (int)cands.size();\n        k = min(k, n);\n        if (k <= 1) return 0;\n\n        double gap = cands[0].val - cands[1].val;\n        if (gap > 150.0) return 0;\n\n        // Hybrid: early more rank-noise, late more softmax exploit\n        double pRank = clampD(0.08 + 0.30 * (1.0 - progress), 0.08, 0.40);\n        if (rng.nextDouble() < pRank) {\n            return pickRankedIndex(k, rng);\n        }\n\n        temp = clampD(temp, 1.0, 160.0);\n        double best = cands[0].val;\n\n        double wsum = 0.0;\n        vector<double> w(k, 0.0);\n        for (int i = 0; i < k; i++) {\n            double d = (cands[i].val - best) / temp;\n            w[i] = (d < -60.0 ? 0.0 : exp(d));\n            wsum += w[i];\n        }\n        if (wsum <= 1e-300) return 0;\n\n        double r = rng.nextDouble() * wsum;\n        for (int i = 0; i < k; i++) {\n            if (r < w[i]) return i;\n            r -= w[i];\n        }\n        return k - 1;\n    }\n\n    int pickBySortedScores(const vector<pair<double, int>> &sorted, int k, double temp, double progress, XorShift64 &rng) const {\n        int n = (int)sorted.size();\n        k = min(k, n);\n        if (k <= 1) return sorted[0].second;\n\n        double gap = sorted[0].first - sorted[1].first;\n        if (gap > 180.0) return sorted[0].second;\n\n        double pRank = clampD(0.05 + 0.18 * (1.0 - progress), 0.05, 0.23);\n        if (rng.nextDouble() < pRank) {\n            int idx = pickRankedIndex(k, rng);\n            return sorted[idx].second;\n        }\n\n        temp = clampD(temp, 1.0, 160.0);\n        double best = sorted[0].first;\n\n        double wsum = 0.0;\n        vector<double> w(k, 0.0);\n        for (int i = 0; i < k; i++) {\n            double d = (sorted[i].first - best) / temp;\n            w[i] = (d < -60.0 ? 0.0 : exp(d));\n            wsum += w[i];\n        }\n        if (wsum <= 1e-300) return sorted[0].second;\n\n        double r = rng.nextDouble() * wsum;\n        for (int i = 0; i < k; i++) {\n            if (r < w[i]) return sorted[i].second;\n            r -= w[i];\n        }\n        return sorted[k - 1].second;\n    }\n\n    bool selectMove(const Core &st, const RunConfig &cfg, int moveCnt, int baseDotCount, int totalAddable,\n                    XorShift64 &rng, Clock::time_point deadline, Move &out, vector<Candidate> &cands) const {\n        double progress = (double)(st.dotCount - baseDotCount) / (double)max(1, totalAddable);\n\n        double a, b, c, g, m;\n        evalCoeffs(cfg.h, progress, a, b, c, g, m);\n\n        int remainMs = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n\n        bool laPossible = cfg.lookahead && (moveCnt < cfg.laSteps);\n        if (remainMs < 900) laPossible = false;\n        if (cfg.laDepth >= 2 && remainMs < 1450) laPossible = false;\n\n        int keep = cfg.h.keep;\n        if (!cfg.h.stochastic && !laPossible) keep = 1;\n        keep = max(keep, max(1, cfg.h.pickK));\n        if (laPossible) keep = max(keep, max(2, cfg.laBranch));\n        if (remainMs < 700) keep = min(keep, 9);\n\n        findTopCandidates(st, a, b, c, g, m, keep, cands);\n        if (cands.empty()) return false;\n\n        int idx = 0;\n\n        bool doLA = laPossible && ((int)cands.size() >= 2);\n        if (doLA) {\n            int needMs = (cfg.laDepth >= 2 ? 6 : 4);\n            if (Clock::now() + chrono::milliseconds(needMs) >= deadline) doLA = false;\n            double margin = (cfg.laDepth >= 2 ? 130.0 : 105.0);\n            if (cands[0].val - cands[1].val > margin) doLA = false;\n        }\n\n        if (doLA) {\n            int B = min(cfg.laBranch, (int)cands.size());\n            vector<pair<double, int>> scored;\n            scored.reserve(B);\n\n            for (int i = 0; i < B; i++) {\n                if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n                Core tmp = st;\n                applyMove(tmp, cands[i].mv);\n\n                double score = (1.0 - cfg.laWmix) * cands[i].val + cfg.laWmix * (double)cands[i].w;\n                double coef = cfg.laCoef;\n\n                for (int dep = 0; dep < cfg.laDepth; dep++) {\n                    if (coef <= 1e-9) break;\n                    if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n                    double p2 = (double)(tmp.dotCount - baseDotCount) / (double)max(1, totalAddable);\n                    double a2, b2, c2, g2, m2;\n                    evalCoeffs(cfg.h, p2, a2, b2, c2, g2, m2);\n\n                    // throughput-oriented: simplify congestion in deeper/late rollouts\n                    double cEval = c2;\n                    if (cfg.laDepth >= 2 || remainMs < 1400 || cEval < 0.35) cEval = 0.0;\n\n                    Candidate nxt;\n                    if (!findBestCandidate(tmp, a2, b2, cEval, g2, m2, nxt)) break;\n\n                    double nxtScore = (1.0 - cfg.laWmix) * nxt.val + cfg.laWmix * (double)nxt.w;\n                    score += coef * nxtScore;\n                    applyMove(tmp, nxt.mv);\n                    coef *= cfg.laDecay;\n                }\n\n                scored.emplace_back(score, i);\n            }\n\n            if (!scored.empty()) {\n                sort(scored.begin(), scored.end(), [&](const auto &A, const auto &B) {\n                    return A.first > B.first;\n                });\n\n                if (cfg.h.stochastic) {\n                    int k = min(cfg.h.pickK, (int)scored.size());\n                    double tempLA = clampD(14.0 - 8.0 * progress, 5.0, 14.0);\n                    idx = pickBySortedScores(scored, k, tempLA, progress, rng);\n                } else {\n                    idx = scored[0].second;\n                }\n            } else {\n                doLA = false;\n            }\n        }\n\n        if (!doLA) {\n            if (cfg.h.stochastic) {\n                int k = min(cfg.h.pickK, (int)cands.size());\n                double temp = clampD(20.0 - 12.0 * progress, 6.0, 20.0);\n                idx = pickByCandVal(cands, k, temp, progress, rng);\n            } else {\n                idx = 0;\n            }\n        }\n\n        out = cands[idx].mv;\n        return true;\n    }\n\n    RunResult runFromState(Core st, vector<Move> ops, const RunConfig &cfg,\n                           int baseDotCount, int totalAddable,\n                           XorShift64 &rng, Clock::time_point deadline) const {\n        ops.reserve(ops.size() + max(0, N * N - st.dotCount));\n        vector<Candidate> cands;\n        cands.reserve(48);\n\n        int moveCnt = (int)ops.size();\n\n        while (true) {\n            if (Clock::now() + chrono::milliseconds(1) >= deadline) break;\n\n            Move mv;\n            if (!selectMove(st, cfg, moveCnt, baseDotCount, totalAddable, rng, deadline, mv, cands)) break;\n\n            applyMove(st, mv);\n            ops.push_back(mv);\n            moveCnt++;\n        }\n\n        return {st.sumW, move(ops)};\n    }\n\n    RunResult runOne(const Core &base, const RunConfig &cfg, XorShift64 &rng, Clock::time_point deadline) const {\n        vector<Move> empty;\n        int baseDotCount = base.dotCount;\n        int totalAddable = max(1, N * N - baseDotCount);\n        return runFromState(base, move(empty), cfg, baseDotCount, totalAddable, rng, deadline);\n    }\n\n    int familyOf(const RunConfig &cfg) const {\n        return (cfg.h.c0 + cfg.h.c1 <= 1e-12) ? 0 : 1;\n    }\n\n    void normalizeConfig(RunConfig &cfg, int remainMs) const {\n        cfg.h.a0 = clampD(cfg.h.a0, 0.0, 8.0);\n        cfg.h.a1 = clampD(cfg.h.a1, 0.0, 4.0);\n        cfg.h.b0 = clampD(cfg.h.b0, 0.0, 0.08);\n        cfg.h.b1 = clampD(cfg.h.b1, 0.0, 0.05);\n        cfg.h.c0 = clampD(cfg.h.c0, 0.0, 2.5);\n        cfg.h.c1 = clampD(cfg.h.c1, 0.0, 2.5);\n        cfg.h.g0 = clampD(cfg.h.g0, 0.0, 4.0);\n        cfg.h.g1 = clampD(cfg.h.g1, 0.0, 3.0);\n        cfg.h.m0 = clampD(cfg.h.m0, 0.0, 1.5);\n        cfg.h.m1 = clampD(cfg.h.m1, 0.0, 1.5);\n\n        cfg.h.pickK = clamp(cfg.h.pickK, 1, 10);\n        cfg.h.keep = clamp(cfg.h.keep, 1, 32);\n        if (!cfg.h.stochastic) cfg.h.pickK = 1;\n\n        if (remainMs < 950) cfg.lookahead = false;\n\n        if (cfg.lookahead) {\n            cfg.laSteps = clamp(cfg.laSteps, 20, 220);\n            cfg.laBranch = clamp(cfg.laBranch, 2, 6);\n            cfg.laDepth = clamp(cfg.laDepth, 1, 2);\n            cfg.laCoef = clampD(cfg.laCoef, 0.35, 1.20);\n            cfg.laDecay = clampD(cfg.laDecay, 0.35, 0.92);\n            cfg.laWmix = clampD(cfg.laWmix, 0.0, 0.5);\n\n            if (remainMs < 1500) cfg.laDepth = 1;\n            if (remainMs < 1200) cfg.laSteps = min(cfg.laSteps, 85);\n\n            cfg.h.keep = max(cfg.h.keep, cfg.laBranch);\n        } else {\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laDepth = 0;\n            cfg.laCoef = 0.0;\n            cfg.laDecay = 0.0;\n            cfg.laWmix = 0.0;\n        }\n\n        cfg.h.keep = max(cfg.h.keep, cfg.h.pickK);\n\n        if (remainMs < 560) {\n            cfg.lookahead = false;\n            cfg.h.keep = min(cfg.h.keep, 14);\n            cfg.h.pickK = min(cfg.h.pickK, 5);\n        }\n        if (remainMs < 320) {\n            cfg.h.keep = min(cfg.h.keep, 10);\n            cfg.h.pickK = min(cfg.h.pickK, 3);\n        }\n    }\n\n    RunConfig randomConfigFamily(XorShift64 &rng, int remainMs, int family) const {\n        RunConfig cfg{};\n\n        double densF = 1.0;\n        if (density < 0.040) densF = 1.15;\n        else if (density > 0.065) densF = 0.90;\n\n        double densC = 1.0;\n        if (density > 0.060) densC = 1.30;\n        else if (density < 0.040) densC = 0.80;\n\n        cfg.h.a0 = randRange(rng, 0.0, 6.0 * densF);\n        cfg.h.a1 = randRange(rng, 0.0, 2.6);\n        cfg.h.b0 = randRange(rng, 0.0, 0.044 * densF);\n        cfg.h.b1 = randRange(rng, 0.0, 0.023);\n        cfg.h.g0 = randRange(rng, 0.0, 2.4);\n        cfg.h.g1 = randRange(rng, 0.0, 1.4);\n        cfg.h.m0 = randRange(rng, 0.45, 1.15);\n        cfg.h.m1 = randRange(rng, 0.30, 1.05);\n\n        if (family == 0) {\n            cfg.h.c0 = 0.0;\n            cfg.h.c1 = 0.0;\n        } else {\n            cfg.h.c0 = randRange(rng, 0.08, 1.05 * densC);\n            cfg.h.c1 = randRange(rng, 0.02, 0.65 * densC);\n            if (rng.nextInt(100) < 10) {\n                cfg.h.c0 = 0.0;\n                cfg.h.c1 = 0.0;\n            }\n        }\n\n        if (rng.nextInt(5) == 0) swap(cfg.h.a0, cfg.h.a1);\n        if (rng.nextInt(6) == 0) swap(cfg.h.b0, cfg.h.b1);\n        if (rng.nextInt(7) == 0) swap(cfg.h.c0, cfg.h.c1);\n        if (rng.nextInt(5) == 0) swap(cfg.h.g0, cfg.h.g1);\n        if (rng.nextInt(7) == 0) swap(cfg.h.m0, cfg.h.m1);\n\n        cfg.h.stochastic = (rng.nextInt(100) < 90);\n        cfg.h.pickK = 2 + rng.nextInt(7); // 2..8\n        cfg.h.keep = 8 + rng.nextInt(16); // 8..23\n        if (!cfg.h.stochastic) {\n            cfg.h.pickK = 1;\n            cfg.h.keep = 1 + rng.nextInt(8);\n        }\n\n        int laProb = (family == 1 ? 13 : 16);\n        bool allowLA = (remainMs > 1050 && rng.nextInt(100) < laProb);\n\n        if (allowLA) {\n            cfg.lookahead = true;\n            cfg.laDepth = (rng.nextInt(100) < 25 ? 2 : 1);\n\n            if (cfg.laDepth == 2) {\n                cfg.laSteps = 26 + rng.nextInt(55);  // 26..80\n                cfg.laBranch = 3 + rng.nextInt(2);   // 3..4\n                cfg.laCoef = randRange(rng, 0.45, 0.80);\n                cfg.laDecay = randRange(rng, 0.45, 0.70);\n                cfg.laWmix = randRange(rng, 0.08, 0.25);\n            } else {\n                cfg.laSteps = 40 + rng.nextInt(91);  // 40..130\n                cfg.laBranch = 3 + rng.nextInt(3);   // 3..5\n                cfg.laCoef = randRange(rng, 0.55, 1.00);\n                cfg.laDecay = randRange(rng, 0.55, 0.86);\n                cfg.laWmix = randRange(rng, 0.05, 0.22);\n            }\n        } else {\n            cfg.lookahead = false;\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laDepth = 0;\n            cfg.laCoef = 0.0;\n            cfg.laDecay = 0.0;\n            cfg.laWmix = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    RunConfig mutateConfig(const RunConfig &baseCfg, XorShift64 &rng, int remainMs, int familyHint = -1) const {\n        RunConfig cfg = baseCfg;\n\n        auto madd = [&](double v, double sigma, double lo, double hi) {\n            v += normalish(rng) * sigma;\n            return clampD(v, lo, hi);\n        };\n\n        cfg.h.a0 = madd(cfg.h.a0, 0.80, 0.0, 8.0);\n        cfg.h.a1 = madd(cfg.h.a1, 0.45, 0.0, 4.0);\n        cfg.h.b0 = madd(cfg.h.b0, 0.007, 0.0, 0.08);\n        cfg.h.b1 = madd(cfg.h.b1, 0.004, 0.0, 0.05);\n        cfg.h.c0 = madd(cfg.h.c0, 0.14, 0.0, 2.5);\n        cfg.h.c1 = madd(cfg.h.c1, 0.10, 0.0, 2.5);\n        cfg.h.g0 = madd(cfg.h.g0, 0.35, 0.0, 4.0);\n        cfg.h.g1 = madd(cfg.h.g1, 0.25, 0.0, 3.0);\n        cfg.h.m0 = madd(cfg.h.m0, 0.10, 0.0, 1.5);\n        cfg.h.m1 = madd(cfg.h.m1, 0.10, 0.0, 1.5);\n\n        if (familyHint == 0) {\n            cfg.h.c0 = 0.0;\n            cfg.h.c1 = 0.0;\n        } else if (familyHint == 1) {\n            double densC = 1.0;\n            if (density > 0.060) densC = 1.30;\n            else if (density < 0.040) densC = 0.80;\n            if (cfg.h.c0 + cfg.h.c1 < 1e-8) {\n                cfg.h.c0 = randRange(rng, 0.10, 0.95 * densC);\n                cfg.h.c1 = randRange(rng, 0.02, 0.60 * densC);\n            }\n        } else {\n            if (rng.nextInt(100) < 10) {\n                cfg.h.c0 = 0.0;\n                cfg.h.c1 = 0.0;\n            }\n        }\n\n        if (rng.nextInt(100) < 9) cfg.h.stochastic = !cfg.h.stochastic;\n        cfg.h.pickK = clamp(cfg.h.pickK + (rng.nextInt(5) - 2), 1, 10);\n        cfg.h.keep = clamp(cfg.h.keep + (rng.nextInt(11) - 5), 1, 32);\n\n        if (remainMs < 950) {\n            cfg.lookahead = false;\n        } else {\n            if (rng.nextInt(100) < 9) cfg.lookahead = !cfg.lookahead;\n            if (!cfg.lookahead && remainMs > 1500 && rng.nextInt(100) < 12) cfg.lookahead = true;\n        }\n\n        if (cfg.lookahead) {\n            if (cfg.laDepth == 0) cfg.laDepth = 1;\n            if (cfg.laSteps == 0) cfg.laSteps = 70;\n            if (cfg.laBranch == 0) cfg.laBranch = 4;\n            if (cfg.laCoef == 0.0) cfg.laCoef = 0.75;\n            if (cfg.laDecay == 0.0) cfg.laDecay = 0.68;\n            if (cfg.laWmix == 0.0) cfg.laWmix = 0.12;\n\n            if (rng.nextInt(100) < 22) cfg.laDepth = clamp(cfg.laDepth + (rng.nextInt(3) - 1), 1, 2);\n            cfg.laSteps = clamp(cfg.laSteps + (rng.nextInt(61) - 30), 20, 220);\n            cfg.laBranch = clamp(cfg.laBranch + (rng.nextInt(3) - 1), 2, 6);\n            cfg.laCoef = clampD(cfg.laCoef + normalish(rng) * 0.08, 0.35, 1.20);\n            cfg.laDecay = clampD(cfg.laDecay + normalish(rng) * 0.08, 0.35, 0.92);\n            cfg.laWmix = clampD(cfg.laWmix + normalish(rng) * 0.04, 0.0, 0.5);\n        } else {\n            cfg.laDepth = 0;\n            cfg.laSteps = 0;\n            cfg.laBranch = 0;\n            cfg.laCoef = 0.0;\n            cfg.laDecay = 0.0;\n            cfg.laWmix = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    RunConfig quickifyConfig(const RunConfig &baseCfg, XorShift64 &rng, int remainMs) const {\n        RunConfig cfg = baseCfg;\n        cfg.lookahead = false;\n        cfg.h.stochastic = true;\n        cfg.h.pickK = 2 + rng.nextInt(3); // 2..4\n        cfg.h.keep = max(cfg.h.pickK, 8 + rng.nextInt(6)); // 8..13\n        cfg.h.m0 = clampD(cfg.h.m0 + normalish(rng) * 0.06, 0.35, 1.2);\n        cfg.h.m1 = clampD(cfg.h.m1 + normalish(rng) * 0.06, 0.30, 1.1);\n\n        if (familyOf(cfg) == 0) {\n            cfg.h.c0 = 0.0;\n            cfg.h.c1 = 0.0;\n        }\n\n        normalizeConfig(cfg, remainMs);\n        return cfg;\n    }\n\n    void addEliteRun(vector<EliteRun> &elites, long long sumW, const RunConfig &cfg, const vector<Move> &ops) const {\n        const int LIM = 8;\n        if ((int)elites.size() == LIM && sumW <= elites.back().sumW) return;\n\n        int pos = 0;\n        while (pos < (int)elites.size() && elites[pos].sumW >= sumW) pos++;\n\n        EliteRun e;\n        e.sumW = sumW;\n        e.cfg = cfg;\n        e.ops = ops;\n\n        elites.insert(elites.begin() + pos, move(e));\n        if ((int)elites.size() > LIM) elites.pop_back();\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t seed = 1469598103934665603ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v;\n            seed *= 1099511628211ULL;\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        for (auto [x, y] : initDots) {\n            mix(((uint64_t)(uint32_t)x << 32) | (uint32_t)y);\n        }\n        return seed ? seed : 1ULL;\n    }\n\npublic:\n    void readInput() {\n        cin >> N >> M;\n        initDots.resize(M);\n        for (int i = 0; i < M; i++) {\n            int x, y;\n            cin >> x >> y;\n            initDots[i] = {x, y};\n        }\n        density = (double)M / (double)(N * N);\n        buildTables();\n    }\n\n    void solve() {\n        Core base = makeBaseState();\n        int baseDotCount = base.dotCount;\n        int totalAddable = max(1, N * N - baseDotCount);\n\n        long long bestSum = base.sumW;\n        vector<Move> bestOps;\n\n        vector<EliteRun> elitesAll;\n\n        array<long long, 2> famBest;\n        famBest.fill(LLONG_MIN);\n        array<long double, 2> famSum{};\n        famSum.fill(0.0L);\n        array<int, 2> famCnt{};\n        famCnt.fill(0);\n\n        XorShift64 rng(makeSeed());\n        auto deadline = Clock::now() + chrono::milliseconds(4760);\n\n        auto mk = [&](double a0, double a1, double b0, double b1, double c0, double c1,\n                      double g0, double g1, double m0, double m1,\n                      bool stochastic, int pickK, int keep,\n                      bool lookahead, int laSteps, int laBranch, int laDepth,\n                      double laCoef, double laDecay, double laWmix) {\n            RunConfig c;\n            c.h = {a0, a1, b0, b1, c0, c1, g0, g1, m0, m1, stochastic, pickK, keep};\n            c.lookahead = lookahead;\n            c.laSteps = laSteps;\n            c.laBranch = laBranch;\n            c.laDepth = laDepth;\n            c.laCoef = laCoef;\n            c.laDecay = laDecay;\n            c.laWmix = laWmix;\n            return c;\n        };\n\n        auto updateFamily = [&](long long score, const RunConfig &cfg) {\n            int f = familyOf(cfg);\n            famBest[f] = max(famBest[f], score);\n            famSum[f] += (long double)score;\n            famCnt[f]++;\n        };\n\n        auto processResult = [&](RunResult &&rr, const RunConfig &cfgUsed) {\n            updateFamily(rr.sumW, cfgUsed);\n            if (rr.sumW > bestSum) {\n                bestSum = rr.sumW;\n                bestOps = rr.ops;\n            }\n            addEliteRun(elitesAll, rr.sumW, cfgUsed, rr.ops);\n        };\n\n        auto runScratch = [&](RunConfig cfg) {\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            normalizeConfig(cfg, remain);\n            if (Clock::now() + chrono::milliseconds(6) >= deadline) return;\n            RunResult rr = runOne(base, cfg, rng, deadline);\n            processResult(move(rr), cfg);\n        };\n\n        auto runFromElitePrefix = [&](const EliteRun &er, int cut, RunConfig cfg) {\n            if (cut <= 0 || cut >= (int)er.ops.size()) {\n                runScratch(cfg);\n                return;\n            }\n\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            normalizeConfig(cfg, remain);\n            if (Clock::now() + chrono::milliseconds(6) >= deadline) return;\n\n            Core st = base;\n            vector<Move> pref;\n            pref.reserve(cut);\n            for (int i = 0; i < cut; i++) {\n                applyMove(st, er.ops[i]);\n                pref.push_back(er.ops[i]);\n            }\n\n            RunResult rr = runFromState(st, move(pref), cfg, baseDotCount, totalAddable, rng, deadline);\n            processResult(move(rr), cfg);\n        };\n\n        auto pickEliteIdx = [&](int family, int topCap) -> int {\n            vector<int> idxs;\n            idxs.reserve(elitesAll.size());\n            for (int i = 0; i < (int)elitesAll.size(); i++) {\n                if (family < 0 || familyOf(elitesAll[i].cfg) == family) {\n                    idxs.push_back(i);\n                    if ((int)idxs.size() >= topCap) break;\n                }\n            }\n            if (idxs.empty()) return -1;\n            int r = pickRankedIndex((int)idxs.size(), rng);\n            return idxs[r];\n        };\n\n        auto chooseFamilySoft = [&](int remainMs) -> int {\n            if (famCnt[0] == 0 && famCnt[1] == 0) return rng.nextInt(2);\n            if (famCnt[0] == 0) return 0;\n            if (famCnt[1] == 0) return 1;\n\n            double avg0 = (double)(famSum[0] / (long double)max(1, famCnt[0]));\n            double avg1 = (double)(famSum[1] / (long double)max(1, famCnt[1]));\n            double b0 = (famBest[0] == LLONG_MIN ? avg0 : (double)famBest[0]);\n            double b1 = (famBest[1] == LLONG_MIN ? avg1 : (double)famBest[1]);\n\n            double scale = (remainMs > 1800 ? 180000.0 : (remainMs > 1000 ? 145000.0 : 120000.0));\n            double p1 = 0.5;\n            p1 += clampD((b1 - b0) / scale, -0.11, 0.11);\n            p1 += clampD((avg1 - avg0) / (scale * 2.2), -0.05, 0.05);\n\n            if (famCnt[0] + 3 < famCnt[1]) p1 -= 0.05;\n            else if (famCnt[1] + 3 < famCnt[0]) p1 += 0.05;\n\n            p1 = clampD(p1, 0.35, 0.65);\n            return (rng.nextDouble() < p1 ? 1 : 0);\n        };\n\n        auto tryPrefix = [&](int family, bool quick) -> bool {\n            int idx = pickEliteIdx(family, quick ? 3 : 5);\n            if (idx < 0 && family != -1) idx = pickEliteIdx(-1, quick ? 3 : 5);\n            if (idx < 0) return false;\n\n            const EliteRun &er = elitesAll[idx];\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n\n            int hint = familyOf(er.cfg);\n            if (!quick && rng.nextInt(100) < 15) hint = 1 - hint; // cross-family continuation\n            RunConfig cfg = mutateConfig(er.cfg, rng, remain, hint);\n            if (!quick && rng.nextInt(100) < 10) cfg = randomConfigFamily(rng, remain, hint);\n            if (quick) cfg = quickifyConfig(cfg, rng, remain);\n\n            int L = (int)er.ops.size();\n            if (L < 8) {\n                runScratch(cfg);\n                return true;\n            }\n\n            int lo = quick ? max(5, L * 30 / 100) : max(6, L * 22 / 100);\n            int hi = quick ? min(L - 1, L * 64 / 100) : min(L - 1, L * 82 / 100);\n            if (remain < 1200) hi = min(hi, max(lo, L * 58 / 100));\n            if (hi < lo) {\n                runScratch(cfg);\n                return true;\n            }\n\n            int cut = lo + (hi > lo ? rng.nextInt(hi - lo + 1) : 0);\n            runFromElitePrefix(er, cut, cfg);\n            return true;\n        };\n\n        // ---- Presets ----\n        vector<RunConfig> presets;\n        // legacy stable\n        presets.push_back(mk(3.0, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, false, 1, 1, false, 0, 0, 0, 0, 0, 0));\n\n        // classic family\n        presets.push_back(mk(2.5, 0.3, 0.010, 0.001, 0.0, 0.0, 1.2, 0.1, 0.95, 0.85, true, 4, 20, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(0.9, 0.0, 0.001, 0.0, 0.0, 0.0, 0.5, 0.0, 0.65, 0.50, true, 6, 24, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(4.4, 0.9, 0.020, 0.002, 0.0, 0.0, 1.8, 0.2, 1.0, 0.9, false, 1, 12, true, 90, 4, 1, 0.78, 0.70, 0.10));\n        presets.push_back(mk(3.6, 0.7, 0.015, 0.003, 0.0, 0.0, 1.2, 0.1, 0.95, 0.85, true, 3, 12, true, 45, 3, 2, 0.62, 0.62, 0.14));\n\n        // congestion family\n        presets.push_back(mk(4.8, 1.1, 0.022, 0.003, 0.70, 0.25, 1.3, 0.1, 1.0, 0.9, false, 1, 12, false, 0, 0, 0, 0, 0, 0));\n        presets.push_back(mk(2.6, 0.4, 0.010, 0.001, 0.55, 0.15, 0.9, 0.1, 0.95, 0.80, true, 4, 16, true, 55, 3, 1, 0.66, 0.66, 0.10));\n        presets.push_back(mk(3.0, 0.5, 0.012, 0.002, 0.85, 0.25, 1.0, 0.1, 0.95, 0.82, true, 3, 14, true, 42, 3, 2, 0.56, 0.58, 0.12));\n\n        if (density < 0.040) {\n            presets.push_back(mk(5.3, 1.2, 0.028, 0.005, 0.0, 0.0, 1.7, 0.25, 1.0, 0.9, false, 1, 10, false, 0, 0, 0, 0, 0, 0));\n        } else {\n            presets.push_back(mk(1.2, 0.1, 0.003, 0.0, 0.95, 0.30, 0.7, 0.0, 0.8, 0.65, true, 5, 18, false, 0, 0, 0, 0, 0, 0));\n        }\n\n        for (auto cfg : presets) {\n            if (Clock::now() + chrono::milliseconds(12) >= deadline) break;\n            runScratch(cfg);\n        }\n\n        // ---- Main loop ----\n        while (Clock::now() + chrono::milliseconds(25) < deadline) {\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            int fam = chooseFamilySoft(remain);\n            int mode = rng.nextInt(100);\n\n            if (remain > 1900) {\n                if (mode < 14 && !elitesAll.empty()) {\n                    if (!tryPrefix(-1, false)) runScratch(randomConfigFamily(rng, remain, fam));\n                } else if (mode < 48 && !elitesAll.empty()) {\n                    int eidx = pickEliteIdx((rng.nextInt(100) < 72 ? fam : -1), 5);\n                    if (eidx >= 0) {\n                        int ef = familyOf(elitesAll[eidx].cfg);\n                        int hint = ef;\n                        if (rng.nextInt(100) < 14) hint = 1 - ef;\n                        RunConfig cfg = mutateConfig(elitesAll[eidx].cfg, rng, remain, hint);\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, fam));\n                    }\n                } else if (mode < 62 && !elitesAll.empty()) {\n                    // replay elite policy (stochastic path variation)\n                    int eidx = pickEliteIdx((rng.nextInt(100) < 70 ? fam : -1), 5);\n                    if (eidx >= 0) {\n                        RunConfig cfg = elitesAll[eidx].cfg;\n                        if (rng.nextInt(100) < 16) cfg = mutateConfig(cfg, rng, remain, familyOf(cfg));\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, fam));\n                    }\n                } else {\n                    int fam2 = (rng.nextInt(100) < 68 ? fam : 1 - fam);\n                    runScratch(randomConfigFamily(rng, remain, fam2));\n                }\n            } else if (remain > 1000) {\n                if (mode < 30 && !elitesAll.empty()) {\n                    if (!tryPrefix(fam, false)) runScratch(randomConfigFamily(rng, remain, fam));\n                } else if (mode < 68 && !elitesAll.empty()) {\n                    int eidx = pickEliteIdx((rng.nextInt(100) < 76 ? fam : -1), 6);\n                    if (eidx >= 0) {\n                        int ef = familyOf(elitesAll[eidx].cfg);\n                        int hint = ef;\n                        if (rng.nextInt(100) < 20) hint = 1 - ef;\n                        RunConfig cfg = mutateConfig(elitesAll[eidx].cfg, rng, remain, hint);\n                        if (rng.nextInt(100) < 22) cfg = quickifyConfig(cfg, rng, remain);\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, fam));\n                    }\n                } else if (mode < 80 && !elitesAll.empty()) {\n                    int eidx = pickEliteIdx((rng.nextInt(100) < 70 ? fam : -1), 5);\n                    if (eidx >= 0) {\n                        RunConfig cfg = elitesAll[eidx].cfg;\n                        if (rng.nextInt(100) < 20) cfg = quickifyConfig(cfg, rng, remain);\n                        runScratch(cfg);\n                    } else {\n                        runScratch(randomConfigFamily(rng, remain, fam));\n                    }\n                } else {\n                    int fam2 = (rng.nextInt(100) < 62 ? fam : 1 - fam);\n                    runScratch(randomConfigFamily(rng, remain, fam2));\n                }\n            } else {\n                if (mode < 74 && !elitesAll.empty()) {\n                    if (!tryPrefix(fam, true)) {\n                        RunConfig cfg = quickifyConfig(randomConfigFamily(rng, remain, fam), rng, remain);\n                        runScratch(cfg);\n                    }\n                } else if (mode < 88 && !elitesAll.empty()) {\n                    int eidx = pickEliteIdx((rng.nextInt(100) < 70 ? fam : -1), 4);\n                    if (eidx >= 0) {\n                        RunConfig cfg = quickifyConfig(elitesAll[eidx].cfg, rng, remain);\n                        runScratch(cfg);\n                    } else {\n                        RunConfig cfg = quickifyConfig(randomConfigFamily(rng, remain, fam), rng, remain);\n                        runScratch(cfg);\n                    }\n                } else {\n                    int fam2 = (rng.nextInt(100) < 65 ? fam : 1 - fam);\n                    RunConfig cfg = quickifyConfig(randomConfigFamily(rng, remain, fam2), rng, remain);\n                    runScratch(cfg);\n                }\n            }\n        }\n\n        // ---- Final quick family-specific tweaks ----\n        if (Clock::now() + chrono::milliseconds(70) < deadline) {\n            for (int fam = 0; fam <= 1; fam++) {\n                if (Clock::now() + chrono::milliseconds(24) >= deadline) break;\n                int idx = -1;\n                for (int i = 0; i < (int)elitesAll.size(); i++) {\n                    if (familyOf(elitesAll[i].cfg) == fam) {\n                        idx = i;\n                        break;\n                    }\n                }\n                if (idx < 0) continue;\n\n                const EliteRun &er = elitesAll[idx];\n                int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n                RunConfig cfg = mutateConfig(er.cfg, rng, remain, fam);\n                cfg = quickifyConfig(cfg, rng, remain);\n\n                int L = (int)er.ops.size();\n                if (L >= 8) {\n                    int cut = clamp((int)((long long)L * 45 / 100LL), 6, L - 1);\n                    runFromElitePrefix(er, cut, cfg);\n                } else {\n                    runScratch(cfg);\n                }\n            }\n        }\n\n        // ---- Small deterministic polish if time allows ----\n        if (!elitesAll.empty() && Clock::now() + chrono::milliseconds(120) < deadline) {\n            const EliteRun &er = elitesAll[0];\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            RunConfig cfg = er.cfg;\n            cfg.lookahead = false;\n            cfg.h.stochastic = false;\n            cfg.h.pickK = 1;\n            cfg.h.keep = 1;\n            if (familyOf(cfg) == 1 && rng.nextInt(100) < 50) {\n                cfg.h.c0 = 0.0;\n                cfg.h.c1 = 0.0;\n            }\n            normalizeConfig(cfg, remain);\n\n            int L = (int)er.ops.size();\n            if (L >= 10) {\n                int pct = 45 + rng.nextInt(11); // 45..55\n                int cut = clamp((int)((long long)L * pct / 100LL), 6, L - 1);\n                runFromElitePrefix(er, cut, cfg);\n            } else {\n                runScratch(cfg);\n            }\n        }\n\n        // ---- Final intensification ----\n        vector<EliteRun> finalSeeds = elitesAll;\n        if ((int)finalSeeds.size() > 4) finalSeeds.resize(4);\n\n        int cyc = 0;\n        while (!finalSeeds.empty() && Clock::now() + chrono::milliseconds(18) < deadline) {\n            int remain = (int)chrono::duration_cast<chrono::milliseconds>(deadline - Clock::now()).count();\n            const EliteRun &er = finalSeeds[cyc % finalSeeds.size()];\n            cyc++;\n\n            RunConfig cfg = mutateConfig(er.cfg, rng, remain, familyOf(er.cfg));\n            cfg = quickifyConfig(cfg, rng, remain);\n\n            int L = (int)er.ops.size();\n            if (L >= 10) {\n                static const int PCTS[5] = {28, 38, 48, 58, 66};\n                int pct = PCTS[rng.nextInt(5)];\n                int cut = clamp((int)((long long)L * pct / 100LL), 6, L - 1);\n                runFromElitePrefix(er, cut, cfg);\n            } else {\n                runScratch(cfg);\n            }\n        }\n\n        cout << bestOps.size() << '\\n';\n        for (const auto &m : bestOps) {\n            cout << m.x1 << ' ' << m.y1 << ' '\n                 << m.x2 << ' ' << m.y2 << ' '\n                 << m.x3 << ' ' << m.y3 << ' '\n                 << m.x4 << ' ' << m.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 10;\nstatic constexpr int CELLS = 100;\nstatic constexpr double TIME_LIMIT = 1.92;\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'};\n\nstruct XorShift {\n    uint64_t x;\n    explicit XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint32_t next_u32() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return static_cast<uint32_t>(x);\n    }\n    inline int next_int(int l, int r) { // inclusive\n        return l + static_cast<int>(next_u32() % static_cast<uint32_t>(r - l + 1));\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Board {\n    uint8_t a[CELLS];\n    int filled;\n};\n\nint FLV[101];\nint SUF[102][4];\nint NEI[CELLS][4];\n\ninline void init_neighbors() {\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int id = r * N + c;\n            NEI[id][0] = (r > 0) ? id - N : -1;      // F (up)\n            NEI[id][1] = (r + 1 < N) ? id + N : -1;  // B (down)\n            NEI[id][2] = (c > 0) ? id - 1 : -1;      // L\n            NEI[id][3] = (c + 1 < N) ? id + 1 : -1;  // R\n        }\n    }\n}\n\ninline void tilt(const Board& src, Board& dst, int dir) {\n    dst.filled = src.filled;\n    if (dir == 2) { // L\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = 0;\n            for (int c = 0; c < N; ++c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w++)] = v;\n            }\n            while (w < N) dst.a[base + (w++)] = 0;\n        }\n    } else if (dir == 3) { // R\n        for (int r = 0; r < N; ++r) {\n            int base = r * N;\n            int w = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                uint8_t v = src.a[base + c];\n                if (v) dst.a[base + (w--)] = v;\n            }\n            while (w >= 0) dst.a[base + (w--)] = 0;\n        }\n    } else if (dir == 0) { // F\n        for (int c = 0; c < N; ++c) {\n            int w = 0;\n            for (int r = 0; r < N; ++r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w++) * N + c] = v;\n            }\n            while (w < N) dst.a[(w++) * N + c] = 0;\n        }\n    } else { // B\n        for (int c = 0; c < N; ++c) {\n            int w = N - 1;\n            for (int r = N - 1; r >= 0; --r) {\n                uint8_t v = src.a[r * N + c];\n                if (v) dst.a[(w--) * N + c] = v;\n            }\n            while (w >= 0) dst.a[(w--) * N + c] = 0;\n        }\n    }\n}\n\ninline void place_by_rank(Board& b, int rank, uint8_t flavor) {\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            if (--rank == 0) {\n                b.a[i] = flavor;\n                ++b.filled;\n                return;\n            }\n        }\n    }\n    // fallback\n    for (int i = 0; i < CELLS; ++i) {\n        if (b.a[i] == 0) {\n            b.a[i] = flavor;\n            ++b.filled;\n            return;\n        }\n    }\n}\n\ninline void comp_stats(const Board& b, int sq[4], int mx[4]) {\n    sq[0] = sq[1] = sq[2] = sq[3] = 0;\n    mx[0] = mx[1] = mx[2] = mx[3] = 0;\n\n    static uint32_t seen[CELLS];\n    static uint32_t stamp = 1;\n    ++stamp;\n    if (stamp == 0) {\n        memset(seen, 0, sizeof(seen));\n        stamp = 1;\n    }\n\n    int q[CELLS];\n    for (int i = 0; i < CELLS; ++i) {\n        uint8_t col = b.a[i];\n        if (col == 0 || seen[i] == stamp) continue;\n\n        seen[i] = stamp;\n        int head = 0, tail = 0;\n        q[tail++] = i;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            ++sz;\n            for (int k = 0; k < 4; ++k) {\n                int to = NEI[v][k];\n                if (to >= 0 && seen[to] != stamp && b.a[to] == col) {\n                    seen[to] = stamp;\n                    q[tail++] = to;\n                }\n            }\n        }\n        sq[col] += sz * sz;\n        mx[col] = max(mx[col], sz);\n    }\n}\n\ninline int comp_sq_total(const Board& b) {\n    int sq[4], mx[4];\n    comp_stats(b, sq, mx);\n    return sq[1] + sq[2] + sq[3];\n}\n\ninline int same_adj_pairs(const Board& b) {\n    int adj = 0;\n    for (int r = 0; r < N; ++r) {\n        int base = r * N;\n        for (int c = 0; c < N; ++c) {\n            int id = base + c;\n            uint8_t v = b.a[id];\n            if (!v) continue;\n            if (c + 1 < N && b.a[id + 1] == v) ++adj;\n            if (r + 1 < N && b.a[id + N] == v) ++adj;\n        }\n    }\n    return adj;\n}\n\ninline long long state_score(const Board& b, int nextTurn) {\n    if (nextTurn < 1) nextTurn = 1;\n    if (nextTurn > 101) nextTurn = 101;\n\n    int sq[4], mx[4];\n    comp_stats(b, sq, mx);\n\n    long long totalSq = 1LL * sq[1] + sq[2] + sq[3];\n    long long score = 100LL * totalSq;\n\n    for (int f = 1; f <= 3; ++f) {\n        int rem = SUF[nextTurn][f];\n        score += 1LL * sq[f] * rem;\n        score += 2LL * mx[f] * rem;\n    }\n\n    if (nextTurn >= 70) score += 6LL * same_adj_pairs(b);\n    return score;\n}\n\ninline void greedy_tilt_step(Board& b, int turn) {\n    Board tmp, bestB;\n    long long bestVal = LLONG_MIN;\n    for (int d = 0; d < 4; ++d) {\n        tilt(b, tmp, d);\n        long long v = state_score(tmp, turn + 1);\n        if (v > bestVal) {\n            bestVal = v;\n            bestB = tmp;\n        }\n    }\n    b = bestB;\n}\n\ninline long long rollout_greedy(const Board& start, int t, int endTurn, const uint8_t ranks[101]) {\n    Board b = start;\n    for (int u = t + 1; u <= endTurn; ++u) {\n        place_by_rank(b, (int)ranks[u], (uint8_t)FLV[u]);\n        if (u < 100) greedy_tilt_step(b, u);\n    }\n    if (endTurn >= 100) return 100LL * comp_sq_total(b);\n    return state_score(b, endTurn + 1);\n}\n\ninline long long rollout_beam2(const Board& start, int t, int endTurn, const uint8_t ranks[101]) {\n    Board cur[2], cand[8], tmp;\n    long long candVal[8];\n    int curN = 1;\n    cur[0] = start;\n\n    for (int u = t + 1; u <= endTurn; ++u) {\n        for (int i = 0; i < curN; ++i) {\n            place_by_rank(cur[i], (int)ranks[u], (uint8_t)FLV[u]);\n        }\n        if (u == 100) break;\n\n        int candN = 0;\n        for (int i = 0; i < curN; ++i) {\n            for (int d = 0; d < 4; ++d) {\n                tilt(cur[i], tmp, d);\n                cand[candN] = tmp;\n                candVal[candN] = state_score(tmp, u + 1);\n                ++candN;\n            }\n        }\n\n        int keep = min(2, candN);\n        for (int k = 0; k < keep; ++k) {\n            int bi = k;\n            for (int j = k + 1; j < candN; ++j) {\n                if (candVal[j] > candVal[bi]) bi = j;\n            }\n            if (bi != k) {\n                swap(candVal[bi], candVal[k]);\n                swap(cand[bi], cand[k]);\n            }\n            cur[k] = cand[k];\n        }\n        curN = keep;\n    }\n\n    long long best = LLONG_MIN;\n    if (endTurn >= 100) {\n        for (int i = 0; i < curN; ++i) best = max(best, 100LL * comp_sq_total(cur[i]));\n    } else {\n        int nt = endTurn + 1;\n        for (int i = 0; i < curN; ++i) best = max(best, state_score(cur[i], nt));\n    }\n    return best;\n}\n\ndouble exact_expect(const Board& b, int nextTurn) {\n    // board state before placing candy nextTurn\n    if (nextTurn == 101) return (double)comp_sq_total(b);\n\n    int empties = 101 - nextTurn;\n    double sum = 0.0;\n\n    for (int p = 1; p <= empties; ++p) {\n        Board placed = b;\n        place_by_rank(placed, p, (uint8_t)FLV[nextTurn]);\n\n        if (nextTurn == 100) {\n            sum += (double)comp_sq_total(placed);\n        } else {\n            double best = -1e100;\n            Board nxt;\n            for (int d = 0; d < 4; ++d) {\n                tilt(placed, nxt, d);\n                double v = exact_expect(nxt, nextTurn + 1);\n                if (v > best) best = v;\n            }\n            sum += best;\n        }\n    }\n    return sum / (double)empties;\n}\n\nbool one_step_prior(\n    const Board first[4], int t, XorShift& rng, const Timer& timer, double softDeadline, long double out[4]\n) {\n    int u = t + 1;\n    if (u > 100) return false;\n    int empties = 100 - t;\n\n    int L;\n    bool exact = false;\n    if (empties <= 12) {\n        L = empties;\n        exact = true;\n    } else if (empties <= 30) {\n        L = 12;\n    } else {\n        L = 8;\n    }\n\n    static int sample[100];\n    if (exact) {\n        for (int i = 0; i < L; ++i) sample[i] = i + 1;\n    } else {\n        static int ord[100];\n        for (int i = 0; i < empties; ++i) ord[i] = i + 1;\n        for (int i = 0; i < L; ++i) {\n            int j = rng.next_int(i, empties - 1);\n            swap(ord[i], ord[j]);\n            sample[i] = ord[i];\n        }\n    }\n\n    Board b, tmp;\n    for (int d = 0; d < 4; ++d) {\n        long long acc = 0;\n        for (int i = 0; i < L; ++i) {\n            if ((i & 3) == 0 && timer.elapsed() > softDeadline) return false;\n\n            b = first[d];\n            place_by_rank(b, sample[i], (uint8_t)FLV[u]);\n\n            long long v;\n            if (u == 100) {\n                v = 100LL * comp_sq_total(b);\n            } else {\n                long long best = LLONG_MIN;\n                for (int d2 = 0; d2 < 4; ++d2) {\n                    tilt(b, tmp, d2);\n                    best = max(best, state_score(tmp, u + 1));\n                }\n                v = best;\n            }\n            acc += v;\n        }\n        out[d] = (long double)acc / (long double)L;\n    }\n    return true;\n}\n\nint choose_move(const Board& cur, int t, XorShift& rng, const Timer& timer) {\n    int rem = 100 - t;\n    if (rem <= 0) return 0;\n\n    Board first[4];\n    long long firstV[4];\n    for (int d = 0; d < 4; ++d) {\n        tilt(cur, first[d], d);\n        firstV[d] = state_score(first[d], t + 1);\n    }\n\n    int bestImmediate = 0;\n    for (int d = 1; d < 4; ++d) if (firstV[d] > firstV[bestImmediate]) bestImmediate = d;\n\n    double now = timer.elapsed();\n    double timeLeft = TIME_LIMIT - now;\n    if (timeLeft < 0.010) return bestImmediate;\n\n    // exact endgame\n    if (rem <= 5 && timeLeft > 0.090) {\n        int bestDir = bestImmediate;\n        double bestVal = -1e100;\n        for (int d = 0; d < 4; ++d) {\n            double v = exact_expect(first[d], t + 1);\n            if (v > bestVal + 1e-12 ||\n                (fabs(v - bestVal) <= 1e-12 && firstV[d] > firstV[bestDir])) {\n                bestVal = v;\n                bestDir = d;\n            }\n        }\n        return bestDir;\n    }\n\n    if (now >= TIME_LIMIT - 0.003) return bestImmediate;\n\n    // time budget\n    double reserve = 0.055;\n    double freeTime = timeLeft - reserve;\n    if (freeTime <= 0.0) return bestImmediate;\n\n    double base = freeTime / (rem + 1);\n    double phase;\n    if (rem >= 70) phase = 0.60;\n    else if (rem >= 45) phase = 0.92;\n    else if (rem >= 25) phase = 1.28;\n    else phase = 1.70;\n\n    double budget = base * phase;\n    budget = max(0.0010, min(0.042, budget));\n\n    // ambiguity correction using immediate scores\n    int b1 = 0, b2 = 1;\n    if (firstV[b2] > firstV[b1]) swap(b1, b2);\n    for (int d = 2; d < 4; ++d) {\n        if (firstV[d] > firstV[b1]) {\n            b2 = b1;\n            b1 = d;\n        } else if (firstV[d] > firstV[b2]) {\n            b2 = d;\n        }\n    }\n    long long gap = firstV[b1] - firstV[b2];\n    long long absTop = llabs(firstV[b1]) + 1;\n    if (gap * 45LL < absTop) budget *= 1.20;\n    else if (gap * 18LL > absTop) budget *= 0.88;\n\n    budget = min(budget, freeTime * 0.92);\n    if (budget < 0.0010) return bestImmediate;\n\n    double deadline = min(TIME_LIMIT - 0.0015, timer.elapsed() + budget);\n\n    // horizon\n    int H;\n    if (rem >= 70) H = 8;\n    else if (rem >= 52) H = 11;\n    else if (rem >= 36) H = 14;\n    else if (rem >= 24) H = 18;\n    else H = rem;\n\n    if (budget < 0.0034) H = min(H, 12);\n    if (budget < 0.0025) H = min(H, 9);\n    H = max(1, min(H, rem));\n\n    int endTurn = t + H;\n\n    long double total[4];\n    for (int d = 0; d < 4; ++d) total[d] = 0.90L * (long double)firstV[d];\n\n    // one-step prior\n    if (rem <= 58 && budget >= 0.0030) {\n        long double prior[4];\n        double pd = min(deadline, timer.elapsed() + min(0.22 * budget, 0.0045));\n        if (one_step_prior(first, t, rng, timer, pd, prior)) {\n            long double w;\n            if (rem <= 18) w = 1.55L;\n            else if (rem <= 35) w = 1.30L;\n            else w = 1.05L;\n            for (int d = 0; d < 4; ++d) total[d] += w * prior[d];\n        }\n    }\n\n    bool useBeam2 = (rem <= 14 && budget >= 0.0070);\n\n    int minScen = (budget >= 0.0045 ? 2 : 1);\n    int maxScen = (useBeam2 ? 96 : 240);\n\n    static uint8_t ranksA[101], ranksB[101];\n    int scen = 0;\n\n    auto eval_one = [&](const uint8_t ranks[101]) {\n        for (int d = 0; d < 4; ++d) {\n            long long v = useBeam2\n                ? rollout_beam2(first[d], t, endTurn, ranks)\n                : rollout_greedy(first[d], t, endTurn, ranks);\n            total[d] += (long double)v;\n        }\n    };\n\n    while (scen < maxScen) {\n        if (scen >= minScen && timer.elapsed() > deadline) break;\n\n        for (int u = t + 1; u <= endTurn; ++u) {\n            int R = 101 - u;\n            int ra = rng.next_int(1, R);\n            ranksA[u] = (uint8_t)ra;\n            ranksB[u] = (uint8_t)(R + 1 - ra); // antithetic\n        }\n\n        eval_one(ranksA);\n        ++scen;\n        if (scen >= maxScen) break;\n\n        if (scen >= minScen && timer.elapsed() > deadline) break;\n        eval_one(ranksB);\n        ++scen;\n    }\n\n    int bestDir = 0;\n    for (int d = 1; d < 4; ++d) {\n        if (total[d] > total[bestDir] + 1e-12L ||\n            (fabsl(total[d] - total[bestDir]) <= 1e-12L && firstV[d] > firstV[bestDir])) {\n            bestDir = d;\n        }\n    }\n    return bestDir;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 1; i <= 100; ++i) {\n        if (!(cin >> FLV[i])) return 0;\n    }\n\n    for (int c = 1; c <= 3; ++c) SUF[101][c] = 0;\n    for (int t = 100; t >= 1; --t) {\n        for (int c = 1; c <= 3; ++c) SUF[t][c] = SUF[t + 1][c];\n        SUF[t][FLV[t]]++;\n    }\n\n    init_neighbors();\n\n    uint64_t seed = 1469598103934665603ull;\n    for (int i = 1; i <= 100; ++i) {\n        seed ^= (uint64_t)(FLV[i] + 131 * i);\n        seed *= 1099511628211ull;\n    }\n    XorShift rng(seed);\n    Timer timer;\n\n    Board cur{};\n    memset(cur.a, 0, sizeof(cur.a));\n    cur.filled = 0;\n\n    for (int t = 1; t <= 100; ++t) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        place_by_rank(cur, p, (uint8_t)FLV[t]);\n\n        int dir = 0; // F\n        if (t < 100) {\n            dir = choose_move(cur, t, rng, timer);\n            Board nxt;\n            tilt(cur, nxt, dir);\n            cur = nxt;\n        }\n\n        cout << DIR_CH[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    inline 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    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n};\n\nstatic inline uint64_t prob_to_u64(double p) {\n    if (p <= 0.0) return 0ULL;\n    if (p >= 1.0) return numeric_limits<uint64_t>::max();\n    long double v = p * (long double)numeric_limits<uint64_t>::max();\n    if (v < 0) v = 0;\n    if (v > (long double)numeric_limits<uint64_t>::max()) v = (long double)numeric_limits<uint64_t>::max();\n    return (uint64_t)v;\n}\n\nstatic inline uint64_t fnv_mix(uint64_t h, uint64_t x) {\n    h ^= x;\n    h *= 1099511628211ULL;\n    return h;\n}\n\nstruct Graph {\n    vector<uint8_t> bits; // length L\n    vector<int> deg_sorted;\n    vector<int> nd_sorted;\n    vector<int> nd2_sorted;\n    int edges = 0;\n    int uniq_sig = 0;\n};\n\nstruct Codebook {\n    int N = 0;\n    int L = 0;\n    int B = 0;\n    int FB = 0;\n    int distinct = 0;\n\n    vector<int> eu, ev;      // edge endpoints by lex index\n    vector<int> pairId;      // B*B -> block feature id\n    vector<int> blockCap;    // FB\n    vector<Graph> graphs;    // size M\n};\n\nstruct FeatureWork {\n    vector<int> deg, nd, nd2;\n    vector<int> ord, bin;\n    vector<uint64_t> key;\n    vector<uint8_t> bits;\n\n    FeatureWork() {}\n    FeatureWork(int N, int L) { init(N, L); }\n\n    void init(int N, int L) {\n        deg.assign(N, 0);\n        nd.assign(N, 0);\n        nd2.assign(N, 0);\n        ord.resize(N);\n        bin.assign(N, 0);\n        key.assign(N, 0);\n        bits.assign(L, 0);\n    }\n};\n\nstruct ProtoBank {\n    int M = 0, N = 0, S = 0, FB = 0;\n    bool useBlock = false;\n\n    // samples\n    vector<int16_t> sdeg;   // M*S*N\n    vector<int16_t> snd;    // M*S*N\n    vector<int32_t> snd2;   // M*S*N\n    vector<uint16_t> sm;    // M*S\n    vector<uint16_t> sblk;  // M*S*FB\n\n    // centers\n    vector<float> cdeg;     // M*N\n    vector<float> cnd;      // M*N\n    vector<float> cnd2;     // M*N\n    vector<float> cm;       // M\n    vector<float> cblk;     // M*FB\n\n    // inverse variances\n    double invD = 1.0;\n    double invN1 = 1.0;\n    double invN2 = 1.0;\n    double invM = 1.0;\n    vector<double> invB;\n};\n\nstruct DecodeParam {\n    double m1 = 1.0; // nd\n    double m2 = 0.0; // nd2\n    double mB = 0.0; // block\n    double mM = 1.0; // edge-count\n\n    double a1 = 0.70;\n    double a2 = 0.10;\n    double a3 = 0.20;\n    bool useSecond = true;\n\n    string name = \"param\";\n};\n\nstruct DecodeResult {\n    int best = 0;\n    double bestScore = 1e300;\n    double secondScore = 1e300;\n};\n\nuint64_t hash_sorted3(const vector<int>& a, const vector<int>& b, const vector<int>& c) {\n    uint64_t h = 1469598103934665603ULL;\n    int n = (int)a.size();\n    for (int i = 0; i < n; i++) {\n        h = fnv_mix(h, (uint64_t)(a[i] + 1));\n        h = fnv_mix(h, (uint64_t)(b[i] + 10007));\n        h = fnv_mix(h, (uint64_t)(c[i] + 1000003));\n    }\n    return h;\n}\n\nuint64_t hash_signature(const Graph& g) {\n    uint64_t h = 1469598103934665603ULL;\n    h = fnv_mix(h, (uint64_t)(g.edges + 1));\n    h = fnv_mix(h, (uint64_t)(g.uniq_sig + 3));\n    int n = (int)g.deg_sorted.size();\n    for (int i = 0; i < n; i++) {\n        h = fnv_mix(h, (uint64_t)(g.deg_sorted[i] + 1));\n        h = fnv_mix(h, (uint64_t)(g.nd_sorted[i] + 10007));\n        h = fnv_mix(h, (uint64_t)(g.nd2_sorted[i] + 1000003));\n    }\n    return h;\n}\n\nvoid build_edges(int N, vector<int>& eu, vector<int>& ev) {\n    eu.clear();\n    ev.clear();\n    eu.reserve(N * (N - 1) / 2);\n    ev.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            eu.push_back(i);\n            ev.push_back(j);\n        }\n    }\n}\n\nint choose_bins(int N) {\n    if (N <= 10) return 3;\n    if (N <= 16) return 4;\n    if (N <= 25) return 5;\n    if (N <= 40) return 6;\n    if (N <= 64) return 8;\n    return 10;\n}\n\nvoid init_block_meta(Codebook& cb) {\n    cb.B = choose_bins(cb.N);\n    cb.FB = cb.B * (cb.B + 1) / 2;\n    cb.pairId.assign(cb.B * cb.B, -1);\n    cb.blockCap.assign(cb.FB, 0);\n\n    vector<int> sz(cb.B);\n    for (int b = 0; b < cb.B; b++) {\n        int l = (long long)b * cb.N / cb.B;\n        int r = (long long)(b + 1) * cb.N / cb.B;\n        sz[b] = r - l;\n    }\n\n    int id = 0;\n    for (int i = 0; i < cb.B; i++) {\n        for (int j = i; j < cb.B; j++) {\n            cb.pairId[i * cb.B + j] = id;\n            cb.pairId[j * cb.B + i] = id;\n            int cap = (i == j) ? (sz[i] * (sz[i] - 1) / 2) : (sz[i] * sz[j]);\n            cb.blockCap[id] = cap;\n            id++;\n        }\n    }\n}\n\nGraph make_graph_from_bits(vector<uint8_t>&& bits, int N, const vector<int>& eu, const vector<int>& ev) {\n    Graph g;\n    g.bits = std::move(bits);\n    int L = (int)eu.size();\n\n    vector<int> deg(N, 0), nd(N, 0), nd2(N, 0);\n    g.edges = 0;\n\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            g.edges++;\n            int u = eu[e], v = ev[e];\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd[u] += deg[v];\n            nd[v] += deg[u];\n        }\n    }\n\n    for (int e = 0; e < L; e++) {\n        if (g.bits[e]) {\n            int u = eu[e], v = ev[e];\n            nd2[u] += nd[v];\n            nd2[v] += nd[u];\n        }\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 (deg[a] != deg[b]) return deg[a] < deg[b];\n        if (nd[a] != nd[b]) return nd[a] < nd[b];\n        if (nd2[a] != nd2[b]) return nd2[a] < nd2[b];\n        return a < b;\n    });\n\n    g.deg_sorted.resize(N);\n    g.nd_sorted.resize(N);\n    g.nd2_sorted.resize(N);\n    g.uniq_sig = 0;\n\n    for (int i = 0; i < N; i++) {\n        int v = ord[i];\n        g.deg_sorted[i] = deg[v];\n        g.nd_sorted[i] = nd[v];\n        g.nd2_sorted[i] = nd2[v];\n\n        if (i == 0) g.uniq_sig++;\n        else {\n            int pv = ord[i - 1];\n            if (deg[v] != deg[pv] || nd[v] != nd[pv] || nd2[v] != nd2[pv]) g.uniq_sig++;\n        }\n    }\n\n    return g;\n}\n\nvector<int> random_group_ids(int N, int K, RNG& rng) {\n    K = min(K, N);\n    vector<int> sz(K, 1);\n    int rem = N - K;\n    for (int i = 0; i < rem; i++) sz[rng.next_int(0, K - 1)]++;\n\n    vector<int> gid;\n    gid.reserve(N);\n    for (int g = 0; g < K; g++) for (int c = 0; c < sz[g]; c++) gid.push_back(g);\n\n    for (int i = N - 1; i >= 1; i--) {\n        int j = rng.next_int(0, i);\n        swap(gid[i], gid[j]);\n    }\n    return gid;\n}\n\nint pick_mode(double eps, RNG& rng) {\n    double r = rng.next_double();\n    if (eps >= 0.28) {\n        if (r < 0.25) return 0;\n        if (r < 0.45) return 4;\n        if (r < 0.63) return 5;\n        if (r < 0.78) return 6;\n        if (r < 0.90) return 7;\n        if (r < 0.97) return 9;\n        return 8;\n    } else if (eps >= 0.15) {\n        if (r < 0.18) return 0;\n        if (r < 0.32) return 1;\n        if (r < 0.44) return 2;\n        if (r < 0.56) return 3;\n        if (r < 0.68) return 4;\n        if (r < 0.78) return 5;\n        if (r < 0.87) return 6;\n        if (r < 0.94) return 7;\n        if (r < 0.97) return 8;\n        return 9;\n    } else {\n        return rng.next_int(0, 9);\n    }\n}\n\nGraph generate_candidate_graph(int N, const vector<int>& eu, const vector<int>& ev, RNG& rng, double eps) {\n    int L = (int)eu.size();\n    vector<uint8_t> bits(L, 0);\n\n    int mode = pick_mode(eps, rng);\n\n    if (mode == 0) {\n        double u = rng.next_double();\n        double p = (rng.next_double() < 0.5) ? (u * u) : (1.0 - (1.0 - u) * (1.0 - u));\n        uint64_t th = prob_to_u64(p);\n        for (int e = 0; e < L; e++) bits[e] = (rng.next_u64() < th);\n    } else if (mode == 1) {\n        int K = rng.next_int(2, min(10, N));\n        auto gid = random_group_ids(N, K, rng);\n        vector<vector<uint8_t>> B(K, vector<uint8_t>(K, 0));\n        for (int i = 0; i < K; i++) for (int j = i; j < K; j++) {\n            uint8_t x = (uint8_t)(rng.next_u64() & 1ULL);\n            B[i][j] = B[j][i] = x;\n        }\n        for (int e = 0; e < L; e++) bits[e] = B[gid[eu[e]]][gid[ev[e]]];\n    } else if (mode == 2) {\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] == gid[ev[e]]);\n    } else if (mode == 3) {\n        int K = rng.next_int(2, min(12, N));\n        auto gid = random_group_ids(N, K, rng);\n        for (int e = 0; e < L; e++) bits[e] = (gid[eu[e]] != gid[ev[e]]);\n    } else if (mode == 4) {\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 2000);\n        for (int e = 0; e < L; e++) bits[e] = (w[eu[e]] + w[ev[e]] >= th);\n    } else if (mode == 5) {\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000000);\n        for (int e = 0; e < L; e++) {\n            long long v = 1LL * w[eu[e]] * w[ev[e]];\n            bits[e] = (v >= th);\n        }\n    } else if (mode == 6) {\n        vector<double> x(N);\n        for (int i = 0; i < N; i++) x[i] = rng.next_double();\n        bool circle = (rng.next_u64() & 1ULL);\n        double th = rng.next_double() * 0.85;\n        for (int e = 0; e < L; e++) {\n            double d = fabs(x[eu[e]] - x[ev[e]]);\n            if (circle) d = min(d, 1.0 - d);\n            bits[e] = (d <= th);\n        }\n    } else if (mode == 7) {\n        int K1 = rng.next_int(2, min(7, N));\n        int K2 = rng.next_int(2, min(7, N));\n        auto g1 = random_group_ids(N, K1, rng);\n        auto g2 = random_group_ids(N, K2, rng);\n        for (int e = 0; e < L; e++) {\n            bool a = (g1[eu[e]] == g1[ev[e]]);\n            bool b = (g2[eu[e]] == g2[ev[e]]);\n            bits[e] = (uint8_t)(a ^ b);\n        }\n    } else if (mode == 8) {\n        vector<uint8_t> dom(N, 0);\n        double p1 = 0.15 + 0.7 * rng.next_double();\n        for (int i = 1; i < N; i++) dom[i] = (uint8_t)(rng.next_double() < p1);\n        for (int e = 0; e < L; e++) bits[e] = dom[ev[e]];\n    } else {\n        vector<int> w(N);\n        for (int i = 0; i < N; i++) w[i] = rng.next_int(0, 1000);\n        int th = rng.next_int(0, 1000);\n        for (int e = 0; e < L; e++) bits[e] = (max(w[eu[e]], w[ev[e]]) >= th);\n    }\n\n    if (rng.next_double() < 0.08) {\n        for (int e = 0; e < L; e++) bits[e] ^= 1;\n    }\n\n    double pmax = (eps >= 0.25 ? 0.05 : 0.07);\n    if (rng.next_double() < 0.85) {\n        double pf = rng.next_double() * pmax;\n        uint64_t th = prob_to_u64(pf);\n        for (int e = 0; e < L; e++) if (rng.next_u64() < th) bits[e] ^= 1;\n    }\n\n    return make_graph_from_bits(std::move(bits), N, eu, ev);\n}\n\nCodebook build_codebook(int N, int M, double eps, int C, RNG& rng) {\n    Codebook cb;\n    cb.N = N;\n    build_edges(N, cb.eu, cb.ev);\n    cb.L = (int)cb.eu.size();\n    init_block_meta(cb);\n\n    vector<Graph> cand;\n    cand.reserve(C);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve((size_t)C * 3);\n\n    int attempts = 0;\n    int maxAttempts = C * 24;\n\n    while ((int)cand.size() < C && attempts < maxAttempts) {\n        Graph g = generate_candidate_graph(N, cb.eu, cb.ev, rng, eps);\n\n        if (eps >= 0.22) {\n            int th = (eps >= 0.30 ? max(3, N / 4) : max(3, N / 6));\n            if (g.uniq_sig < th && rng.next_double() < 0.75) {\n                attempts++;\n                continue;\n            }\n        }\n\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        attempts++;\n    }\n\n    for (int m = 0; (int)cand.size() < C && m <= cb.L; m++) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < m; e++) bits[e] = 1;\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n    }\n\n    int extra = 0;\n    while ((int)cand.size() < C && extra < C * 8) {\n        vector<uint8_t> bits(cb.L, 0);\n        for (int e = 0; e < cb.L; e++) bits[e] = (uint8_t)(rng.next_u64() & 1ULL);\n        Graph g = make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev);\n        uint64_t h = hash_signature(g);\n        if (seen.insert(h).second) cand.push_back(std::move(g));\n        extra++;\n    }\n\n    if (cand.empty()) {\n        vector<uint8_t> bits(cb.L, 0);\n        cand.push_back(make_graph_from_bits(std::move(bits), N, cb.eu, cb.ev));\n    }\n\n    int Cn = (int)cand.size();\n\n    double a = max(0.0, 1.0 - 2.0 * eps);\n    double w1 = (0.04 + 1.0 * a * a) / ((double)N * N);\n    double w2 = (eps < 0.25 ? (0.002 + 0.30 * a * a * a * a) / ((double)N * N * N * N) : 0.0);\n    double wm = (0.20 + 0.80 * a * a) / max(1, cb.L);\n    double lambdaUniq = (eps >= 0.25 ? 0.45 : (eps >= 0.15 ? 0.28 : 0.10));\n\n    auto dist_idx = [&](int ia, int ib) -> double {\n        const auto& A = cand[ia];\n        const auto& B = cand[ib];\n        double s = 0.0;\n\n        for (int i = 0; i < N; i++) {\n            double d = (double)A.deg_sorted[i] - (double)B.deg_sorted[i];\n            s += d * d;\n        }\n        if (w1 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd_sorted[i] - (double)B.nd_sorted[i];\n                s += w1 * d * d;\n            }\n        }\n        if (w2 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)A.nd2_sorted[i] - (double)B.nd2_sorted[i];\n                s += w2 * d * d;\n            }\n        }\n        double dm = (double)A.edges - (double)B.edges;\n        s += wm * dm * dm;\n        return s;\n    };\n\n    vector<int> selected;\n    selected.reserve(M);\n    vector<char> used(Cn, false);\n\n    auto add_seed = [&](int idx) {\n        if (idx < 0 || idx >= Cn || used[idx] || (int)selected.size() >= M) return;\n        used[idx] = true;\n        selected.push_back(idx);\n    };\n\n    vector<int> byEdge(Cn);\n    iota(byEdge.begin(), byEdge.end(), 0);\n    sort(byEdge.begin(), byEdge.end(), [&](int a, int b) {\n        return cand[a].edges < cand[b].edges;\n    });\n\n    int iuniq = 0;\n    for (int i = 1; i < Cn; i++) if (cand[i].uniq_sig > cand[iuniq].uniq_sig) iuniq = i;\n\n    add_seed(byEdge[0]);\n    add_seed(byEdge[Cn - 1]);\n    add_seed(byEdge[Cn / 2]);\n    add_seed(byEdge[Cn / 4]);\n    add_seed(byEdge[(3 * Cn) / 4]);\n    add_seed(iuniq);\n    if (selected.empty()) add_seed(0);\n\n    vector<double> minDist(Cn, 1e300);\n    for (int i = 0; i < Cn; i++) {\n        double d = 1e300;\n        for (int s : selected) d = min(d, dist_idx(i, s));\n        minDist[i] = d;\n    }\n\n    while ((int)selected.size() < M && (int)selected.size() < Cn) {\n        int best = -1;\n        double bestVal = -1.0;\n        for (int i = 0; i < Cn; i++) {\n            if (used[i]) continue;\n            double qual = 1.0 + lambdaUniq * ((double)cand[i].uniq_sig / max(1, N));\n            double val = minDist[i] * qual;\n            if (val > bestVal) {\n                bestVal = val;\n                best = i;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        selected.push_back(best);\n\n        for (int i = 0; i < Cn; i++) {\n            if (!used[i]) {\n                double d = dist_idx(i, best);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    int uniqueSel = (int)selected.size();\n    if (uniqueSel == 0) {\n        selected.push_back(0);\n        uniqueSel = 1;\n    }\n    while ((int)selected.size() < M) {\n        selected.push_back(selected[(int)selected.size() % uniqueSel]);\n    }\n\n    cb.distinct = min(uniqueSel, M);\n    cb.graphs.reserve(M);\n    for (int i = 0; i < M; i++) cb.graphs.push_back(cand[selected[i]]);\n\n    return cb;\n}\n\nvoid extract_features_from_string(\n    const string& H, const Codebook& cb, FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2, vector<int>& outBlk,\n    int& uniq, int& mObs, bool useBlock\n) {\n    int N = cb.N, L = cb.L, B = cb.B, FB = cb.FB;\n\n    if ((int)outDeg.size() != N) {\n        outDeg.assign(N, 0);\n        outNd.assign(N, 0);\n        outNd2.assign(N, 0);\n    }\n    if ((int)outBlk.size() != FB) outBlk.assign(FB, 0);\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    fill(w.nd.begin(), w.nd.end(), 0);\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n\n    mObs = 0;\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            mObs++;\n            int u = cb.eu[e], v = cb.ev[e];\n            w.deg[u]++;\n            w.deg[v]++;\n        }\n    }\n\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    for (int e = 0; e < L; e++) {\n        if (H[e] == '1') {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) w.ord[i] = i;\n    sort(w.ord.begin(), w.ord.end(), [&](int a, int b) {\n        if (w.deg[a] != w.deg[b]) return w.deg[a] < w.deg[b];\n        if (w.nd[a] != w.nd[b]) return w.nd[a] < w.nd[b];\n        if (w.nd2[a] != w.nd2[b]) return w.nd2[a] < w.nd2[b];\n        return a < b;\n    });\n\n    uniq = 0;\n    for (int pos = 0; pos < N; pos++) {\n        int v = w.ord[pos];\n        outDeg[pos] = w.deg[v];\n        outNd[pos] = w.nd[v];\n        outNd2[pos] = w.nd2[v];\n\n        if (pos == 0) uniq++;\n        else {\n            int pv = w.ord[pos - 1];\n            if (w.deg[v] != w.deg[pv] || w.nd[v] != w.nd[pv] || w.nd2[v] != w.nd2[pv]) uniq++;\n        }\n\n        w.bin[v] = (long long)pos * B / N;\n    }\n\n    if (useBlock) {\n        fill(outBlk.begin(), outBlk.end(), 0);\n        for (int e = 0; e < L; e++) {\n            if (H[e] == '1') {\n                int u = cb.eu[e], v = cb.ev[e];\n                int bu = w.bin[u], bv = w.bin[v];\n                if (bu > bv) swap(bu, bv);\n                int id = cb.pairId[bu * B + bv];\n                outBlk[id]++;\n            }\n        }\n    }\n}\n\nvoid sample_noisy_features(\n    const Graph& g, const Codebook& cb, double eps, uint64_t flipThr, RNG& rng,\n    FeatureWork& w,\n    vector<int>& outDeg, vector<int>& outNd, vector<int>& outNd2, vector<int>& outBlk,\n    int& uniq, int& mObs, bool useBlock\n) {\n    int N = cb.N, L = cb.L, B = cb.B, FB = cb.FB;\n\n    if ((int)outDeg.size() != N) {\n        outDeg.assign(N, 0);\n        outNd.assign(N, 0);\n        outNd2.assign(N, 0);\n    }\n    if ((int)outBlk.size() != FB) outBlk.assign(FB, 0);\n\n    fill(w.deg.begin(), w.deg.end(), 0);\n    fill(w.nd.begin(), w.nd.end(), 0);\n    fill(w.nd2.begin(), w.nd2.end(), 0);\n\n    mObs = 0;\n    if (eps <= 0.0) {\n        for (int e = 0; e < L; e++) {\n            uint8_t b = g.bits[e];\n            w.bits[e] = b;\n            if (b) {\n                mObs++;\n                int u = cb.eu[e], v = cb.ev[e];\n                w.deg[u]++;\n                w.deg[v]++;\n            }\n        }\n    } else {\n        for (int e = 0; e < L; e++) {\n            uint8_t b = g.bits[e];\n            if (rng.next_u64() < flipThr) b ^= 1;\n            w.bits[e] = b;\n            if (b) {\n                mObs++;\n                int u = cb.eu[e], v = cb.ev[e];\n                w.deg[u]++;\n                w.deg[v]++;\n            }\n        }\n    }\n\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd[u] += w.deg[v];\n            w.nd[v] += w.deg[u];\n        }\n    }\n\n    for (int e = 0; e < L; e++) {\n        if (w.bits[e]) {\n            int u = cb.eu[e], v = cb.ev[e];\n            w.nd2[u] += w.nd[v];\n            w.nd2[v] += w.nd[u];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        w.ord[i] = i;\n        w.key[i] = rng.next_u64();\n    }\n    sort(w.ord.begin(), w.ord.end(), [&](int a, int b) {\n        if (w.deg[a] != w.deg[b]) return w.deg[a] < w.deg[b];\n        if (w.nd[a] != w.nd[b]) return w.nd[a] < w.nd[b];\n        if (w.nd2[a] != w.nd2[b]) return w.nd2[a] < w.nd2[b];\n        if (w.key[a] != w.key[b]) return w.key[a] < w.key[b];\n        return a < b;\n    });\n\n    uniq = 0;\n    for (int pos = 0; pos < N; pos++) {\n        int v = w.ord[pos];\n        outDeg[pos] = w.deg[v];\n        outNd[pos] = w.nd[v];\n        outNd2[pos] = w.nd2[v];\n\n        if (pos == 0) uniq++;\n        else {\n            int pv = w.ord[pos - 1];\n            if (w.deg[v] != w.deg[pv] || w.nd[v] != w.nd[pv] || w.nd2[v] != w.nd2[pv]) uniq++;\n        }\n\n        w.bin[v] = (long long)pos * B / N;\n    }\n\n    if (useBlock) {\n        fill(outBlk.begin(), outBlk.end(), 0);\n        for (int e = 0; e < L; e++) {\n            if (w.bits[e]) {\n                int u = cb.eu[e], v = cb.ev[e];\n                int bu = w.bin[u], bv = w.bin[v];\n                if (bu > bv) swap(bu, bv);\n                int id = cb.pairId[bu * B + bv];\n                outBlk[id]++;\n            }\n        }\n    }\n}\n\nProtoBank calibrate_prototypes(const Codebook& cb, double eps, int S, bool useBlock, RNG& rng) {\n    ProtoBank pb;\n    pb.M = (int)cb.graphs.size();\n    pb.N = cb.N;\n    pb.S = (eps <= 0.0 ? 1 : max(1, S));\n    pb.FB = cb.FB;\n    pb.useBlock = useBlock;\n\n    size_t sampleN = (size_t)pb.M * pb.S * pb.N;\n    pb.sdeg.assign(sampleN, 0);\n    pb.snd.assign(sampleN, 0);\n    pb.snd2.assign(sampleN, 0);\n    pb.sm.assign((size_t)pb.M * pb.S, 0);\n\n    if (useBlock) pb.sblk.assign((size_t)pb.M * pb.S * pb.FB, 0);\n    else pb.sblk.clear();\n\n    pb.cdeg.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cnd2.assign((size_t)pb.M * pb.N, 0.0f);\n    pb.cm.assign((size_t)pb.M, 0.0f);\n\n    if (useBlock) pb.cblk.assign((size_t)pb.M * pb.FB, 0.0f);\n    else pb.cblk.clear();\n\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N), ob(cb.FB);\n    vector<double> sumD(cb.N), sumN(cb.N), sumN2(cb.N), sumB(cb.FB);\n\n    uint64_t flipThr = prob_to_u64(eps);\n\n    for (int k = 0; k < pb.M; k++) {\n        fill(sumD.begin(), sumD.end(), 0.0);\n        fill(sumN.begin(), sumN.end(), 0.0);\n        fill(sumN2.begin(), sumN2.end(), 0.0);\n        if (useBlock) fill(sumB.begin(), sumB.end(), 0.0);\n        double sumM = 0.0;\n\n        for (int s = 0; s < pb.S; s++) {\n            int uniq = 0, mObs = 0;\n            sample_noisy_features(cb.graphs[k], cb, eps, flipThr, rng, w, od, on, on2, ob, uniq, mObs, useBlock);\n\n            size_t baseN = ((size_t)k * pb.S + s) * pb.N;\n            for (int i = 0; i < pb.N; i++) {\n                pb.sdeg[baseN + i] = (int16_t)od[i];\n                pb.snd[baseN + i] = (int16_t)on[i];\n                pb.snd2[baseN + i] = (int32_t)on2[i];\n                sumD[i] += od[i];\n                sumN[i] += on[i];\n                sumN2[i] += on2[i];\n            }\n\n            if (useBlock) {\n                size_t baseB = ((size_t)k * pb.S + s) * pb.FB;\n                for (int b = 0; b < pb.FB; b++) {\n                    pb.sblk[baseB + b] = (uint16_t)ob[b];\n                    sumB[b] += ob[b];\n                }\n            }\n\n            pb.sm[(size_t)k * pb.S + s] = (uint16_t)mObs;\n            sumM += mObs;\n        }\n\n        for (int i = 0; i < pb.N; i++) {\n            pb.cdeg[(size_t)k * pb.N + i] = (float)(sumD[i] / pb.S);\n            pb.cnd[(size_t)k * pb.N + i] = (float)(sumN[i] / pb.S);\n            pb.cnd2[(size_t)k * pb.N + i] = (float)(sumN2[i] / pb.S);\n        }\n        pb.cm[k] = (float)(sumM / pb.S);\n\n        if (useBlock) {\n            for (int b = 0; b < pb.FB; b++) {\n                pb.cblk[(size_t)k * pb.FB + b] = (float)(sumB[b] / pb.S);\n            }\n        }\n    }\n\n    // global variances\n    double varD = 0.0, varN1 = 0.0, varN2 = 0.0, varM = 0.0;\n    vector<double> varB(useBlock ? pb.FB : 0, 0.0);\n\n    for (int k = 0; k < pb.M; k++) {\n        for (int s = 0; s < pb.S; s++) {\n            size_t baseN = ((size_t)k * pb.S + s) * pb.N;\n            size_t cN = (size_t)k * pb.N;\n\n            for (int i = 0; i < pb.N; i++) {\n                double d0 = (double)pb.sdeg[baseN + i] - (double)pb.cdeg[cN + i];\n                double d1 = (double)pb.snd[baseN + i] - (double)pb.cnd[cN + i];\n                double d2 = (double)pb.snd2[baseN + i] - (double)pb.cnd2[cN + i];\n                varD += d0 * d0;\n                varN1 += d1 * d1;\n                varN2 += d2 * d2;\n            }\n\n            if (useBlock) {\n                size_t baseB = ((size_t)k * pb.S + s) * pb.FB;\n                size_t cB = (size_t)k * pb.FB;\n                for (int b = 0; b < pb.FB; b++) {\n                    double db = (double)pb.sblk[baseB + b] - (double)pb.cblk[cB + b];\n                    varB[b] += db * db;\n                }\n            }\n\n            double dm = (double)pb.sm[(size_t)k * pb.S + s] - (double)pb.cm[k];\n            varM += dm * dm;\n        }\n    }\n\n    double cntN = (double)pb.M * pb.S * pb.N;\n    double cntM = (double)pb.M * pb.S;\n    if (cntN <= 0) cntN = 1.0;\n    if (cntM <= 0) cntM = 1.0;\n\n    varD /= cntN;\n    varN1 /= cntN;\n    varN2 /= cntN;\n    varM /= cntM;\n\n    double baseD = max(0.0, (cb.N - 1) * eps * (1.0 - eps));\n    varD = max(varD, 0.50 * baseD);\n    varM = max(varM, 1.0 + 0.50 * cb.L * eps * (1.0 - eps));\n\n    pb.invD = 1.0 / (varD + 1.0);\n    pb.invN1 = 1.0 / (varN1 + cb.N + 1.0);\n    pb.invN2 = 1.0 / (varN2 + (double)cb.N * cb.N + 1.0);\n    pb.invM = 1.0 / (varM + 1.0);\n\n    if (useBlock) {\n        pb.invB.assign(pb.FB, 1.0);\n        double cntB = (double)pb.M * pb.S;\n        if (cntB <= 0) cntB = 1.0;\n        for (int b = 0; b < pb.FB; b++) {\n            varB[b] /= cntB;\n            double baseBb = 0.35 * cb.blockCap[b] * eps * (1.0 - eps);\n            double vb = max(varB[b], baseBb);\n            pb.invB[b] = 1.0 / (vb + 1.0);\n        }\n    } else {\n        pb.invB.clear();\n    }\n\n    return pb;\n}\n\nvoid dynamic_scales(int uniq, int N, double eps, double& sN2, double& sB, double& sM) {\n    double r = (double)uniq / max(1, N);\n\n    double u0, u1;\n    if (eps < 0.10) {\n        u0 = 0.10; u1 = 0.45;\n    } else if (eps < 0.25) {\n        u0 = 0.14; u1 = 0.50;\n    } else {\n        u0 = 0.18; u1 = 0.58;\n    }\n\n    double t = (r - u0) / (u1 - u0);\n    t = max(0.0, min(1.0, t));\n\n    sN2 = 0.55 + 0.45 * t;\n    sB  = 0.35 + 0.65 * t;\n    sM  = 1.0 + 0.50 * (1.0 - t);\n\n    if (eps >= 0.30) sB *= 0.25;\n    if (eps >= 0.35) sB = 0.0;\n}\n\nDecodeResult decode_with_param(\n    const vector<int>& od, const vector<int>& on, const vector<int>& on2, const vector<int>& ob,\n    int uniq, int mObs, const ProtoBank& pb, const DecodeParam& prm, double eps\n) {\n    int M = pb.M, N = pb.N, S = pb.S, FB = pb.FB;\n\n    double sN2, sB, sM;\n    dynamic_scales(uniq, N, eps, sN2, sB, sM);\n\n    double cD  = pb.invD;\n    double cN1 = prm.m1 * pb.invN1;\n    double cN2 = prm.m2 * pb.invN2 * sN2;\n    double cB  = (pb.useBlock ? prm.mB * sB : 0.0);\n    double cM  = prm.mM * pb.invM * sM;\n\n    DecodeResult ret;\n\n    for (int k = 0; k < M; k++) {\n        double best1 = 1e300, best2 = 1e300;\n\n        for (int s = 0; s < S; s++) {\n            size_t baseN = ((size_t)k * S + s) * N;\n            const int16_t* pd = pb.sdeg.data() + baseN;\n            const int16_t* pn = pb.snd.data() + baseN;\n            const int32_t* p2 = pb.snd2.data() + baseN;\n\n            double cutoff = best2;\n            double dsum = 0.0;\n\n            for (int i = 0; i < N; i++) {\n                double d = (double)od[i] - (double)pd[i];\n                dsum += cD * d * d;\n                if (dsum >= cutoff) break;\n            }\n            if (dsum >= cutoff) continue;\n\n            if (cN1 > 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on[i] - (double)pn[i];\n                    dsum += cN1 * d * d;\n                    if (dsum >= cutoff) break;\n                }\n                if (dsum >= cutoff) continue;\n            }\n\n            if (cN2 > 0.0) {\n                for (int i = 0; i < N; i++) {\n                    double d = (double)on2[i] - (double)p2[i];\n                    dsum += cN2 * d * d;\n                    if (dsum >= cutoff) break;\n                }\n                if (dsum >= cutoff) continue;\n            }\n\n            if (pb.useBlock && cB > 0.0) {\n                size_t baseB = ((size_t)k * S + s) * FB;\n                const uint16_t* pbk = pb.sblk.data() + baseB;\n                for (int b = 0; b < FB; b++) {\n                    double d = (double)ob[b] - (double)pbk[b];\n                    dsum += cB * pb.invB[b] * d * d;\n                    if (dsum >= cutoff) break;\n                }\n                if (dsum >= cutoff) continue;\n            }\n\n            if (cM > 0.0) {\n                double d = (double)mObs - (double)pb.sm[(size_t)k * S + s];\n                dsum += cM * d * d;\n            }\n\n            if (dsum < best1) {\n                best2 = best1;\n                best1 = dsum;\n            } else if (dsum < best2) {\n                best2 = dsum;\n            }\n        }\n\n        if (!prm.useSecond || best2 > 1e299) best2 = best1;\n\n        // center distance\n        size_t cN = (size_t)k * N;\n        const float* cd = pb.cdeg.data() + cN;\n        const float* cn = pb.cnd.data() + cN;\n        const float* c2 = pb.cnd2.data() + cN;\n\n        double cdist = 0.0;\n        for (int i = 0; i < N; i++) {\n            double d = (double)od[i] - (double)cd[i];\n            cdist += cD * d * d;\n        }\n\n        if (cN1 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on[i] - (double)cn[i];\n                cdist += cN1 * d * d;\n            }\n        }\n\n        if (cN2 > 0.0) {\n            for (int i = 0; i < N; i++) {\n                double d = (double)on2[i] - (double)c2[i];\n                cdist += cN2 * d * d;\n            }\n        }\n\n        if (pb.useBlock && cB > 0.0) {\n            size_t cBidx = (size_t)k * FB;\n            const float* cbk = pb.cblk.data() + cBidx;\n            for (int b = 0; b < FB; b++) {\n                double d = (double)ob[b] - (double)cbk[b];\n                cdist += cB * pb.invB[b] * d * d;\n            }\n        }\n\n        if (cM > 0.0) {\n            double d = (double)mObs - (double)pb.cm[k];\n            cdist += cM * d * d;\n        }\n\n        double score = prm.a1 * best1 + prm.a2 * best2 + prm.a3 * cdist;\n\n        if (score < ret.bestScore) {\n            ret.secondScore = ret.bestScore;\n            ret.bestScore = score;\n            ret.best = k;\n        } else if (score < ret.secondScore) {\n            ret.secondScore = score;\n        }\n    }\n\n    if (ret.secondScore > 1e299) ret.secondScore = ret.bestScore;\n    return ret;\n}\n\ndouble confidence_of(const DecodeResult& r) {\n    return (r.secondScore - r.bestScore) / (fabs(r.bestScore) + 1e-9);\n}\n\nbool same_param(const DecodeParam& a, const DecodeParam& b) {\n    auto eq = [&](double x, double y) { return fabs(x - y) <= 1e-12; };\n    return eq(a.m1, b.m1) && eq(a.m2, b.m2) && eq(a.mB, b.mB) && eq(a.mM, b.mM) &&\n           eq(a.a1, b.a1) && eq(a.a2, b.a2) && eq(a.a3, b.a3) && a.useSecond == b.useSecond;\n}\n\nint decode_with_guard(\n    const vector<int>& od, const vector<int>& on, const vector<int>& on2, const vector<int>& ob,\n    int uniq, int mObs, const ProtoBank& pb,\n    const DecodeParam& baseP, const DecodeParam& robustP,\n    double eps, bool allowFallback\n) {\n    DecodeResult rb = decode_with_param(od, on, on2, ob, uniq, mObs, pb, baseP, eps);\n\n    if (!allowFallback) return rb.best;\n    if (same_param(baseP, robustP)) return rb.best;\n\n    double rr = (double)uniq / max(1, pb.N);\n    double confB = confidence_of(rb);\n\n    bool needRob = false;\n    if (eps >= 0.30) {\n        needRob = true;\n    } else {\n        double uniqTh, confTh;\n        if (eps < 0.18) {\n            uniqTh = 0.20; confTh = 0.012;\n        } else {\n            uniqTh = 0.24; confTh = 0.009;\n        }\n        needRob = (rr < uniqTh || confB < confTh);\n    }\n\n    if (!needRob) return rb.best;\n\n    DecodeResult rrst = decode_with_param(od, on, on2, ob, uniq, mObs, pb, robustP, eps);\n    if (rrst.best == rb.best) return rb.best;\n\n    double confR = confidence_of(rrst);\n\n    if (eps >= 0.30) {\n        if (rrst.bestScore <= rb.bestScore * 1.06) return rrst.best;\n        if (confR >= confB * 1.10) return rrst.best;\n        return rb.best;\n    }\n\n    if (rr < 0.20) {\n        if (rrst.bestScore <= rb.bestScore * 1.02) return rrst.best;\n        if (confR >= confB * 1.05) return rrst.best;\n    } else {\n        if (rrst.bestScore <= rb.bestScore * 0.98) return rrst.best;\n        if (confR >= confB * 1.25) return rrst.best;\n    }\n\n    return rb.best;\n}\n\ndouble estimate_eval_score(int err, int T, int N) {\n    double q = (double)err / (double)T;\n    double st = sqrt(max(1e-12, q * (1.0 - q) / T));\n    double qu = min(1.0, q + 1.15 * st + 0.5 / T);\n    double survive = max(0.0, 1.0 - 0.1 * qu);\n    return pow(survive, 100.0) / (double)N;\n}\n\ndouble evaluate_codebook(\n    const Codebook& cb, const ProtoBank& pb,\n    const DecodeParam& baseP, const DecodeParam& robustP, bool allowFallback,\n    double eps, int T, RNG& rng\n) {\n    if (cb.distinct < pb.M) return -1e100;\n    if (T <= 0) return -1e100;\n\n    FeatureWork w(cb.N, cb.L);\n    vector<int> od(cb.N), on(cb.N), on2(cb.N), ob(pb.useBlock ? cb.FB : 0);\n\n    uint64_t flipThr = prob_to_u64(eps);\n    int err = 0;\n\n    for (int t = 0; t < T; t++) {\n        int s = rng.next_int(0, pb.M - 1);\n\n        int uniq = 0, mObs = 0;\n        sample_noisy_features(cb.graphs[s], cb, eps, flipThr, rng, w, od, on, on2, ob, uniq, mObs, pb.useBlock);\n\n        int pred = decode_with_guard(od, on, on2, ob, uniq, mObs, pb, baseP, robustP, eps, allowFallback);\n        if (pred != s) err++;\n    }\n\n    return estimate_eval_score(err, T, cb.N);\n}\n\nvector<int> choose_candidate_Ns(int M, double eps) {\n    // unlabeled graph counts A000088 (n=0..10)\n    static const vector<long long> unl = {\n        0LL, 1LL, 1LL, 2LL, 4LL, 11LL, 34LL, 156LL, 1044LL, 12346LL, 274668LL\n    };\n\n    int nlb = 4;\n    while (nlb + 1 < (int)unl.size() && unl[nlb] < M) nlb++;\n\n    int edgeMin = 4;\n    while (edgeMin * (edgeMin - 1) / 2 < M - 1) edgeMin++;\n\n    vector<int> Ns;\n    auto add = [&](int n) {\n        if (eps >= 0.12) n = max(n, edgeMin);\n        n = max(4, min(100, n));\n        if (find(Ns.begin(), Ns.end(), n) == Ns.end()) Ns.push_back(n);\n    };\n\n    if (eps < 0.05) {\n        add(nlb); add(nlb + 2); add(10); add(14); add(20); add(28);\n    } else if (eps < 0.12) {\n        add(max(nlb, 8)); add(14); add(22); add(32); add(44); add(58);\n    } else if (eps < 0.22) {\n        add(max(nlb, 10)); add(20); add(32); add(46); add(62); add(80);\n    } else if (eps < 0.30) {\n        add(max(nlb, 16)); add(36); add(52); add(68); add(84); add(100);\n    } else {\n        add(max(nlb, 24)); add(60); add(76); add(92); add(100);\n    }\n\n    sort(Ns.begin(), Ns.end());\n    Ns.erase(unique(Ns.begin(), Ns.end()), Ns.end());\n    return Ns;\n}\n\nDecodeParam default_param(double eps, bool useBlock) {\n    DecodeParam p;\n    if (eps < 0.08) {\n        p.m1 = 1.0; p.m2 = 0.7; p.mB = useBlock ? 0.10 : 0.0; p.mM = 0.25;\n        p.a1 = 0.70; p.a2 = 0.10; p.a3 = 0.20; p.useSecond = true;\n    } else if (eps < 0.20) {\n        p.m1 = 1.0; p.m2 = 0.4; p.mB = useBlock ? 0.50 : 0.0; p.mM = 0.65;\n        p.a1 = 0.65; p.a2 = 0.15; p.a3 = 0.20; p.useSecond = true;\n    } else if (eps < 0.30) {\n        p.m1 = 0.8; p.m2 = 0.15; p.mB = useBlock ? 0.75 : 0.0; p.mM = 1.10;\n        p.a1 = 0.62; p.a2 = 0.18; p.a3 = 0.20; p.useSecond = true;\n    } else {\n        p.m1 = 0.6; p.m2 = 0.0; p.mB = useBlock ? 0.20 : 0.0; p.mM = 1.70;\n        p.a1 = 0.70; p.a2 = 0.10; p.a3 = 0.20; p.useSecond = true;\n    }\n    p.name = \"default\";\n    return p;\n}\n\nDecodeParam degree_only_param() {\n    DecodeParam p;\n    p.m1 = 0.0; p.m2 = 0.0; p.mB = 0.0; p.mM = 1.8;\n    p.a1 = 1.0; p.a2 = 0.0; p.a3 = 0.0;\n    p.useSecond = false;\n    p.name = \"deg_only\";\n    return p;\n}\n\nDecodeParam block_heavy_param(bool useBlock) {\n    DecodeParam p;\n    p.m1 = 0.2; p.m2 = 0.0; p.mB = useBlock ? 1.2 : 0.0; p.mM = 0.8;\n    p.a1 = 0.60; p.a2 = 0.20; p.a3 = 0.20;\n    p.useSecond = true;\n    p.name = \"block_heavy\";\n    return p;\n}\n\nDecodeParam robust_param(double eps) {\n    DecodeParam p;\n    if (eps < 0.15) {\n        p.m1 = 0.35; p.m2 = 0.0; p.mB = 0.0; p.mM = 1.8;\n        p.a1 = 0.86; p.a2 = 0.0; p.a3 = 0.14;\n    } else if (eps < 0.30) {\n        p.m1 = 0.20; p.m2 = 0.0; p.mB = 0.0; p.mM = 2.2;\n        p.a1 = 0.90; p.a2 = 0.0; p.a3 = 0.10;\n    } else {\n        p.m1 = 0.10; p.m2 = 0.0; p.mB = 0.0; p.mM = 2.6;\n        p.a1 = 0.92; p.a2 = 0.0; p.a3 = 0.08;\n    }\n    p.useSecond = false;\n    p.name = \"robust\";\n    return p;\n}\n\nvector<DecodeParam> make_param_candidates(double eps, bool useBlock, const DecodeParam& initP) {\n    vector<DecodeParam> v;\n    auto add = [&](DecodeParam p, const string& nm) {\n        if (!useBlock) p.mB = 0.0;\n        p.name = nm;\n        for (auto& q : v) if (same_param(p, q)) return;\n        v.push_back(p);\n    };\n\n    DecodeParam def = default_param(eps, useBlock);\n    DecodeParam deg = degree_only_param();\n    DecodeParam blk = block_heavy_param(useBlock);\n    DecodeParam rob = robust_param(eps);\n\n    add(initP, \"init\");\n    add(def, \"default\");\n    add(deg, \"deg_only\");\n    add(rob, \"robust\");\n\n    DecodeParam rich = def;\n    rich.m2 *= 1.4;\n    rich.mB *= 0.8;\n    rich.mM *= 0.9;\n    add(rich, \"rich\");\n\n    DecodeParam lowhigh = def;\n    lowhigh.m2 *= 0.4;\n    lowhigh.mB *= 1.1;\n    lowhigh.m1 *= 0.9;\n    lowhigh.mM *= 1.2;\n    add(lowhigh, \"lowhigh\");\n\n    if (useBlock) add(blk, \"block_heavy\");\n    return v;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    if (!(cin >> M >> eps)) return 0;\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count();\n    };\n\n    uint64_t epsInt = (uint64_t)llround(eps * 100.0);\n    uint64_t baseSeed = 0x1234abcddcba4321ULL ^ (uint64_t)M * 10007ULL ^ epsInt * 1000003ULL;\n\n    vector<int> Ns = choose_candidate_Ns(M, eps);\n    if (eps > 0.22) reverse(Ns.begin(), Ns.end());\n\n    double bestEst = -1e100;\n    Codebook bestCb;\n    DecodeParam bestInitParam = default_param(eps, eps < 0.22);\n    bool haveBest = false;\n\n    const long long searchDeadline = 2500;\n\n    for (int ni = 0; ni < (int)Ns.size(); ni++) {\n        int N = Ns[ni];\n        int tries = (eps < 0.10 ? 1 : (eps < 0.25 ? 2 : 3));\n        if (M > 80) tries = min(4, tries + 1);\n\n        for (int att = 0; att < tries; att++) {\n            if (elapsed_ms() > searchDeadline) break;\n\n            int C = max(450, M * 10);\n            if (eps > 0.20) C += M * 3;\n            if (N <= 12) C += 240;\n            C += att * 70;\n            C = min(C, 1500);\n\n            RNG rngBuild(baseSeed + 1000003ULL * (uint64_t)N + 1009ULL * (uint64_t)att + 97ULL * (uint64_t)ni + 11ULL);\n            Codebook cb = build_codebook(N, M, eps, C, rngBuild);\n            if (cb.distinct < M) continue;\n\n            bool useBlockEval = (eps < 0.22);\n\n            int Se = (eps < 0.08 ? 3 : (eps < 0.20 ? 4 : 5));\n            if (M > 80) Se++;\n            if (eps > 0.30) Se++;\n            if (elapsed_ms() > 1800) Se = max(3, Se - 1);\n\n            RNG rngCal(baseSeed + 2000003ULL * (uint64_t)N + 1237ULL * (uint64_t)att + 17ULL);\n            ProtoBank pb = calibrate_prototypes(cb, eps, Se, useBlockEval, rngCal);\n\n            DecodeParam pDef = default_param(eps, useBlockEval);\n            DecodeParam pRob = robust_param(eps);\n            DecodeParam pBlk = block_heavy_param(useBlockEval);\n\n            int T = (eps < 0.08 ? 120 : (eps < 0.20 ? 160 : 200));\n            if (M > 80) T += 30;\n            if (elapsed_ms() > 2200) T = max(85, T - 55);\n\n            bool allowFb = (eps >= 0.12);\n\n            uint64_t evalSeed = baseSeed + 3000017ULL * (uint64_t)N + 2713ULL * (uint64_t)att + 233ULL * (uint64_t)ni;\n\n            RNG re0(evalSeed);\n            double est = evaluate_codebook(cb, pb, pDef, pRob, allowFb, eps, T, re0);\n            DecodeParam localBest = pDef;\n\n            if (eps >= 0.24 && elapsed_ms() < searchDeadline - 160) {\n                RNG re1(evalSeed + 911ULL);\n                double est1 = evaluate_codebook(cb, pb, pRob, pRob, false, eps, max(60, T / 2), re1);\n                if (est1 > est) {\n                    est = est1;\n                    localBest = pRob;\n                }\n            }\n\n            if (useBlockEval && eps >= 0.12 && eps <= 0.24 && elapsed_ms() < searchDeadline - 160) {\n                RNG re2(evalSeed + 1237ULL);\n                double est2 = evaluate_codebook(cb, pb, pBlk, pRob, allowFb, eps, max(60, T / 2), re2);\n                if (est2 > est) {\n                    est = est2;\n                    localBest = pBlk;\n                }\n            }\n\n            if (eps >= 0.25 && elapsed_ms() < searchDeadline - 120) {\n                RNG re3(evalSeed + 77777ULL);\n                double est3 = evaluate_codebook(cb, pb, localBest, pRob, allowFb, eps, max(50, T / 2), re3);\n                if (est > 0.0 && est3 > 0.0) est = sqrt(est * est3);\n                else est = min(est, est3);\n            }\n\n            if (est > bestEst) {\n                bestEst = est;\n                bestCb = std::move(cb);\n                bestInitParam = localBest;\n                haveBest = true;\n            }\n        }\n\n        if (elapsed_ms() > searchDeadline) break;\n    }\n\n    // force-check N=100 candidate for very high noise to reduce catastrophic failures\n    if (eps >= 0.30 && elapsed_ms() < 3300) {\n        int Nf = 100;\n        RNG rb(baseSeed + 0x9e3779b97f4a7c15ULL + 131ULL);\n        Codebook cbf = build_codebook(Nf, M, eps, max(900, M * 12), rb);\n        if (cbf.distinct >= M) {\n            bool useBlock = false;\n            int Se = (M > 80 ? 6 : 5);\n            RNG rc(baseSeed + 0xabcdef1234567890ULL + 17ULL);\n            ProtoBank pbf = calibrate_prototypes(cbf, eps, Se, useBlock, rc);\n\n            DecodeParam pDef = default_param(eps, useBlock);\n            DecodeParam pRob = robust_param(eps);\n\n            int T = 130;\n            RNG re(baseSeed + 0x3141592653589793ULL + 23ULL);\n            double estf = evaluate_codebook(cbf, pbf, pDef, pRob, true, eps, T, re);\n\n            if (bestCb.graphs.empty() || estf > bestEst * 0.99 || (bestCb.N < 80 && estf > bestEst * 0.95)) {\n                bestCb = std::move(cbf);\n                bestEst = estf;\n                bestInitParam = pDef;\n            }\n        }\n    }\n\n    if (!haveBest || bestCb.graphs.empty() || bestCb.distinct < M) {\n        vector<int> fallbackNs = {100, 90, 80, 70, 60, 50, 40, 30, 20, 12, 8};\n        Codebook bestTmp;\n        int bestDistinct = -1;\n        bool found = false;\n\n        for (int n : fallbackNs) {\n            if (found) break;\n            for (int rep = 0; rep < 2; rep++) {\n                RNG rb(baseSeed + 777ULL * (uint64_t)n + 99991ULL * (uint64_t)(rep + 1));\n                int C = max(800, M * 12);\n                C = min(C, 1500);\n                Codebook cb = build_codebook(n, M, eps, C, rb);\n\n                if (cb.distinct > bestDistinct) {\n                    bestDistinct = cb.distinct;\n                    bestTmp = cb;\n                }\n                if (cb.distinct >= M) {\n                    bestTmp = cb;\n                    found = true;\n                    break;\n                }\n            }\n        }\n\n        bestCb = bestTmp;\n        if (bestCb.graphs.empty()) {\n            RNG rb(baseSeed + 0x9e3779b97f4a7c15ULL);\n            bestCb = build_codebook(100, M, eps, max(1000, M * 12), rb);\n        }\n    }\n\n    bool useBlockFinal = (eps < 0.22);\n\n    int Sf;\n    if (eps < 0.05) Sf = 8;\n    else if (eps < 0.15) Sf = 12;\n    else if (eps < 0.25) Sf = 16;\n    else if (eps < 0.35) Sf = 20;\n    else Sf = 22;\n    if (M > 80) Sf += 2;\n\n    if (elapsed_ms() > 3200) Sf = max(8, Sf - 4);\n    if (elapsed_ms() > 3900) Sf = max(6, Sf / 2);\n\n    RNG rngFinal(baseSeed ^ 0x9e3779b97f4a7c15ULL);\n    ProtoBank pbFinal = calibrate_prototypes(bestCb, eps, Sf, useBlockFinal, rngFinal);\n\n    DecodeParam robustFinal = robust_param(eps);\n\n    auto pcands = make_param_candidates(eps, useBlockFinal, bestInitParam);\n    DecodeParam bestParam = pcands[0];\n    double bestPEst = -1e100;\n\n    if (elapsed_ms() < 3800) {\n        int Tt = (eps < 0.15 ? 50 : 70);\n        if (M > 80) Tt += 20;\n        if (elapsed_ms() > 3400) Tt = max(40, Tt - 20);\n\n        bool allowFb = (eps >= 0.12);\n\n        for (int i = 0; i < (int)pcands.size(); i++) {\n            if (elapsed_ms() > 4450) break;\n            RNG rt1(baseSeed + 0x55555555ULL);\n            double est1 = evaluate_codebook(bestCb, pbFinal, pcands[i], robustFinal, allowFb, eps, Tt, rt1);\n\n            double est = est1;\n            if (eps >= 0.25 && elapsed_ms() < 4300) {\n                RNG rt2(baseSeed + 0x77777777ULL);\n                double est2 = evaluate_codebook(bestCb, pbFinal, pcands[i], robustFinal, allowFb, eps, max(40, Tt / 2), rt2);\n                if (est1 > 0.0 && est2 > 0.0) est = sqrt(est1 * est2);\n                else est = min(est1, est2);\n            }\n\n            if (est > bestPEst) {\n                bestPEst = est;\n                bestParam = pcands[i];\n            }\n        }\n    }\n\n    // output codebook\n    cout << bestCb.N << '\\n';\n    for (int k = 0; k < M; k++) {\n        string s(bestCb.L, '0');\n        for (int e = 0; e < bestCb.L; e++) if (bestCb.graphs[k].bits[e]) s[e] = '1';\n        cout << s << '\\n';\n    }\n    cout.flush();\n\n    // exact shortcut for eps=0 and unique signatures\n    bool exactMode = (eps <= 1e-12);\n    unordered_map<uint64_t, int> exactMap;\n    if (exactMode) {\n        exactMap.reserve((size_t)M * 2);\n        for (int k = 0; k < M; k++) {\n            uint64_t h = hash_sorted3(bestCb.graphs[k].deg_sorted, bestCb.graphs[k].nd_sorted, bestCb.graphs[k].nd2_sorted);\n            auto it = exactMap.find(h);\n            if (it == exactMap.end()) exactMap[h] = k;\n            else it->second = -1;\n        }\n    }\n\n    FeatureWork qwork(bestCb.N, bestCb.L);\n    vector<int> od(bestCb.N), on(bestCb.N), on2(bestCb.N), ob(useBlockFinal ? bestCb.FB : 0);\n\n    bool allowFallbackOnline = (eps >= 0.12) && !same_param(bestParam, robustFinal);\n\n    for (int q = 0; q < 100; q++) {\n        string H;\n        if (!(cin >> H)) return 0;\n\n        int uniq = 0, mObs = 0;\n        extract_features_from_string(H, bestCb, qwork, od, on, on2, ob, uniq, mObs, useBlockFinal);\n\n        int ans = 0;\n        if (exactMode) {\n            uint64_t h = hash_sorted3(od, on, on2);\n            auto it = exactMap.find(h);\n            if (it != exactMap.end() && it->second >= 0) ans = it->second;\n            else ans = decode_with_guard(od, on, on2, ob, uniq, mObs, pbFinal, bestParam, robustFinal, eps, allowFallbackOnline);\n        } else {\n            ans = decode_with_guard(od, on, on2, ob, uniq, mObs, pbFinal, bestParam, robustFinal, eps, allowFallbackOnline);\n        }\n\n        if (ans < 0) ans = 0;\n        if (ans >= M) ans = M - 1;\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;\nstatic constexpr int UNREACH = 1'000'000'000;\nstatic constexpr ll DISCONNECT_UNIT = 100'000'000LL;\n\nstruct Edge {\n    int u, v, w;\n    int cell = 0;\n    double imp = 0.0;\n};\n\nint N, M, D, K;\nint GRID = 10;\n\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj; // (to, edge id)\nvector<int> X, Y, degv;\n\nmt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count());\n\nvector<int> samples;\nint S = 0;\nvector<vector<int>> baseDist;\nvector<int> tmpDist;\n\n// current solution state\nvector<int> dayOf;               // edge -> day [0..D-1]\nvector<int> cntDay;              // day -> count\nvector<vector<int>> incCnt;      // vertex, day -> #incident edges repaired that day\nvector<vector<int>> dayEdges;    // day -> edge list\nvector<int> posInDay;            // edge -> position in dayEdges[dayOf[edge]]\nvector<ll> dayScore;             // approximate score per day\n\nvector<int> seen;\nint seenToken = 1;\n\ninline int rnd_int(int n) {\n    return (int)(rng() % (uint32_t)n);\n}\ninline double rnd01() {\n    return (rng() + 0.5) * (1.0 / 4294967296.0);\n}\n\nvoid dijkstra_full_parent(int src, vector<int>& dist, vector<int>& parent) {\n    fill(dist.begin(), dist.end(), UNREACH);\n    fill(parent.begin(), parent.end(), -1);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                parent[to] = eid;\n                pq.push({nd, to});\n            } else if (nd == dist[to] && parent[to] != -1) {\n                // deterministic tie-break\n                if (eid < parent[to]) parent[to] = eid;\n            }\n        }\n    }\n}\n\nvoid dijkstra_ban_day(int src, int banDay, vector<int>& dist) {\n    fill(dist.begin(), dist.end(), UNREACH);\n\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\n    while (!pq.empty()) {\n        auto [d, v] = pq.top();\n        pq.pop();\n        if (d != dist[v]) continue;\n\n        for (auto [to, eid] : adj[v]) {\n            if (dayOf[eid] == banDay) continue;\n            int nd = d + edges[eid].w;\n            if (nd < dist[to]) {\n                dist[to] = nd;\n                pq.push({nd, to});\n            }\n        }\n    }\n}\n\n// ordered pairs across different connected components after removing banDay edges.\n// 0 means connected.\nll disconnected_cross_pairs(int banDay) {\n    static vector<int> q;\n    if ((int)q.size() < N) q.resize(N);\n\n    ll sameOrdered = 0;\n    for (int st = 0; st < N; st++) {\n        if (seen[st] == seenToken) continue;\n        int head = 0, tail = 0;\n        q[tail++] = st;\n        seen[st] = seenToken;\n        int sz = 0;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (auto [to, eid] : adj[v]) {\n                if (dayOf[eid] == banDay) continue;\n                if (seen[to] == seenToken) continue;\n                seen[to] = seenToken;\n                q[tail++] = to;\n            }\n        }\n        sameOrdered += 1LL * sz * (sz - 1);\n    }\n\n    seenToken++;\n    if (seenToken == INT_MAX) {\n        fill(seen.begin(), seen.end(), 0);\n        seenToken = 1;\n    }\n\n    ll totalOrdered = 1LL * N * (N - 1);\n    return totalOrdered - sameOrdered;\n}\n\nll compute_day_score(int day) {\n    // Strong connectivity penalty to avoid hidden catastrophic solutions.\n    ll crossPairs = disconnected_cross_pairs(day);\n    if (crossPairs > 0) {\n        return crossPairs * DISCONNECT_UNIT;\n    }\n\n    ll sum = 0;\n    for (int si = 0; si < S; si++) {\n        dijkstra_ban_day(samples[si], day, tmpDist);\n        const auto& b = baseDist[si];\n        for (int v = 0; v < N; v++) {\n            sum += (ll)tmpDist[v] - b[v];\n        }\n    }\n    return sum;\n}\n\nll evaluate_total(vector<ll>& outDayScore) {\n    outDayScore.assign(D, 0);\n    ll tot = 0;\n    for (int d = 0; d < D; d++) {\n        outDayScore[d] = compute_day_score(d);\n        tot += outDayScore[d];\n    }\n    return tot;\n}\n\nvector<int> select_samples(int cnt) {\n    cnt = min(cnt, N);\n    vector<int> res;\n    vector<double> minD2(N, 1e100);\n    vector<char> used(N, false);\n\n    int first = 0;\n    for (int i = 1; i < N; i++) {\n        if (degv[i] > degv[first]) first = i;\n    }\n\n    for (int it = 0; it < cnt; it++) {\n        int cur = -1;\n        if (it == 0) {\n            cur = first;\n        } else {\n            double best = -1.0;\n            for (int v = 0; v < N; v++) {\n                if (used[v]) continue;\n                if (minD2[v] > best) {\n                    best = minD2[v];\n                    cur = v;\n                }\n            }\n        }\n        used[cur] = true;\n        res.push_back(cur);\n\n        for (int v = 0; v < N; v++) {\n            if (used[v]) continue;\n            double dx = (double)X[v] - X[cur];\n            double dy = (double)Y[v] - Y[cur];\n            double d2 = dx * dx + dy * dy;\n            if (d2 < minD2[v]) minD2[v] = d2;\n        }\n    }\n\n    return res;\n}\n\nvector<int> build_initial_schedule(double alpha, double beta, double gamma) {\n    vector<int> assign(M, -1);\n    vector<int> cnt(D, 0);\n    vector<vector<int>> inc(N, vector<int>(D, 0));\n    int C = GRID * GRID;\n    vector<vector<int>> cellCnt(C, vector<int>(D, 0));\n\n    vector<int> order(M);\n    iota(order.begin(), order.end(), 0);\n\n    vector<double> key(M);\n    for (int e = 0; e < M; e++) {\n        key[e] = edges[e].imp + (double)(rng() & 2047) * 1e-6;\n    }\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (key[a] != key[b]) return key[a] > key[b];\n        return a < b;\n    });\n\n    double maxImp = 1e-9;\n    for (int e = 0; e < M; e++) maxImp = max(maxImp, edges[e].imp);\n\n    for (int eid : order) {\n        const Edge& E = edges[eid];\n        int u = E.u, v = E.v, c = E.cell;\n        double impf = 1.0 + E.imp / maxImp;\n\n        int bestDay = -1;\n        double bestP = 1e100;\n\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] >= K) continue;\n            if (inc[u][d] >= degv[u] - 1) continue;\n            if (inc[v][d] >= degv[v] - 1) continue;\n\n            double p = alpha * cnt[d]\n                     + beta * impf * (inc[u][d] + inc[v][d])\n                     + gamma * cellCnt[c][d];\n            if (p < bestP) {\n                bestP = p;\n                bestDay = d;\n            }\n        }\n\n        // If hard constraints block all days, relax slightly with heavy penalty.\n        if (bestDay == -1) {\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] >= K) continue;\n                double viol = 0.0;\n                if (inc[u][d] >= degv[u] - 1) viol += 1000.0;\n                if (inc[v][d] >= degv[v] - 1) viol += 1000.0;\n                double p = alpha * cnt[d]\n                         + beta * impf * (inc[u][d] + inc[v][d])\n                         + gamma * cellCnt[c][d]\n                         + viol;\n                if (p < bestP) {\n                    bestP = p;\n                    bestDay = d;\n                }\n            }\n        }\n\n        if (bestDay == -1) {\n            // very defensive fallback\n            for (int d = 0; d < D; d++) {\n                if (cnt[d] < K) {\n                    bestDay = d;\n                    break;\n                }\n            }\n            if (bestDay == -1) bestDay = 0;\n        }\n\n        assign[eid] = bestDay;\n        cnt[bestDay]++;\n        inc[u][bestDay]++;\n        inc[v][bestDay]++;\n        cellCnt[c][bestDay]++;\n    }\n\n    return assign;\n}\n\nvoid build_state_from_assignment() {\n    cntDay.assign(D, 0);\n    incCnt.assign(N, vector<int>(D, 0));\n    dayEdges.assign(D, vector<int>());\n    posInDay.assign(M, -1);\n\n    for (int e = 0; e < M; e++) {\n        int d = dayOf[e];\n        cntDay[d]++;\n        int u = edges[e].u, v = edges[e].v;\n        incCnt[u][d]++;\n        incCnt[v][d]++;\n        posInDay[e] = (int)dayEdges[d].size();\n        dayEdges[d].push_back(e);\n    }\n}\n\ninline void day_remove_edge(int e, int d) {\n    int p = posInDay[e];\n    int last = dayEdges[d].back();\n    dayEdges[d][p] = last;\n    posInDay[last] = p;\n    dayEdges[d].pop_back();\n}\n\ninline void day_add_edge(int e, int d) {\n    posInDay[e] = (int)dayEdges[d].size();\n    dayEdges[d].push_back(e);\n}\n\nvoid apply_move(int e, int from, int to) {\n    day_remove_edge(e, from);\n    day_add_edge(e, to);\n\n    dayOf[e] = to;\n    cntDay[from]--;\n    cntDay[to]++;\n\n    int u = edges[e].u, v = edges[e].v;\n    incCnt[u][from]--;\n    incCnt[v][from]--;\n    incCnt[u][to]++;\n    incCnt[v][to]++;\n}\n\nvoid apply_swap(int e, int f, int d1, int d2) {\n    // e: d1 -> d2, f: d2 -> d1\n    int pe = posInDay[e];\n    int pf = posInDay[f];\n\n    dayEdges[d1][pe] = f;\n    posInDay[f] = pe;\n    dayEdges[d2][pf] = e;\n    posInDay[e] = pf;\n\n    dayOf[e] = d2;\n    dayOf[f] = d1;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    incCnt[eu][d1]--;\n    incCnt[ev][d1]--;\n    incCnt[eu][d2]++;\n    incCnt[ev][d2]++;\n\n    incCnt[fu][d2]--;\n    incCnt[fv][d2]--;\n    incCnt[fu][d1]++;\n    incCnt[fv][d1]++;\n}\n\nbool can_move_edge(int e, int to) {\n    int from = dayOf[e];\n    if (from == to) return false;\n    if (cntDay[to] >= K) return false;\n    int u = edges[e].u, v = edges[e].v;\n    if (incCnt[u][to] + 1 > degv[u] - 1) return false;\n    if (incCnt[v][to] + 1 > degv[v] - 1) return false;\n    return true;\n}\n\nbool can_swap_edges(int e, int f) {\n    int d1 = dayOf[e];\n    int d2 = dayOf[f];\n    if (d1 == d2) return false;\n\n    int eu = edges[e].u, ev = edges[e].v;\n    int fu = edges[f].u, fv = edges[f].v;\n\n    int vv[4] = {eu, ev, fu, fv};\n    sort(vv, vv + 4);\n    int m = (int)(unique(vv, vv + 4) - vv);\n\n    for (int i = 0; i < m; i++) {\n        int x = vv[i];\n        int nd1 = incCnt[x][d1] - (eu == x) - (ev == x) + (fu == x) + (fv == x);\n        int nd2 = incCnt[x][d2] - (fu == x) - (fv == x) + (eu == x) + (ev == x);\n        if (nd1 > degv[x] - 1) return false;\n        if (nd2 > degv[x] - 1) return false;\n    }\n    return true;\n}\n\nint day_with_max_score() {\n    int id = 0;\n    for (int d = 1; d < D; d++) {\n        if (dayScore[d] > dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_move(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (cntDay[d] >= K) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint day_with_min_score_swap(int avoid) {\n    int id = -1;\n    for (int d = 0; d < D; d++) {\n        if (d == avoid) continue;\n        if (dayEdges[d].empty()) continue;\n        if (id == -1 || dayScore[d] < dayScore[id]) id = d;\n    }\n    return id;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    cin >> N >> M >> D >> K;\n    edges.resize(M);\n    adj.assign(N, {});\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        adj[u].push_back({v, i});\n        adj[v].push_back({u, i});\n    }\n\n    X.resize(N);\n    Y.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n    }\n\n    degv.assign(N, 0);\n    for (int v = 0; v < N; v++) degv[v] = (int)adj[v].size();\n\n    // edge cell id\n    for (int e = 0; e < M; e++) {\n        int mx = X[edges[e].u] + X[edges[e].v]; // [0,2000]\n        int my = Y[edges[e].u] + Y[edges[e].v];\n        int gx = min(GRID - 1, mx * GRID / 2001);\n        int gy = min(GRID - 1, my * GRID / 2001);\n        edges[e].cell = gx * GRID + gy;\n    }\n\n    int sampleTarget = 14;\n    if (N > 850 || M > 2500) sampleTarget = 12;\n    S = min(N, sampleTarget);\n\n    samples = select_samples(S);\n\n    baseDist.assign(S, vector<int>(N, UNREACH));\n    vector<double> imp(M, 0.0);\n\n    vector<int> dist(N), parent(N);\n    for (int si = 0; si < S; si++) {\n        int src = samples[si];\n        dijkstra_full_parent(src, dist, parent);\n        baseDist[si] = dist;\n        for (int v = 0; v < N; v++) {\n            if (v == src) continue;\n            int pe = parent[v];\n            if (pe >= 0) imp[pe] += 1.0;\n        }\n    }\n\n    for (int e = 0; e < M; e++) {\n        imp[e] += 1000.0 / edges[e].w;\n        imp[e] += 0.1 * (1.0 / degv[edges[e].u] + 1.0 / degv[edges[e].v]);\n        edges[e].imp = imp[e];\n    }\n\n    dayOf.assign(M, 0);\n    tmpDist.assign(N, UNREACH);\n    seen.assign(N, 0);\n    seenToken = 1;\n\n    vector<array<double,3>> params = {\n        {1.0, 4.0, 1.8},\n        {0.8, 5.0, 0.7},\n        {1.2, 3.2, 2.6}\n    };\n\n    vector<int> bestAssignInit;\n    vector<ll> bestDayScoreInit;\n    ll bestTotInit = (1LL << 62);\n\n    for (auto p : params) {\n        auto initAssign = build_initial_schedule(p[0], p[1], p[2]);\n        dayOf = initAssign;\n        vector<ll> ds;\n        ll tot = evaluate_total(ds);\n        if (tot < bestTotInit) {\n            bestTotInit = tot;\n            bestAssignInit = move(initAssign);\n            bestDayScoreInit = move(ds);\n        }\n    }\n\n    dayOf = bestAssignInit;\n    dayScore = bestDayScoreInit;\n    ll currentTotal = bestTotInit;\n\n    build_state_from_assignment();\n\n    vector<int> bestAssign = dayOf;\n    ll bestTotal = currentTotal;\n\n    const double TIME_LIMIT = 5.60;\n    const double T0 = 5e6;\n    const double T1 = 1e3;\n    const double logT0 = log(T0);\n    const double logT1 = log(T1);\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 7) == 0) {\n            double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n            if (elapsed >= TIME_LIMIT) break;\n        }\n        iter++;\n\n        bool generated = false;\n        bool isMove = false;\n        int e = -1, f = -1, toDay = -1;\n\n        for (int tr = 0; tr < 25 && !generated; tr++) {\n            int mode = rnd_int(100);\n\n            if (mode < 35) {\n                // targeted move: bad day -> good day\n                int d1 = day_with_max_score();\n                if (dayEdges[d1].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                int d2 = day_with_min_score_move(d1);\n                if (d2 < 0) continue;\n                if (!can_move_edge(e, d2)) continue;\n                isMove = true;\n                toDay = d2;\n                generated = true;\n\n            } else if (mode < 65) {\n                // targeted swap: bad day <-> good day\n                int d1 = day_with_max_score();\n                int d2 = day_with_min_score_swap(d1);\n                if (d2 < 0) continue;\n                if (dayEdges[d1].empty() || dayEdges[d2].empty()) continue;\n                e = dayEdges[d1][rnd_int((int)dayEdges[d1].size())];\n                f = dayEdges[d2][rnd_int((int)dayEdges[d2].size())];\n                if (!can_swap_edges(e, f)) continue;\n                isMove = false;\n                generated = true;\n\n            } else {\n                // random\n                e = rnd_int(M);\n                if (rnd_int(2) == 0) {\n                    int d2 = rnd_int(D);\n                    if (!can_move_edge(e, d2)) continue;\n                    isMove = true;\n                    toDay = d2;\n                    generated = true;\n                } else {\n                    f = rnd_int(M);\n                    if (e == f) continue;\n                    if (!can_swap_edges(e, f)) continue;\n                    isMove = false;\n                    generated = true;\n                }\n            }\n        }\n\n        if (!generated) continue;\n\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        double progress = min(1.0, elapsed / TIME_LIMIT);\n        double temp = exp(logT0 + (logT1 - logT0) * progress);\n\n        if (isMove) {\n            int from = dayOf[e];\n            int to = toDay;\n\n            ll oldA = dayScore[from];\n            ll oldB = dayScore[to];\n\n            apply_move(e, from, to);\n\n            ll newA = compute_day_score(from);\n            ll newB = compute_day_score(to);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[from] = newA;\n                dayScore[to] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_move(e, to, from); // revert\n            }\n\n        } else {\n            int d1 = dayOf[e];\n            int d2 = dayOf[f];\n\n            ll oldA = dayScore[d1];\n            ll oldB = dayScore[d2];\n\n            apply_swap(e, f, d1, d2);\n\n            ll newA = compute_day_score(d1);\n            ll newB = compute_day_score(d2);\n            ll delta = (newA - oldA) + (newB - oldB);\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double x = -(double)delta / temp;\n                if (x > -60.0 && exp(x) > rnd01()) accept = true;\n            }\n\n            if (accept) {\n                dayScore[d1] = newA;\n                dayScore[d2] = newB;\n                currentTotal += delta;\n\n                if (currentTotal < bestTotal) {\n                    bestTotal = currentTotal;\n                    bestAssign = dayOf;\n                }\n            } else {\n                apply_swap(e, f, d2, d1); // revert\n            }\n        }\n    }\n\n    dayOf = bestAssign;\n\n    // defensive validity check\n    bool ok = true;\n    vector<int> checkCnt(D, 0);\n    for (int e = 0; e < M; e++) {\n        if (dayOf[e] < 0 || dayOf[e] >= D) ok = false;\n        else checkCnt[dayOf[e]]++;\n    }\n    for (int d = 0; d < D; d++) if (checkCnt[d] > K) ok = false;\n\n    if (!ok) {\n        // guaranteed feasible fallback\n        for (int e = 0; e < M; e++) dayOf[e] = e % D;\n    }\n\n    for (int e = 0; e < M; e++) {\n        if (e) cout << ' ';\n        cout << (dayOf[e] + 1);\n    }\n    cout << '\\n';\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seg { int s, stride; };\n\nstruct LayerData {\n    vector<int> X, Y;\n    vector<int> allowed; // x*D+y\n    int base = 0;\n    int cap = 0;\n};\n\nstruct Occupancy {\n    vector<char> occ;\n    int vol = 0;\n    int zadj = 0;\n    int adj6 = 0;\n    array<int, 14> zcnt{};\n    array<int, 14> xcnt{};\n    array<int, 14> ycnt{};\n};\n\nstruct Solution {\n    long double score = 1e100L;\n    int n = 0;\n    vector<int> b1, b2;\n};\n\nstruct Pt { int x, y, z; };\nstruct Rot { int p[3], s[3]; };\n\nstruct ShapeGroup {\n    int k = 0;\n    bool isLine = false;\n    vector<array<int, 8>> plc; // first k entries used\n};\n\nint D, N;\nint SX, SY, SZ;\n\narray<vector<string>, 2> F, Rv;\narray<vector<LayerData>, 2> LAY;\narray<int, 2> VminObj, VmaxObj;\narray<vector<int>, 2> ColLife;\n\nvector<Rot> ROTS;\nvector<vector<Seg>> allSegs; // all lines length L>=3\nShapeGroup cubeGroup;\nvector<ShapeGroup> groups3, groups4;\n\nvector<vector<int>> neighbors;\nvector<int> parityCell;\nvector<unsigned char> CX, CY, CZ;\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline int clampi(int v, int lo, int hi) {\n    return v < lo ? lo : (v > hi ? hi : v);\n}\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++) if (p[i] > p[j]) inv++;\n    return (inv % 2 == 0 ? 1 : -1);\n}\n\nvoid build_rotations() {\n    ROTS.clear();\n    vector<array<int,3>> perms = {\n        {0,1,2}, {0,2,1}, {1,0,2}, {1,2,0}, {2,0,1}, {2,1,0}\n    };\n    for (auto perm : perms) {\n        int pp = perm_parity(perm);\n        for (int sx : {-1, 1}) for (int sy : {-1, 1}) for (int sz : {-1, 1}) {\n            int det = pp * sx * sy * sz;\n            if (det != 1) continue;\n            Rot r;\n            r.p[0] = perm[0]; r.p[1] = perm[1]; r.p[2] = perm[2];\n            r.s[0] = sx;      r.s[1] = sy;      r.s[2] = sz;\n            ROTS.push_back(r);\n        }\n    }\n}\n\nPt rotate_pt(const Pt& a, const Rot& r) {\n    int v[3] = {a.x, a.y, a.z};\n    return Pt{r.s[0] * v[r.p[0]], r.s[1] * v[r.p[1]], r.s[2] * v[r.p[2]]};\n}\n\nvector<Pt> normalize_pts(vector<Pt> v) {\n    int mnx = 1e9, mny = 1e9, mnz = 1e9;\n    for (auto& p : v) {\n        mnx = min(mnx, p.x);\n        mny = min(mny, p.y);\n        mnz = min(mnz, p.z);\n    }\n    for (auto& p : v) {\n        p.x -= mnx;\n        p.y -= mny;\n        p.z -= mnz;\n    }\n    sort(v.begin(), v.end(), [](const Pt& a, const Pt& b) {\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    return v;\n}\n\nstring encode_pts_text(const vector<Pt>& v) {\n    string s;\n    s.reserve(v.size() * 12);\n    for (auto& p : v) {\n        s += to_string(p.x); s.push_back(',');\n        s += to_string(p.y); s.push_back(',');\n        s += to_string(p.z); s.push_back(';');\n    }\n    return s;\n}\n\npair<string, vector<Pt>> canonical_repr(const vector<Pt>& cells) {\n    string bestKey;\n    vector<Pt> best;\n    bool first = true;\n    for (auto& r : ROTS) {\n        vector<Pt> t;\n        t.reserve(cells.size());\n        for (auto& p : cells) t.push_back(rotate_pt(p, r));\n        t = normalize_pts(move(t));\n        string key = encode_pts_text(t);\n        if (first || key < bestKey) {\n            first = false;\n            bestKey = move(key);\n            best = move(t);\n        }\n    }\n    return {bestKey, best};\n}\n\nvector<vector<Pt>> enumerate_free_shapes(int K) {\n    static const int dx[6] = {1,-1,0,0,0,0};\n    static const int dy[6] = {0,0,1,-1,0,0};\n    static const int dz[6] = {0,0,0,0,1,-1};\n\n    vector<vector<vector<Pt>>> by(K + 1);\n    by[1].push_back(vector<Pt>{{0,0,0}});\n\n    for (int s = 1; s < K; s++) {\n        unordered_map<string, vector<Pt>> mp;\n        mp.reserve(1024);\n\n        for (const auto& sh : by[s]) {\n            unordered_set<long long> have;\n            have.reserve(sh.size() * 5 + 16);\n\n            for (auto& p : sh) {\n                long long code = ((long long)(p.x + 32) << 40)\n                               ^ ((long long)(p.y + 32) << 20)\n                               ^ (long long)(p.z + 32);\n                have.insert(code);\n            }\n\n            set<tuple<int,int,int>> cand;\n            for (auto& p : sh) {\n                for (int d = 0; d < 6; d++) {\n                    int nx = p.x + dx[d], ny = p.y + dy[d], nz = p.z + dz[d];\n                    long long code = ((long long)(nx + 32) << 40)\n                                   ^ ((long long)(ny + 32) << 20)\n                                   ^ (long long)(nz + 32);\n                    if (!have.count(code)) cand.emplace(nx, ny, nz);\n                }\n            }\n\n            for (auto [nx, ny, nz] : cand) {\n                vector<Pt> ns = sh;\n                ns.push_back({nx, ny, nz});\n                auto [key, canon] = canonical_repr(ns);\n                if (mp.find(key) == mp.end()) mp.emplace(key, move(canon));\n            }\n        }\n\n        by[s + 1].reserve(mp.size());\n        for (auto& kv : mp) by[s + 1].push_back(move(kv.second));\n    }\n\n    return by[K];\n}\n\nbool consecutive_unique(vector<int> v) {\n    sort(v.begin(), v.end());\n    for (int i = 1; i < (int)v.size(); i++) if (v[i] == v[i - 1]) return false;\n    return v.back() - v.front() + 1 == (int)v.size();\n}\n\nbool is_line_shape(const vector<Pt>& sh) {\n    int k = (int)sh.size();\n    if (k <= 1) return true;\n\n    bool lineX = true, lineY = true, lineZ = true;\n    for (auto& p : sh) {\n        if (p.y != sh[0].y || p.z != sh[0].z) lineX = false;\n        if (p.x != sh[0].x || p.z != sh[0].z) lineY = false;\n        if (p.x != sh[0].x || p.y != sh[0].y) lineZ = false;\n    }\n\n    if (lineX) {\n        vector<int> xs; xs.reserve(k);\n        for (auto& p : sh) xs.push_back(p.x);\n        if (consecutive_unique(xs)) return true;\n    }\n    if (lineY) {\n        vector<int> ys; ys.reserve(k);\n        for (auto& p : sh) ys.push_back(p.y);\n        if (consecutive_unique(ys)) return true;\n    }\n    if (lineZ) {\n        vector<int> zs; zs.reserve(k);\n        for (auto& p : sh) zs.push_back(p.z);\n        if (consecutive_unique(zs)) return true;\n    }\n    return false;\n}\n\nvector<ShapeGroup> build_groups_from_shapes(const vector<vector<Pt>>& shapes, int k) {\n    vector<ShapeGroup> gs;\n\n    for (auto& sh : shapes) {\n        unordered_map<string, vector<Pt>> oriMap;\n        oriMap.reserve(64);\n\n        for (auto& r : ROTS) {\n            vector<Pt> t;\n            t.reserve(k);\n            for (auto& p : sh) t.push_back(rotate_pt(p, r));\n            t = normalize_pts(move(t));\n            string key = encode_pts_text(t);\n            if (oriMap.find(key) == oriMap.end()) oriMap.emplace(key, move(t));\n        }\n\n        ShapeGroup g;\n        g.k = k;\n        g.isLine = is_line_shape(sh);\n\n        for (auto& kv : oriMap) {\n            const auto& o = kv.second;\n            int mx = 0, my = 0, mz = 0;\n            for (auto& p : o) {\n                mx = max(mx, p.x);\n                my = max(my, p.y);\n                mz = max(mz, p.z);\n            }\n\n            for (int ox = 0; ox + mx < D; ox++) {\n                for (int oy = 0; oy + my < D; oy++) {\n                    for (int oz = 0; oz + mz < D; oz++) {\n                        array<int,8> arr{};\n                        for (int i = 0; i < k; i++) {\n                            arr[i] = idx3(ox + o[i].x, oy + o[i].y, oz + o[i].z);\n                        }\n                        g.plc.push_back(arr);\n                    }\n                }\n            }\n        }\n\n        if (!g.plc.empty()) gs.push_back(move(g));\n    }\n\n    return gs;\n}\n\nvoid precompute() {\n    SX = D * D;\n    SY = D;\n    SZ = 1;\n    N = D * D * D;\n\n    CX.assign(N, 0);\n    CY.assign(N, 0);\n    CZ.assign(N, 0);\n\n    for (int obj = 0; obj < 2; obj++) {\n        LAY[obj].assign(D, LayerData{});\n        int vmin = 0, vmax = 0;\n\n        for (int z = 0; z < D; z++) {\n            LayerData ld;\n            for (int x = 0; x < D; x++) if (F[obj][z][x] == '1') ld.X.push_back(x);\n            for (int y = 0; y < D; y++) if (Rv[obj][z][y] == '1') ld.Y.push_back(y);\n\n            int a = (int)ld.X.size();\n            int b = (int)ld.Y.size();\n            ld.base = max(a, b);\n            ld.cap = a * b - ld.base;\n            ld.allowed.reserve(a * b);\n            for (int x : ld.X) for (int y : ld.Y) ld.allowed.push_back(x * D + y);\n\n            vmin += ld.base;\n            vmax += a * b;\n            LAY[obj][z] = move(ld);\n        }\n\n        VminObj[obj] = vmin;\n        VmaxObj[obj] = vmax;\n\n        ColLife[obj].assign(D * D, 0);\n        for (int z = 0; z < D; z++) {\n            for (int idxy : LAY[obj][z].allowed) ColLife[obj][idxy]++;\n        }\n    }\n\n    parityCell.assign(N, 0);\n    neighbors.assign(N, {});\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        CX[id] = (unsigned char)x;\n        CY[id] = (unsigned char)y;\n        CZ[id] = (unsigned char)z;\n\n        parityCell[id] = (x + y + z) & 1;\n        auto& nb = neighbors[id];\n        if (x > 0) nb.push_back(id - SX);\n        if (x + 1 < D) nb.push_back(id + SX);\n        if (y > 0) nb.push_back(id - SY);\n        if (y + 1 < D) nb.push_back(id + SY);\n        if (z > 0) nb.push_back(id - SZ);\n        if (z + 1 < D) nb.push_back(id + SZ);\n    }\n\n    allSegs.assign(D + 1, {});\n    for (int L = 3; L <= D; L++) {\n        auto& v = allSegs[L];\n        v.reserve(3 * (D - L + 1) * D * D);\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int s = idx3(x, y, z);\n            if (x + L <= D) v.push_back({s, SX});\n            if (y + L <= D) v.push_back({s, SY});\n            if (z + L <= D) v.push_back({s, SZ});\n        }\n    }\n\n    cubeGroup = ShapeGroup{};\n    cubeGroup.k = 8;\n    cubeGroup.isLine = false;\n    for (int x = 0; x + 1 < D; x++) for (int y = 0; y + 1 < D; y++) for (int z = 0; z + 1 < D; z++) {\n        array<int,8> c = {\n            idx3(x, y, z), idx3(x + 1, y, z), idx3(x, y + 1, z), idx3(x + 1, y + 1, z),\n            idx3(x, y, z + 1), idx3(x + 1, y, z + 1), idx3(x, y + 1, z + 1), idx3(x + 1, y + 1, z + 1)\n        };\n        cubeGroup.plc.push_back(c);\n    }\n\n    build_rotations();\n    auto sh3 = enumerate_free_shapes(3);\n    auto sh4 = enumerate_free_shapes(4);\n    groups3 = build_groups_from_shapes(sh3, 3);\n    groups4 = build_groups_from_shapes(sh4, 4);\n}\n\nvector<int> allocate_add(int obj, int target, int mode, mt19937_64& rng) {\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    target = max(lo, min(hi, target));\n\n    int need = target - lo;\n    vector<int> add(D, 0);\n    if (need <= 0) return add;\n\n    int totalCap = hi - lo;\n    if (totalCap <= 0) return add;\n\n    if (mode == 1) {\n        vector<int> slots;\n        slots.reserve(totalCap);\n        for (int z = 0; z < D; z++) {\n            int c = LAY[obj][z].cap;\n            for (int t = 0; t < c; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < need; i++) add[slots[i]]++;\n        return add;\n    }\n\n    vector<long double> frac(D, -1.0L);\n    int used = 0;\n    for (int z = 0; z < D; z++) {\n        int cap = LAY[obj][z].cap;\n        if (!cap) continue;\n        long double ex = (long double)need * (long double)cap / (long double)totalCap;\n        int a = (int)floor(ex);\n        a = min(a, cap);\n        add[z] = a;\n        used += a;\n        frac[z] = ex - a + (long double)(rng() % 1000) * 1e-12L;\n    }\n\n    int rem = need - used;\n    vector<int> ord(D);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int p, int q) { return frac[p] > frac[q]; });\n\n    while (rem > 0) {\n        bool any = false;\n        for (int z : ord) {\n            if (!rem) break;\n            int cap = LAY[obj][z].cap;\n            if (add[z] < cap) {\n                add[z]++;\n                rem--;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n\n    if (rem > 0) {\n        vector<int> slots;\n        for (int z = 0; z < D; z++) {\n            int cap = LAY[obj][z].cap;\n            for (int t = add[z]; t < cap; t++) slots.push_back(z);\n        }\n        shuffle(slots.begin(), slots.end(), rng);\n        for (int i = 0; i < rem && i < (int)slots.size(); i++) add[slots[i]]++;\n    }\n\n    return add;\n}\n\n// nLeft >= nRight\nvector<int> surjection_dp(const vector<vector<int>>& w, mt19937_64& rng) {\n    int nLeft = (int)w.size();\n    int nRight = (int)w[0].size();\n    int M = 1 << nRight;\n    const int NEG = -1000000000;\n\n    vector<int> dp(M, NEG), ndp(M, NEG);\n    vector<int> parMask((nLeft + 1) * M, -1);\n    vector<short> parChoice((nLeft + 1) * M, -1);\n\n    dp[0] = 0;\n    for (int i = 0; i < nLeft; i++) {\n        fill(ndp.begin(), ndp.end(), NEG);\n        int base = (i + 1) * M;\n\n        for (int mask = 0; mask < M; mask++) {\n            int cur = dp[mask];\n            if (cur <= NEG / 2) continue;\n            for (int j = 0; j < nRight; j++) {\n                int m2 = mask | (1 << j);\n                int val = cur + w[i][j];\n                if (val > ndp[m2] || (val == ndp[m2] && (rng() & 1ULL))) {\n                    ndp[m2] = val;\n                    parMask[base + m2] = mask;\n                    parChoice[base + m2] = (short)j;\n                }\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    int full = M - 1;\n    vector<int> assign(nLeft, 0);\n\n    if (dp[full] <= NEG / 2) {\n        for (int i = 0; i < nLeft; i++) assign[i] = i % nRight;\n        return assign;\n    }\n\n    int mask = full;\n    for (int i = nLeft; i >= 1; i--) {\n        int pos = i * M + mask;\n        short c = parChoice[pos];\n        int pm = parMask[pos];\n        if (c < 0 || pm < 0) {\n            for (int t = 0; t < nLeft; t++) assign[t] = t % nRight;\n            return assign;\n        }\n        assign[i - 1] = (int)c;\n        mask = pm;\n    }\n\n    return assign;\n}\n\nvoid compute_features(Occupancy& oc) {\n    oc.zcnt.fill(0);\n    oc.xcnt.fill(0);\n    oc.ycnt.fill(0);\n\n    int adj6 = 0, zadj = 0;\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        int id = idx3(x, y, z);\n        if (!oc.occ[id]) continue;\n\n        oc.xcnt[x]++;\n        oc.ycnt[y]++;\n        oc.zcnt[z]++;\n\n        if (x + 1 < D && oc.occ[id + SX]) adj6++;\n        if (y + 1 < D && oc.occ[id + SY]) adj6++;\n        if (z + 1 < D && oc.occ[id + SZ]) { adj6++; zadj++; }\n    }\n\n    oc.adj6 = adj6;\n    oc.zadj = zadj;\n}\n\n// style:\n// 0 = DP surjection + continuity bias\n// 1 = grouped shift + continuity bias\n// 2 = random surjection\nOccupancy build_occ_target(int obj, int target, int style, mt19937_64& rng) {\n    Occupancy oc;\n    oc.occ.assign(N, 0);\n    oc.vol = 0;\n\n    int allocMode = (style == 2 ? 1 : 0);\n    vector<int> addz = allocate_add(obj, target, allocMode, rng);\n\n    vector<char> prevXY(D * D, 0), usedXY(D * D, 0);\n\n    for (int z = 0; z < D; z++) {\n        const auto& ld = LAY[obj][z];\n        int a = (int)ld.X.size();\n        int b = (int)ld.Y.size();\n        int m = ld.base + addz[z];\n\n        fill(usedXY.begin(), usedXY.end(), 0);\n        int edgeCount = 0;\n\n        auto put_edge = [&](int x, int y) {\n            int idxy = x * D + y;\n            if (usedXY[idxy]) return;\n            usedXY[idxy] = 1;\n            edgeCount++;\n            int id = idx3(x, y, z);\n            if (!oc.occ[id]) {\n                oc.occ[id] = 1;\n                oc.vol++;\n            }\n        };\n\n        int effStyle = style;\n        if (effStyle == 0 && min(a, b) > 11) effStyle = 1; // speed guard\n\n        // Build minimal cover\n        if (effStyle == 0) {\n            if (a >= b) {\n                vector<vector<int>> w(a, vector<int>(b, 0));\n                for (int i = 0; i < a; i++) {\n                    int x = ld.X[i];\n                    for (int j = 0; j < b; j++) {\n                        int y = ld.Y[j];\n                        int idxy = x * D + y;\n                        int val = (prevXY[idxy] ? 1000 : 0);\n                        val += ColLife[obj][idxy] * 4;\n                        val += (int)(rng() % 31);\n                        w[i][j] = val;\n                    }\n                }\n                auto assign = surjection_dp(w, rng);\n                for (int i = 0; i < a; i++) put_edge(ld.X[i], ld.Y[assign[i]]);\n            } else {\n                vector<vector<int>> w(b, vector<int>(a, 0));\n                for (int j = 0; j < b; j++) {\n                    int y = ld.Y[j];\n                    for (int i = 0; i < a; i++) {\n                        int x = ld.X[i];\n                        int idxy = x * D + y;\n                        int val = (prevXY[idxy] ? 1000 : 0);\n                        val += ColLife[obj][idxy] * 4;\n                        val += (int)(rng() % 31);\n                        w[j][i] = val;\n                    }\n                }\n                auto assign = surjection_dp(w, rng);\n                for (int j = 0; j < b; j++) put_edge(ld.X[assign[j]], ld.Y[j]);\n            }\n        } else if (effStyle == 1) {\n            vector<int> Xv = ld.X, Yv = ld.Y;\n            if (rng() & 1ULL) reverse(Xv.begin(), Xv.end());\n            if (rng() & 1ULL) reverse(Yv.begin(), Yv.end());\n\n            if (a >= b) {\n                int best = INT_MIN;\n                vector<int> bestSh;\n                for (int sh = 0; sh < b; sh++) {\n                    int mat = 0;\n                    for (int j = 0; j < a; j++) {\n                        int g = (int)((long long)j * b / a);\n                        int x = Xv[j];\n                        int y = Yv[(g + sh) % b];\n                        int idxy = x * D + y;\n                        mat += (prevXY[idxy] ? 10 : 0);\n                        mat += ColLife[obj][idxy];\n                    }\n                    if (mat > best) { best = mat; bestSh = {sh}; }\n                    else if (mat == best) bestSh.push_back(sh);\n                }\n                int shift = bestSh[(size_t)(rng() % bestSh.size())];\n                for (int j = 0; j < a; j++) {\n                    int g = (int)((long long)j * b / a);\n                    put_edge(Xv[j], Yv[(g + shift) % b]);\n                }\n            } else {\n                int best = INT_MIN;\n                vector<int> bestSh;\n                for (int sh = 0; sh < a; sh++) {\n                    int mat = 0;\n                    for (int j = 0; j < b; j++) {\n                        int g = (int)((long long)j * a / b);\n                        int x = Xv[(g + sh) % a];\n                        int y = Yv[j];\n                        int idxy = x * D + y;\n                        mat += (prevXY[idxy] ? 10 : 0);\n                        mat += ColLife[obj][idxy];\n                    }\n                    if (mat > best) { best = mat; bestSh = {sh}; }\n                    else if (mat == best) bestSh.push_back(sh);\n                }\n                int shift = bestSh[(size_t)(rng() % bestSh.size())];\n                for (int j = 0; j < b; j++) {\n                    int g = (int)((long long)j * a / b);\n                    put_edge(Xv[(g + shift) % a], Yv[j]);\n                }\n            }\n        } else {\n            if (a >= b) {\n                vector<int> Xv = ld.X;\n                shuffle(Xv.begin(), Xv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(a);\n                for (int y : ld.Y) pool.push_back(y);\n                for (int t = 0; t < a - b; t++) pool.push_back(ld.Y[(int)(rng() % b)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < a; j++) put_edge(Xv[j], pool[j]);\n            } else {\n                vector<int> Yv = ld.Y;\n                shuffle(Yv.begin(), Yv.end(), rng);\n\n                vector<int> pool;\n                pool.reserve(b);\n                for (int x : ld.X) pool.push_back(x);\n                for (int t = 0; t < b - a; t++) pool.push_back(ld.X[(int)(rng() % a)]);\n                shuffle(pool.begin(), pool.end(), rng);\n\n                for (int j = 0; j < b; j++) put_edge(pool[j], Yv[j]);\n            }\n        }\n\n        // Add extras\n        int extra = m - edgeCount;\n        if (extra > 0) {\n            vector<int> cand;\n            cand.reserve(ld.allowed.size());\n            for (int idxy : ld.allowed) if (!usedXY[idxy]) cand.push_back(idxy);\n\n            if (extra >= (int)cand.size()) {\n                for (int idxy : cand) put_edge(idxy / D, idxy % D);\n            } else if (effStyle == 2) {\n                shuffle(cand.begin(), cand.end(), rng);\n                for (int t = 0; t < extra; t++) {\n                    int idxy = cand[t];\n                    put_edge(idxy / D, idxy % D);\n                }\n            } else {\n                for (int t = 0; t < extra; t++) {\n                    int bestId = -1, bestV = INT_MIN;\n\n                    for (int idxy : cand) {\n                        if (usedXY[idxy]) continue;\n                        int x = idxy / D, y = idxy % D;\n\n                        int sc = 0;\n                        sc += (prevXY[idxy] ? (effStyle == 0 ? 120 : 60) : 0);\n\n                        int adj = 0;\n                        if (x > 0 && usedXY[(x - 1) * D + y]) adj++;\n                        if (x + 1 < D && usedXY[(x + 1) * D + y]) adj++;\n                        if (y > 0 && usedXY[x * D + (y - 1)]) adj++;\n                        if (y + 1 < D && usedXY[x * D + (y + 1)]) adj++;\n                        sc += adj * (effStyle == 0 ? 12 : 8);\n\n                        sc += ColLife[obj][idxy] * (effStyle == 0 ? 2 : 1);\n                        sc += (int)(rng() % 16);\n\n                        if (sc > bestV) {\n                            bestV = sc;\n                            bestId = idxy;\n                        }\n                    }\n\n                    if (bestId < 0) break;\n                    put_edge(bestId / D, bestId % D);\n                }\n            }\n        }\n\n        prevXY = usedXY;\n    }\n\n    compute_features(oc);\n    return oc;\n}\n\nvector<Occupancy> generate_candidates(int obj, mt19937_64& rng) {\n    vector<Occupancy> cands;\n\n    int lo = VminObj[obj], hi = VmaxObj[obj];\n    int span = hi - lo;\n\n    if (span == 0) {\n        cands.push_back(build_occ_target(obj, lo, 0, rng));\n        cands.push_back(build_occ_target(obj, lo, 1, rng));\n        cands.push_back(build_occ_target(obj, lo, 2, rng));\n        return cands;\n    }\n\n    int softCap = (D <= 8 ? 52 : (D <= 11 ? 46 : 40));\n\n    vector<int> targets;\n    for (int q = 0; q <= 10; q++) targets.push_back(lo + (int)((long long)span * q / 10));\n    for (int q = 0; q <= 8; q++) targets.push_back(lo + (int)((long long)span * q * q / 64));\n    for (int q = 0; q <= 8; q++) targets.push_back(lo + (int)((long long)span * (64 - (8 - q)*(8 - q)) / 64));\n\n    targets.push_back(lo);\n    targets.push_back(lo + span / 4);\n    targets.push_back(lo + span / 2);\n    targets.push_back(lo + (3 * span) / 4);\n    targets.push_back(hi);\n\n    sort(targets.begin(), targets.end());\n    targets.erase(unique(targets.begin(), targets.end()), targets.end());\n\n    for (int T : targets) {\n        if ((int)cands.size() >= softCap) break;\n\n        if (T <= lo + max(1, span / 3)) {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            cands.push_back(build_occ_target(obj, T, 1, rng));\n            cands.push_back(build_occ_target(obj, T, 2, rng));\n        } else if (T >= lo + (2 * span) / 3) {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            if ((int)cands.size() < softCap) cands.push_back(build_occ_target(obj, T, 1, rng));\n        } else {\n            cands.push_back(build_occ_target(obj, T, 0, rng));\n            if ((int)cands.size() < softCap) cands.push_back(build_occ_target(obj, T, 2, rng));\n        }\n    }\n\n    for (int t = 0; t < 8 && (int)cands.size() < softCap + 8; t++) {\n        long double u = (long double)(rng() % 1000000) / 1000000.0L;\n        if (t & 1) u = 1.0L - (1.0L - u) * (1.0L - u);\n        else u = u * u;\n\n        int T = lo + (int)llround((long double)span * u);\n\n        int styleRoll = (int)(rng() % 100);\n        int style = (styleRoll < 56 ? 0 : (styleRoll < 78 ? 1 : 2));\n\n        cands.push_back(build_occ_target(obj, T, style, rng));\n    }\n\n    return cands;\n}\n\nvector<int> pack_line_best_idx(const vector<char>& freeCells, int L, mt19937_64& rng, int tries = 2) {\n    const auto& pls = allSegs[L];\n\n    vector<int> valid;\n    valid.reserve(pls.size());\n\n    for (int i = 0; i < (int)pls.size(); i++) {\n        const auto& sg = pls[i];\n        int p = sg.s;\n        bool ok = true;\n        for (int t = 0; t < L; t++, p += sg.stride) {\n            if (!freeCells[p]) { ok = false; break; }\n        }\n        if (ok) valid.push_back(i);\n    }\n\n    if (valid.empty()) return {};\n\n    vector<int> best;\n    vector<int> rareOrder;\n\n    if (tries >= 2) {\n        vector<int> freq(N, 0);\n        for (int id : valid) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            for (int t = 0; t < L; t++, p += sg.stride) freq[p]++;\n        }\n\n        vector<pair<long long,int>> scored;\n        scored.reserve(valid.size());\n        for (int id : valid) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            int s = 0;\n            for (int t = 0; t < L; t++, p += sg.stride) s += freq[p];\n            long long key = (long long)s * 2048LL + (long long)(rng() & 2047ULL);\n            scored.push_back({key, id});\n        }\n        sort(scored.begin(), scored.end(), [](auto& a, auto& b){ return a.first < b.first; });\n        rareOrder.reserve(scored.size());\n        for (auto& p : scored) rareOrder.push_back(p.second);\n    }\n\n    for (int tr = 0; tr < tries; tr++) {\n        vector<int> order;\n        if (tr == 0 && !rareOrder.empty()) order = rareOrder;\n        else {\n            order = valid;\n            shuffle(order.begin(), order.end(), rng);\n        }\n\n        vector<char> tmp = freeCells;\n        vector<int> sel;\n        sel.reserve(order.size() / max(1, L) + 1);\n\n        for (int id : order) {\n            const auto& sg = pls[id];\n            int p = sg.s;\n            bool ok = true;\n            for (int t = 0; t < L; t++, p += sg.stride) {\n                if (!tmp[p]) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            sel.push_back(id);\n            p = sg.s;\n            for (int t = 0; t < L; t++, p += sg.stride) tmp[p] = 0;\n        }\n\n        if (sel.size() > best.size()) best.swap(sel);\n    }\n\n    return best;\n}\n\nvector<int> pack_group_best(const vector<char>& freeCells, const ShapeGroup& g, mt19937_64& rng, int tries = 2) {\n    int k = g.k;\n    const auto& pls = g.plc;\n\n    vector<int> valid;\n    valid.reserve(pls.size());\n\n    for (int i = 0; i < (int)pls.size(); i++) {\n        const auto& a = pls[i];\n        bool ok = true;\n        for (int t = 0; t < k; t++) {\n            if (!freeCells[a[t]]) { ok = false; break; }\n        }\n        if (ok) valid.push_back(i);\n    }\n\n    if (valid.empty()) return {};\n\n    vector<int> best;\n    vector<int> rareOrder;\n\n    if (tries >= 2) {\n        vector<int> freq(N, 0);\n        for (int id : valid) {\n            const auto& a = pls[id];\n            for (int t = 0; t < k; t++) freq[a[t]]++;\n        }\n\n        vector<pair<long long,int>> scored;\n        scored.reserve(valid.size());\n        for (int id : valid) {\n            const auto& a = pls[id];\n            int s = 0;\n            for (int t = 0; t < k; t++) s += freq[a[t]];\n            long long key = (long long)s * 2048LL + (long long)(rng() & 2047ULL);\n            scored.push_back({key, id});\n        }\n        sort(scored.begin(), scored.end(), [](auto& p, auto& q){ return p.first < q.first; });\n        rareOrder.reserve(scored.size());\n        for (auto& p : scored) rareOrder.push_back(p.second);\n    }\n\n    for (int tr = 0; tr < tries; tr++) {\n        vector<int> order;\n        if (tr == 0 && !rareOrder.empty()) order = rareOrder;\n        else {\n            order = valid;\n            shuffle(order.begin(), order.end(), rng);\n        }\n\n        vector<char> tmp = freeCells;\n        vector<int> sel;\n        sel.reserve(order.size() / max(1, k) + 1);\n\n        for (int id : order) {\n            const auto& a = pls[id];\n            bool ok = true;\n            for (int t = 0; t < k; t++) {\n                if (!tmp[a[t]]) { ok = false; break; }\n            }\n            if (!ok) continue;\n\n            sel.push_back(id);\n            for (int t = 0; t < k; t++) tmp[a[t]] = 0;\n        }\n\n        if (sel.size() > best.size()) best.swap(sel);\n    }\n\n    return best;\n}\n\nvector<pair<int,int>> max_domino_matching(const vector<char>& freeCells) {\n    vector<int> lid(N, -1), rid(N, -1);\n    vector<int> Lc, Rc;\n    Lc.reserve(N); Rc.reserve(N);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i]) continue;\n        if (parityCell[i] == 0) {\n            lid[i] = (int)Lc.size();\n            Lc.push_back(i);\n        } else {\n            rid[i] = (int)Rc.size();\n            Rc.push_back(i);\n        }\n    }\n\n    int Ls = (int)Lc.size();\n    int Rs = (int)Rc.size();\n\n    vector<vector<int>> g(Ls);\n    for (int u = 0; u < Ls; u++) {\n        int c = Lc[u];\n        auto& adj = g[u];\n        for (int nb : neighbors[c]) {\n            if (!freeCells[nb]) continue;\n            int v = rid[nb];\n            if (v != -1) adj.push_back(v);\n        }\n    }\n\n    vector<int> dist(Ls), matchL(Ls, -1), matchR(Rs, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(dist.begin(), dist.end(), -1);\n        bool found = false;\n        for (int u = 0; u < Ls; u++) {\n            if (matchL[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : g[u]) {\n                int u2 = matchR[v];\n                if (u2 == -1) {\n                    found = true;\n                } else if (dist[u2] == -1) {\n                    dist[u2] = dist[u] + 1;\n                    q.push(u2);\n                }\n            }\n        }\n        return found;\n    };\n\n    auto dfs = [&](auto&& self, int u) -> bool {\n        for (int v : g[u]) {\n            int u2 = matchR[v];\n            if (u2 == -1 || (dist[u2] == dist[u] + 1 && self(self, u2))) {\n                matchL[u] = v;\n                matchR[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int u = 0; u < Ls; u++) if (matchL[u] == -1) dfs(dfs, u);\n    }\n\n    vector<pair<int,int>> pairs;\n    pairs.reserve(Ls);\n    for (int u = 0; u < Ls; u++) {\n        if (matchL[u] != -1) pairs.push_back({Lc[u], Rc[matchL[u]]});\n    }\n    return pairs;\n}\n\nvector<vector<int>> extract_components(const vector<char>& freeCells) {\n    vector<char> vis(N, 0);\n    vector<vector<int>> comps;\n    vector<int> q;\n    q.reserve(256);\n\n    for (int i = 0; i < N; i++) {\n        if (!freeCells[i] || vis[i]) continue;\n        q.clear();\n        q.push_back(i);\n        vis[i] = 1;\n\n        vector<int> comp;\n        comp.reserve(16);\n\n        for (int qi = 0; qi < (int)q.size(); qi++) {\n            int v = q[qi];\n            comp.push_back(v);\n            for (int nb : neighbors[v]) {\n                if (freeCells[nb] && !vis[nb]) {\n                    vis[nb] = 1;\n                    q.push_back(nb);\n                }\n            }\n        }\n\n        comps.push_back(move(comp));\n    }\n\n    return comps;\n}\n\nstring canonical_key_component(const vector<int>& cells) {\n    int k = (int)cells.size();\n\n    vector<Pt> pts;\n    pts.reserve(k);\n    for (int id : cells) pts.push_back({(int)CX[id], (int)CY[id], (int)CZ[id]});\n\n    string best;\n    bool first = true;\n    vector<Pt> t;\n    t.reserve(k);\n\n    for (const auto& r : ROTS) {\n        t.clear();\n        int mnx = 1e9, mny = 1e9, mnz = 1e9;\n        for (const auto& p : pts) {\n            Pt q = rotate_pt(p, r);\n            mnx = min(mnx, q.x);\n            mny = min(mny, q.y);\n            mnz = min(mnz, q.z);\n            t.push_back(q);\n        }\n\n        for (auto& q : t) {\n            q.x -= mnx;\n            q.y -= mny;\n            q.z -= mnz;\n        }\n\n        sort(t.begin(), t.end(), [](const Pt& a, const Pt& b) {\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        string key;\n        key.resize(3 * k);\n        int pos = 0;\n        for (auto& q : t) {\n            key[pos++] = (char)q.x;\n            key[pos++] = (char)q.y;\n            key[pos++] = (char)q.z;\n        }\n\n        if (first || key < best) {\n            first = false;\n            best = move(key);\n        }\n    }\n\n    return best;\n}\n\nvoid match_exact_components(\n    vector<char>& free1, vector<char>& free2,\n    vector<int>& b1, vector<int>& b2,\n    int& id, int& sharedVol, long double& sharedTerm,\n    mt19937_64& rng\n) {\n    int c1 = 0, c2 = 0;\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) c1++;\n        if (free2[i]) c2++;\n    }\n\n    int fmin = min(c1, c2);\n    if (fmin < 3) return;\n\n    int maxSize;\n    if (fmin <= 350) maxSize = 96;\n    else if (fmin <= 800) maxSize = 56;\n    else maxSize = 32;\n\n    if ((rng() % 100) < 12) maxSize = min(120, maxSize * 2);\n    maxSize = min(maxSize, 120);\n\n    auto comps1 = extract_components(free1);\n    auto comps2 = extract_components(free2);\n\n    unordered_map<int,int> szCnt1, szCnt2;\n    szCnt1.reserve(comps1.size() * 2 + 1);\n    szCnt2.reserve(comps2.size() * 2 + 1);\n\n    for (auto& c : comps1) {\n        int s = (int)c.size();\n        if (s >= 3 && s <= maxSize) szCnt1[s]++;\n    }\n    for (auto& c : comps2) {\n        int s = (int)c.size();\n        if (s >= 3 && s <= maxSize) szCnt2[s]++;\n    }\n\n    vector<int> goodSizes;\n    goodSizes.reserve(16);\n    for (auto& kv : szCnt1) {\n        int s = kv.first;\n        if (szCnt2.find(s) != szCnt2.end()) goodSizes.push_back(s);\n    }\n    if (goodSizes.empty()) return;\n\n    unordered_set<int> goodSet(goodSizes.begin(), goodSizes.end());\n\n    unordered_map<string, vector<int>> mp1, mp2;\n    mp1.reserve(comps1.size() * 2 + 1);\n    mp2.reserve(comps2.size() * 2 + 1);\n\n    for (int i = 0; i < (int)comps1.size(); i++) {\n        int s = (int)comps1[i].size();\n        if (!goodSet.count(s)) continue;\n        string key = canonical_key_component(comps1[i]);\n        key.push_back((char)(unsigned char)s);\n        mp1[key].push_back(i);\n    }\n    for (int i = 0; i < (int)comps2.size(); i++) {\n        int s = (int)comps2[i].size();\n        if (!goodSet.count(s)) continue;\n        string key = canonical_key_component(comps2[i]);\n        key.push_back((char)(unsigned char)s);\n        mp2[key].push_back(i);\n    }\n\n    for (auto& kv : mp1) {\n        auto it = mp2.find(kv.first);\n        if (it == mp2.end()) continue;\n\n        auto& v1 = kv.second;\n        auto& v2 = it->second;\n\n        shuffle(v1.begin(), v1.end(), rng);\n        shuffle(v2.begin(), v2.end(), rng);\n\n        int s = min((int)v1.size(), (int)v2.size());\n        for (int t = 0; t < s; t++) {\n            int i1 = v1[t], i2 = v2[t];\n            int sz = (int)comps1[i1].size();\n\n            ++id;\n            for (int c : comps1[i1]) {\n                b1[c] = id;\n                free1[c] = 0;\n            }\n            for (int c : comps2[i2]) {\n                b2[c] = id;\n                free2[c] = 0;\n            }\n\n            sharedVol += sz;\n            sharedTerm += 1.0L / (long double)sz;\n        }\n    }\n}\n\nSolution make_solution(const Occupancy& o1, const Occupancy& o2, mt19937_64& rng) {\n    vector<char> free1 = o1.occ;\n    vector<char> free2 = o2.occ;\n    vector<int> b1(N, 0), b2(N, 0);\n\n    int id = 0;\n    int sharedVol = 0;\n    long double sharedTerm = 0.0L;\n\n    auto apply_line_pair = [&](int L, int tries) {\n        if (L < 3) return;\n        auto s1 = pack_line_best_idx(free1, L, rng, tries);\n        auto s2 = pack_line_best_idx(free2, L, rng, tries);\n\n        int s = min((int)s1.size(), (int)s2.size());\n        if (s == 0) return;\n\n        if ((int)s1.size() > s) { shuffle(s1.begin(), s1.end(), rng); s1.resize(s); }\n        if ((int)s2.size() > s) { shuffle(s2.begin(), s2.end(), rng); s2.resize(s); }\n\n        const auto& pls = allSegs[L];\n        for (int i = 0; i < s; i++) {\n            ++id;\n\n            const auto& A = pls[s1[i]];\n            int p = A.s;\n            for (int t = 0; t < L; t++, p += A.stride) {\n                b1[p] = id;\n                free1[p] = 0;\n            }\n\n            const auto& B = pls[s2[i]];\n            p = B.s;\n            for (int t = 0; t < L; t++, p += B.stride) {\n                b2[p] = id;\n                free2[p] = 0;\n            }\n\n            sharedVol += L;\n            sharedTerm += 1.0L / (long double)L;\n        }\n    };\n\n    auto apply_group_pair = [&](const ShapeGroup& g, int tries) {\n        auto s1 = pack_group_best(free1, g, rng, tries);\n        auto s2 = pack_group_best(free2, g, rng, tries);\n\n        int s = min((int)s1.size(), (int)s2.size());\n        if (s == 0) return;\n\n        if ((int)s1.size() > s) { shuffle(s1.begin(), s1.end(), rng); s1.resize(s); }\n        if ((int)s2.size() > s) { shuffle(s2.begin(), s2.end(), rng); s2.resize(s); }\n\n        int k = g.k;\n        for (int i = 0; i < s; i++) {\n            ++id;\n            const auto& A = g.plc[s1[i]];\n            const auto& B = g.plc[s2[i]];\n            for (int t = 0; t < k; t++) {\n                b1[A[t]] = id;\n                free1[A[t]] = 0;\n            }\n            for (int t = 0; t < k; t++) {\n                b2[B[t]] = id;\n                free2[B[t]] = 0;\n            }\n            sharedVol += k;\n            sharedTerm += 1.0L / (long double)k;\n        }\n    };\n\n    int variant = (int)(rng() % 5);\n\n    if (variant == 0) {\n        for (int L = D; L >= 9; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n        for (int L = min(8, D); L >= 5; L--) apply_line_pair(L, 2);\n    } else if (variant == 1) {\n        apply_group_pair(cubeGroup, 2);\n        for (int L = D; L >= 5; L--) apply_line_pair(L, 2);\n    } else if (variant == 2) {\n        for (int L = D; L >= 5; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n    } else if (variant == 3) {\n        for (int L = D; L >= 6; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 2);\n        if (D >= 5) apply_line_pair(5, 2);\n    } else {\n        for (int L = D; L >= 7; L--) apply_line_pair(L, 2);\n        apply_group_pair(cubeGroup, 1);\n        for (int L = min(6, D); L >= 5; L--) apply_line_pair(L, 2);\n    }\n\n    // Tetracubes\n    vector<int> ord4(groups4.size());\n    iota(ord4.begin(), ord4.end(), 0);\n\n    int p4 = (int)(rng() % 4);\n    if (p4 == 0) {\n        shuffle(ord4.begin(), ord4.end(), rng);\n    } else if (p4 == 1) {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            return groups4[i].plc.size() < groups4[j].plc.size();\n        });\n    } else if (p4 == 2) {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            return groups4[i].plc.size() > groups4[j].plc.size();\n        });\n    } else {\n        sort(ord4.begin(), ord4.end(), [&](int i, int j) {\n            if (groups4[i].isLine != groups4[j].isLine) return groups4[i].isLine > groups4[j].isLine;\n            return groups4[i].plc.size() < groups4[j].plc.size();\n        });\n    }\n\n    for (int idx : ord4) {\n        int tries = 2;\n        if (groups4[idx].isLine && (rng() % 100) < 30) tries = 3;\n        apply_group_pair(groups4[idx], tries);\n    }\n\n    // Tricubes\n    vector<int> ord3(groups3.size());\n    iota(ord3.begin(), ord3.end(), 0);\n\n    if ((rng() & 1ULL) == 0) {\n        sort(ord3.begin(), ord3.end(), [&](int i, int j) {\n            if (groups3[i].isLine != groups3[j].isLine) return groups3[i].isLine > groups3[j].isLine;\n            return groups3[i].plc.size() < groups3[j].plc.size();\n        });\n    } else {\n        shuffle(ord3.begin(), ord3.end(), rng);\n    }\n    for (int idx : ord3) apply_group_pair(groups3[idx], 2);\n\n    auto free_count = [&](const vector<char>& f) {\n        int c = 0;\n        for (char v : f) c += (v != 0);\n        return c;\n    };\n\n    int f1 = free_count(free1), f2 = free_count(free2);\n    int fmin = min(f1, f2);\n\n    if (fmin >= 3) {\n        bool doComp = (fmin <= 1200) || ((rng() % 100) < 35);\n        if (doComp) {\n            match_exact_components(free1, free2, b1, b2, id, sharedVol, sharedTerm, rng);\n        }\n    }\n\n    // Domino pass 1\n    auto d1 = max_domino_matching(free1);\n    auto d2 = max_domino_matching(free2);\n    int sd = min((int)d1.size(), (int)d2.size());\n\n    if (sd > 0) {\n        if ((int)d1.size() > sd) { shuffle(d1.begin(), d1.end(), rng); d1.resize(sd); }\n        if ((int)d2.size() > sd) { shuffle(d2.begin(), d2.end(), rng); d2.resize(sd); }\n\n        for (int i = 0; i < sd; i++) {\n            ++id;\n            auto [a,b] = d1[i];\n            b1[a] = id; b1[b] = id;\n            free1[a] = 0; free1[b] = 0;\n\n            auto [c,d] = d2[i];\n            b2[c] = id; b2[d] = id;\n            free2[c] = 0; free2[d] = 0;\n\n            sharedVol += 2;\n            sharedTerm += 0.5L;\n        }\n    }\n\n    f1 = free_count(free1), f2 = free_count(free2);\n    fmin = min(f1, f2);\n    if (fmin >= 3 && fmin <= 300 && (rng() % 100) < 55) {\n        match_exact_components(free1, free2, b1, b2, id, sharedVol, sharedTerm, rng);\n    }\n\n    // Salvage pass\n    if ((rng() % 100) < 70) {\n        if (D >= 4) apply_line_pair(4, 1);\n        apply_line_pair(3, 1);\n\n        auto d1b = max_domino_matching(free1);\n        auto d2b = max_domino_matching(free2);\n        int sdb = min((int)d1b.size(), (int)d2b.size());\n        if (sdb > 0) {\n            if ((int)d1b.size() > sdb) { shuffle(d1b.begin(), d1b.end(), rng); d1b.resize(sdb); }\n            if ((int)d2b.size() > sdb) { shuffle(d2b.begin(), d2b.end(), rng); d2b.resize(sdb); }\n\n            for (int i = 0; i < sdb; i++) {\n                ++id;\n                auto [a,b] = d1b[i];\n                b1[a] = id; b1[b] = id;\n                free1[a] = 0; free1[b] = 0;\n\n                auto [c,d] = d2b[i];\n                b2[c] = id; b2[d] = id;\n                free2[c] = 0; free2[d] = 0;\n\n                sharedVol += 2;\n                sharedTerm += 0.5L;\n            }\n        }\n\n        f1 = free_count(free1), f2 = free_count(free2);\n        fmin = min(f1, f2);\n        if (fmin >= 3 && fmin <= 180 && (rng() % 100) < 45) {\n            match_exact_components(free1, free2, b1, b2, id, sharedVol, sharedTerm, rng);\n        }\n    }\n\n    // Monomino fallback\n    vector<int> rem1, rem2;\n    rem1.reserve(N); rem2.reserve(N);\n    for (int i = 0; i < N; i++) {\n        if (free1[i]) rem1.push_back(i);\n        if (free2[i]) rem2.push_back(i);\n    }\n\n    shuffle(rem1.begin(), rem1.end(), rng);\n    shuffle(rem2.begin(), rem2.end(), rng);\n\n    int sm = min((int)rem1.size(), (int)rem2.size());\n    for (int i = 0; i < sm; i++) {\n        ++id;\n        b1[rem1[i]] = id;\n        b2[rem2[i]] = id;\n        sharedVol += 1;\n        sharedTerm += 1.0L;\n    }\n    for (int i = sm; i < (int)rem1.size(); i++) {\n        ++id;\n        b1[rem1[i]] = id;\n    }\n    for (int i = sm; i < (int)rem2.size(); i++) {\n        ++id;\n        b2[rem2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = (long double)(o1.vol + o2.vol - 2 * sharedVol) + sharedTerm;\n    return sol;\n}\n\nbool check_silhouette_one(const vector<int>& b, int obj) {\n    for (int z = 0; z < D; z++) {\n        for (int x = 0; x < D; x++) {\n            bool seen = false;\n            for (int y = 0; y < D; y++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (F[obj][z][x] == '1')) return false;\n        }\n        for (int y = 0; y < D; y++) {\n            bool seen = false;\n            for (int x = 0; x < D; x++) {\n                if (b[idx3(x, y, z)] > 0) { seen = true; break; }\n            }\n            if (seen != (Rv[obj][z][y] == '1')) return false;\n        }\n    }\n    return true;\n}\n\nbool check_silhouette(const Solution& sol) {\n    if ((int)sol.b1.size() != N || (int)sol.b2.size() != N) return false;\n    return check_silhouette_one(sol.b1, 0) && check_silhouette_one(sol.b2, 1);\n}\n\nSolution fallback_simple() {\n    vector<int> b1(N, 0), b2(N, 0);\n    vector<int> c1, c2;\n    c1.reserve(N); c2.reserve(N);\n\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (F[0][z][x] == '1' && Rv[0][z][y] == '1') c1.push_back(idx3(x, y, z));\n        if (F[1][z][x] == '1' && Rv[1][z][y] == '1') c2.push_back(idx3(x, y, z));\n    }\n\n    int id = 0;\n    int m = min((int)c1.size(), (int)c2.size());\n    for (int i = 0; i < m; i++) {\n        ++id;\n        b1[c1[i]] = id;\n        b2[c2[i]] = id;\n    }\n    for (int i = m; i < (int)c1.size(); i++) {\n        ++id;\n        b1[c1[i]] = id;\n    }\n    for (int i = m; i < (int)c2.size(); i++) {\n        ++id;\n        b2[c2[i]] = id;\n    }\n\n    Solution sol;\n    sol.n = id;\n    sol.b1 = move(b1);\n    sol.b2 = move(b2);\n    sol.score = 1e99L;\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        Rv[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> Rv[i][z];\n    }\n\n    precompute();\n\n    mt19937_64 rng(\n        chrono::steady_clock::now().time_since_epoch().count()\n        ^ ((uint64_t)D * 1000003ULL)\n    );\n\n    const double TL = 5.35;\n    auto st = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    };\n\n    Solution best;\n    const long double INF = 1e100L;\n\n    Occupancy bestO1, bestO2;\n    bool haveBestOcc = false;\n\n    int overlapL = max(VminObj[0], VminObj[1]);\n    int overlapU = min(VmaxObj[0], VmaxObj[1]);\n    bool hasOverlap = (overlapL <= overlapU);\n\n    auto try_pair = [&](const Occupancy& o1, const Occupancy& o2, int repsBase) -> long double {\n        if (elapsed() >= TL) return INF;\n\n        int mn = min(o1.vol, o2.vol);\n        long double lb = fabsl((long double)o1.vol - (long double)o2.vol) + 1.0L / (long double)mn;\n        if (lb + 1e-12L >= best.score) return INF;\n\n        int reps = repsBase;\n        if (best.score < INF / 2) {\n            if (lb < best.score * 0.72L) reps = max(reps, 2);\n            if (lb < best.score * 0.58L) reps = max(reps, 3);\n        }\n        if (elapsed() > TL * 0.90) reps = 1;\n\n        long double localBest = INF;\n        for (int t = 0; t < reps; t++) {\n            if (elapsed() >= TL) break;\n            Solution cur = make_solution(o1, o2, rng);\n            localBest = min(localBest, cur.score);\n            if (cur.score < best.score) {\n                best = move(cur);\n                bestO1 = o1;\n                bestO2 = o2;\n                haveBestOcc = true;\n            }\n        }\n        return localBest;\n    };\n\n    // Initial solution\n    {\n        int t1, t2;\n        if (hasOverlap) {\n            t1 = overlapL;\n            t2 = overlapL;\n        } else if (VmaxObj[0] < VminObj[1]) {\n            t1 = VmaxObj[0];\n            t2 = VminObj[1];\n        } else {\n            t1 = VminObj[0];\n            t2 = VmaxObj[1];\n        }\n        Occupancy o1 = build_occ_target(0, t1, 0, rng);\n        Occupancy o2 = build_occ_target(1, t2, 0, rng);\n        try_pair(o1, o2, 3);\n    }\n\n    vector<Occupancy> cand1, cand2;\n    if (elapsed() < TL * 0.35) {\n        cand1 = generate_candidates(0, rng);\n        cand2 = generate_candidates(1, rng);\n    } else {\n        cand1.push_back(build_occ_target(0, VminObj[0], 0, rng));\n        cand2.push_back(build_occ_target(1, VminObj[1], 0, rng));\n    }\n\n    auto l1arr = [&](const array<int,14>& a, const array<int,14>& b) {\n        int s = 0;\n        for (int i = 0; i < D; i++) s += abs(a[i] - b[i]);\n        return s;\n    };\n\n    struct PairCand {\n        int i, j;\n        int dZ;\n        int dXY;\n        int zmin;\n        int amin;\n        int mn;\n        long double lb;\n        uint64_t tie;\n    };\n\n    vector<PairCand> plist;\n    plist.reserve((int)cand1.size() * (int)cand2.size());\n\n    for (int i = 0; i < (int)cand1.size(); i++) {\n        for (int j = 0; j < (int)cand2.size(); j++) {\n            int mn = min(cand1[i].vol, cand2[j].vol);\n            long double lb = fabsl((long double)cand1[i].vol - (long double)cand2[j].vol)\n                           + 1.0L / (long double)mn;\n\n            int dZ = l1arr(cand1[i].zcnt, cand2[j].zcnt);\n            int dXY = l1arr(cand1[i].xcnt, cand2[j].xcnt) + l1arr(cand1[i].ycnt, cand2[j].ycnt);\n            int zmin = min(cand1[i].zadj, cand2[j].zadj);\n            int amin = min(cand1[i].adj6, cand2[j].adj6);\n\n            plist.push_back({i, j, dZ, dXY, zmin, amin, mn, lb, rng()});\n        }\n    }\n\n    sort(plist.begin(), plist.end(), [](const PairCand& a, const PairCand& b) {\n        if (fabsl(a.lb - b.lb) > 1e-12L) return a.lb < b.lb;\n        if (a.dZ != b.dZ) return a.dZ < b.dZ;\n        if (a.dXY != b.dXY) return a.dXY < b.dXY;\n        if (a.mn != b.mn) return a.mn > b.mn;\n        if (a.zmin != b.zmin) return a.zmin > b.zmin;\n        if (a.amin != b.amin) return a.amin > b.amin;\n        return a.tie < b.tie;\n    });\n\n    vector<pair<int,int>> initPairs;\n    {\n        int initLimit = min((int)plist.size(), (D <= 8 ? 210 : (D <= 11 ? 180 : 150)));\n        initPairs.reserve(initLimit + 50);\n\n        unordered_set<unsigned long long> used;\n        auto add_pair = [&](int i, int j) {\n            unsigned long long key = (unsigned long long)(unsigned int)i << 32 | (unsigned int)j;\n            if (used.insert(key).second) initPairs.push_back({i, j});\n        };\n\n        int baseTake = initLimit;\n        for (int p = 0; p < baseTake; p++) add_pair(plist[p].i, plist[p].j);\n\n        int poolStart = baseTake;\n        int poolLen = 0;\n        if ((int)plist.size() > poolStart) {\n            poolLen = min((int)plist.size() - poolStart, (D <= 8 ? 180 : (D <= 11 ? 140 : 110)));\n        }\n        int extraTake = min(poolLen, (D <= 8 ? 45 : (D <= 11 ? 35 : 28)));\n        for (int t = 0; t < extraTake; t++) {\n            int idx = poolStart + (int)(rng() % poolLen);\n            add_pair(plist[idx].i, plist[idx].j);\n        }\n    }\n\n    vector<tuple<long double,int,int>> records;\n    for (int p = 0; p < (int)initPairs.size(); p++) {\n        if (elapsed() >= TL * 0.60) break;\n        auto [ii, jj] = initPairs[p];\n        int reps = (p < 20 ? 2 : 1);\n        long double sc = try_pair(cand1[ii], cand2[jj], reps);\n        if (sc < INF / 10) records.emplace_back(sc, ii, jj);\n    }\n\n    if (records.empty() && !plist.empty() && elapsed() < TL) {\n        const auto& pc = plist[0];\n        long double sc = try_pair(cand1[pc.i], cand2[pc.j], 1);\n        if (sc < INF / 10) records.emplace_back(sc, pc.i, pc.j);\n    }\n\n    sort(records.begin(), records.end(), [](const auto& A, const auto& B) {\n        return get<0>(A) < get<0>(B);\n    });\n\n    vector<pair<int,int>> eliteIdx;\n    int eN = min((int)records.size(), 40);\n    for (int i = 0; i < eN; i++) eliteIdx.push_back({get<1>(records[i]), get<2>(records[i])});\n\n    struct DynPair {\n        Occupancy o1, o2;\n        long double sc;\n    };\n    vector<DynPair> dyn;\n\n    auto add_dyn = [&](const Occupancy& o1, const Occupancy& o2, long double sc) {\n        if (!(sc < INF / 10)) return;\n        if ((int)dyn.size() < 10) {\n            dyn.push_back({o1, o2, sc});\n        } else {\n            int worst = 0;\n            for (int i = 1; i < (int)dyn.size(); i++) if (dyn[i].sc > dyn[worst].sc) worst = i;\n            if (sc < dyn[worst].sc) dyn[worst] = {o1, o2, sc};\n        }\n    };\n\n    for (int i = 0; i < min((int)records.size(), 8); i++) {\n        int ii = get<1>(records[i]), jj = get<2>(records[i]);\n        add_dyn(cand1[ii], cand2[jj], get<0>(records[i]));\n    }\n\n    double phase1End = TL * 0.88;\n\n    while (elapsed() < phase1End) {\n        int r = (int)(rng() % 100);\n\n        if (!eliteIdx.empty() && r < 50) {\n            auto [i, j] = eliteIdx[(size_t)(rng() % eliteIdx.size())];\n            int reps = ((rng() % 100) < 24 ? 2 : 1);\n            try_pair(cand1[i], cand2[j], reps);\n        } else if (!dyn.empty() && r < 78) {\n            int idp = (int)(rng() % dyn.size());\n            int reps = ((rng() % 100) < 30 ? 2 : 1);\n            long double sc = try_pair(dyn[idp].o1, dyn[idp].o2, reps);\n            dyn[idp].sc = min(dyn[idp].sc, sc);\n        } else {\n            int rr1 = (int)(rng() % 100);\n            int style1 = (rr1 < 56 ? 0 : (rr1 < 78 ? 1 : 2));\n\n            int style2;\n            if ((rng() % 100) < 70) style2 = style1;\n            else {\n                int rr2 = (int)(rng() % 100);\n                style2 = (rr2 < 56 ? 0 : (rr2 < 78 ? 1 : 2));\n            }\n\n            int t1, t2;\n\n            if (haveBestOcc && (rng() % 100) < 32) {\n                int span1 = max(1, (VmaxObj[0] - VminObj[0]) / 20);\n                int span2 = max(1, (VmaxObj[1] - VminObj[1]) / 20);\n                int d1 = (int)(rng() % (2 * span1 + 1)) - span1;\n                int d2 = (int)(rng() % (2 * span2 + 1)) - span2;\n                t1 = clampi(bestO1.vol + d1, VminObj[0], VmaxObj[0]);\n                t2 = clampi(bestO2.vol + d2, VminObj[1], VmaxObj[1]);\n            } else if (hasOverlap && (rng() % 100) < 88) {\n                int span = overlapU - overlapL;\n                long double u = (long double)(rng() % 1000000) / 1000000.0L;\n                if ((rng() & 1ULL) == 0) u = u * u;\n                else u = 1.0L - (1.0L - u) * (1.0L - u);\n                int T = overlapL + (int)llround((long double)span * u);\n\n                int jit = max(0, span / 12);\n                int d1 = (jit ? (int)(rng() % (2 * jit + 1)) - jit : 0);\n                int d2 = (jit ? (int)(rng() % (2 * jit + 1)) - jit : 0);\n\n                t1 = clampi(T + d1, VminObj[0], VmaxObj[0]);\n                t2 = clampi(T + d2, VminObj[1], VmaxObj[1]);\n            } else if (VmaxObj[0] < VminObj[1]) {\n                int a = min(8, VmaxObj[0] - VminObj[0]);\n                int b = min(8, VmaxObj[1] - VminObj[1]);\n                t1 = VmaxObj[0] - (a ? (int)(rng() % (a + 1)) : 0);\n                t2 = VminObj[1] + (b ? (int)(rng() % (b + 1)) : 0);\n            } else if (VmaxObj[1] < VminObj[0]) {\n                int a = min(8, VmaxObj[0] - VminObj[0]);\n                int b = min(8, VmaxObj[1] - VminObj[1]);\n                t1 = VminObj[0] + (a ? (int)(rng() % (a + 1)) : 0);\n                t2 = VmaxObj[1] - (b ? (int)(rng() % (b + 1)) : 0);\n            } else {\n                int span1 = VmaxObj[0] - VminObj[0];\n                int span2 = VmaxObj[1] - VminObj[1];\n                long double u1 = (long double)(rng() % 1000000) / 1000000.0L;\n                long double u2 = (long double)(rng() % 1000000) / 1000000.0L;\n                if ((rng() & 1ULL) == 0) u1 = u1 * u1;\n                if ((rng() & 1ULL) == 0) u2 = u2 * u2;\n                t1 = VminObj[0] + (int)llround((long double)span1 * u1);\n                t2 = VminObj[1] + (int)llround((long double)span2 * u2);\n            }\n\n            Occupancy o1 = build_occ_target(0, t1, style1, rng);\n            Occupancy o2 = build_occ_target(1, t2, style2, rng);\n\n            long double sc = try_pair(o1, o2, 1);\n            if (sc < best.score * 1.30L) add_dyn(o1, o2, sc);\n        }\n    }\n\n    // Neighborhood search around best occupancy (late)\n    if (haveBestOcc) {\n        int baseSpan1 = max(1, (VmaxObj[0] - VminObj[0]) / 22);\n        int baseSpan2 = max(1, (VmaxObj[1] - VminObj[1]) / 22);\n        for (int t = 0; t < 24 && elapsed() < TL * 0.95; t++) {\n            int rr1 = (int)(rng() % 100);\n            int style1 = (rr1 < 65 ? 0 : (rr1 < 85 ? 1 : 2));\n            int rr2 = (int)(rng() % 100);\n            int style2 = ((rng() % 100) < 70 ? style1 : (rr2 < 65 ? 0 : (rr2 < 85 ? 1 : 2)));\n\n            int mul = (t < 10 ? 1 : 2);\n            int s1 = baseSpan1 * mul;\n            int s2 = baseSpan2 * mul;\n\n            int d1 = (int)(rng() % (2 * s1 + 1)) - s1;\n            int d2 = (int)(rng() % (2 * s2 + 1)) - s2;\n\n            int t1 = clampi(bestO1.vol + d1, VminObj[0], VmaxObj[0]);\n            int t2 = clampi(bestO2.vol + d2, VminObj[1], VmaxObj[1]);\n\n            Occupancy o1 = build_occ_target(0, t1, style1, rng);\n            Occupancy o2 = build_occ_target(1, t2, style2, rng);\n\n            long double sc = try_pair(o1, o2, 1);\n            if (sc < best.score * 1.20L) add_dyn(o1, o2, sc);\n        }\n    }\n\n    // Final intensification (repack only)\n    vector<pair<Occupancy, Occupancy>> focus;\n    if (haveBestOcc) {\n        for (int k = 0; k < 4; k++) focus.push_back({bestO1, bestO2});\n    }\n\n    for (int i = 0; i < min((int)records.size(), 8); i++) {\n        int ii = get<1>(records[i]), jj = get<2>(records[i]);\n        focus.push_back({cand1[ii], cand2[jj]});\n    }\n\n    sort(dyn.begin(), dyn.end(), [](const DynPair& a, const DynPair& b) { return a.sc < b.sc; });\n    for (int i = 0; i < min((int)dyn.size(), 5); i++) {\n        focus.push_back({dyn[i].o1, dyn[i].o2});\n    }\n\n    while (elapsed() < TL && !focus.empty()) {\n        int idx;\n        if (haveBestOcc && (rng() % 100) < 55) idx = (int)(rng() % min<int>(4, (int)focus.size()));\n        else idx = (int)(rng() % focus.size());\n\n        auto& pp = focus[idx];\n        Solution cur = make_solution(pp.first, pp.second, rng);\n        if (cur.score < best.score) {\n            best = move(cur);\n            bestO1 = pp.first;\n            bestO2 = pp.second;\n            haveBestOcc = true;\n        }\n    }\n\n    if (best.n == 0 || !check_silhouette(best)) {\n        best = fallback_simple();\n    }\n\n    cout << best.n << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << best.b2[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(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    using ll = long long;\n    static constexpr ll INF = (1LL << 62);\n    static constexpr int RAD = 5000;\n    static constexpr int MAXN = 105;\n    static constexpr int MAXM = 305;\n\n    int N, M, K;\n\n    struct Edge { int u, v, w; };\n    vector<int> x, y;\n    vector<Edge> edges;\n    vector<int> a, b;\n\n    vector<vector<pair<int,int>>> g; // (to, edge_id)\n    vector<vector<int>> incident;\n    vector<int> edgeOrder; // by weight asc\n\n    vector<vector<uint16_t>> distSR; // [N][K]\n\n    // resident -> candidates within 5000: (dist, station), sorted\n    vector<vector<pair<uint16_t,int>>> cand; // [K]\n\n    // station -> residents within 5000: (dist, resident), sorted\n    vector<vector<pair<uint16_t,int>>> byStation; // [N]\n    vector<vector<int>> coverResidents;           // [N]\n\n    // APSP on station graph\n    vector<vector<ll>> spDist;\n    vector<vector<int>> prevNode;\n    vector<vector<int>> prevEdge;\n\n    vector<double> rootPen; // scaled root shortest path\n    vector<int> addOrderStatic;\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point startTime;\n\n    struct Key {\n        uint64_t lo = 0, hi = 0;\n        bool operator==(const Key& o) const noexcept {\n            return lo == o.lo && hi == o.hi;\n        }\n    };\n    struct KeyHash {\n        size_t operator()(const Key& k) const noexcept {\n            size_t h1 = std::hash<uint64_t>{}(k.lo);\n            size_t h2 = std::hash<uint64_t>{}(k.hi);\n            return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));\n        }\n    };\n\n    unordered_map<Key, ll, KeyHash> cacheFast;\n    unordered_map<Key, ll, KeyHash> cacheExact;\n\n    struct Solution {\n        bool feasible = false;\n        ll cost = INF;\n        vector<int> P;\n        vector<char> B;\n    };\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n    double rand01() {\n        return (double(rng()) + 0.5) / (double(rng.max()) + 1.0);\n    }\n\n    static int ceilDistInt(int x1, int y1, int x2, int y2) {\n        long long dx = 1LL * x1 - x2;\n        long long dy = 1LL * y1 - y2;\n        long long sq = dx * dx + dy * dy;\n        int d = (int)std::sqrt((double)sq);\n        while (1LL * d * d < sq) ++d;\n        while (d > 0 && 1LL * (d - 1) * (d - 1) >= sq) --d;\n        return d;\n    }\n\n    Key makeKey(const vector<char>& active) const {\n        Key k;\n        for (int i = 0; i < N; i++) {\n            if (!active[i]) continue;\n            if (i < 64) k.lo |= (1ULL << i);\n            else k.hi |= (1ULL << (i - 64));\n        }\n        return k;\n    }\n\n    bool sameState(const vector<char>& A, const vector<char>& B) const {\n        if ((int)A.size() != N || (int)B.size() != N) return false;\n        for (int i = 0; i < N; i++) if (A[i] != B[i]) return false;\n        return true;\n    }\n\n    void addUniqueState(vector<vector<char>>& vec, const vector<char>& st) {\n        for (auto& v : vec) if (sameState(v, st)) return;\n        vec.push_back(st);\n    }\n\n    void pushPool(vector<pair<ll, vector<char>>>& pool, const vector<char>& st, ll cost, int lim = 14) {\n        for (auto& p : pool) {\n            if (sameState(p.second, st)) {\n                if (cost < p.first) p.first = cost;\n                sort(pool.begin(), pool.end(), [](auto& L, auto& R){ return L.first < R.first; });\n                if ((int)pool.size() > lim) pool.resize(lim);\n                return;\n            }\n        }\n        pool.push_back({cost, st});\n        sort(pool.begin(), pool.end(), [](auto& L, auto& R){ return L.first < R.first; });\n        if ((int)pool.size() > lim) pool.resize(lim);\n    }\n\n    void readInput() {\n        cin >> N >> M >> K;\n        x.resize(N); y.resize(N);\n        for (int i = 0; i < N; i++) cin >> x[i] >> y[i];\n\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(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            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        }\n\n        a.resize(K); b.resize(K);\n        for (int k = 0; k < K; k++) cin >> a[k] >> b[k];\n\n        edgeOrder.resize(M);\n        iota(edgeOrder.begin(), edgeOrder.end(), 0);\n        sort(edgeOrder.begin(), edgeOrder.end(),\n             [&](int e1, int e2){ return edges[e1].w < edges[e2].w; });\n    }\n\n    void precomputeDistances() {\n        distSR.assign(N, vector<uint16_t>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                int d = ceilDistInt(x[i], y[i], a[k], b[k]);\n                if (d > 65535) d = 65535;\n                distSR[i][k] = (uint16_t)d;\n            }\n        }\n\n        cand.assign(K, {});\n        byStation.assign(N, {});\n        for (int k = 0; k < K; k++) {\n            auto& v = cand[k];\n            v.reserve(N);\n            for (int i = 0; i < N; i++) {\n                int d = distSR[i][k];\n                if (d <= RAD) v.push_back({(uint16_t)d, i});\n            }\n            sort(v.begin(), v.end(), [](auto& L, auto& R){\n                if (L.first != R.first) return L.first < R.first;\n                return L.second < R.second;\n            });\n\n            if (v.empty()) {\n                int bestI = 0, bestD = INT_MAX;\n                for (int i = 0; i < N; i++) {\n                    int d = distSR[i][k];\n                    if (d < bestD) bestD = d, bestI = i;\n                }\n                v.push_back({(uint16_t)bestD, bestI});\n            }\n\n            for (auto& pr : v) byStation[pr.second].push_back({pr.first, k});\n        }\n\n        coverResidents.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            auto& bs = byStation[i];\n            sort(bs.begin(), bs.end(), [](auto& L, auto& R){\n                if (L.first != R.first) return L.first < R.first;\n                return L.second < R.second;\n            });\n            coverResidents[i].reserve(bs.size());\n            for (auto& pr : bs) coverResidents[i].push_back(pr.second);\n        }\n    }\n\n    void precomputeShortestPaths() {\n        spDist.assign(N, vector<ll>(N, INF));\n        prevNode.assign(N, vector<int>(N, -1));\n        prevEdge.assign(N, vector<int>(N, -1));\n\n        for (int s = 0; s < N; s++) {\n            vector<ll> d(N, INF);\n            priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n            d[s] = 0;\n            prevNode[s][s] = s;\n            prevEdge[s][s] = -1;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n                if (cd != d[v]) continue;\n                for (auto [to, eid] : g[v]) {\n                    ll nd = cd + edges[eid].w;\n                    if (nd < d[to]) {\n                        d[to] = nd;\n                        prevNode[s][to] = v;\n                        prevEdge[s][to] = eid;\n                        pq.push({nd, to});\n                    }\n                }\n            }\n\n            spDist[s] = move(d);\n        }\n\n        rootPen.assign(N, 0.0);\n        for (int i = 0; i < N; i++) rootPen[i] = (double)spDist[0][i] / 1000.0;\n    }\n\n    void buildStaticAddOrder() {\n        addOrderStatic.clear();\n        for (int i = 1; i < N; i++) addOrderStatic.push_back(i);\n        sort(addOrderStatic.begin(), addOrderStatic.end(), [&](int i, int j){\n            long long si = 100000LL * (long long)coverResidents[i].size() - spDist[0][i] / 1000;\n            long long sj = 100000LL * (long long)coverResidents[j].size() - spDist[0][j] / 1000;\n            if (si != sj) return si > sj;\n            return i < j;\n        });\n    }\n\n    // ---------- assignment / power ----------\n    bool buildPNearest(const vector<char>& active, int P[]) {\n        for (int i = 0; i < N; i++) P[i] = 0;\n        for (int k = 0; k < K; k++) {\n            int chosen = -1, d = 0;\n            for (auto& pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return false;\n            if (d > P[chosen]) P[chosen] = d;\n        }\n        return true;\n    }\n\n    bool buildAssignNearest(const vector<char>& active, vector<int>& assign, vector<int>& P) {\n        assign.assign(K, -1);\n        P.assign(N, 0);\n        for (int k = 0; k < K; k++) {\n            int chosen = -1, d = 0;\n            for (auto& pr : cand[k]) {\n                int st = pr.second;\n                if (active[st]) {\n                    chosen = st;\n                    d = pr.first;\n                    break;\n                }\n            }\n            if (chosen == -1) return false;\n            assign[k] = chosen;\n            if (d > P[chosen]) P[chosen] = d;\n        }\n        return true;\n    }\n\n    bool buildAssignWeighted(const vector<char>& active, double lambda, vector<int>& assign, vector<int>& P) {\n        assign.assign(K, -1);\n        P.assign(N, 0);\n\n        for (int k = 0; k < K; k++) {\n            int bestSt = -1;\n            int bestD = INT_MAX;\n            double bestSc = 1e100;\n\n            for (auto& pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                if (!active[st]) continue;\n                double sc = 1.0 * d * d + lambda * rootPen[st];\n                if (sc < bestSc - 1e-12 || (fabs(sc - bestSc) <= 1e-12 && d < bestD)) {\n                    bestSc = sc;\n                    bestD = d;\n                    bestSt = st;\n                }\n            }\n\n            if (bestSt == -1) return false;\n            assign[k] = bestSt;\n            if (bestD > P[bestSt]) P[bestSt] = bestD;\n        }\n\n        return true;\n    }\n\n    bool buildAssignIncremental(const vector<char>& active, double alpha, vector<int>& assign, vector<int>& P) {\n        vector<pair<int,int>> ord; // (-difficulty, resident)\n        ord.reserve(K);\n\n        for (int k = 0; k < K; k++) {\n            int nd = RAD + 1;\n            for (auto& pr : cand[k]) {\n                if (active[pr.second]) {\n                    nd = pr.first;\n                    break;\n                }\n            }\n            if (nd > RAD) return false;\n            ord.push_back({-nd, k});\n        }\n        sort(ord.begin(), ord.end());\n\n        assign.assign(K, -1);\n        P.assign(N, 0);\n\n        for (auto [negd, k] : ord) {\n            (void)negd;\n            int bestSt = -1;\n            int bestD = INT_MAX;\n            double bestSc = 1e100;\n\n            for (auto& pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                if (!active[st]) continue;\n\n                int oldP = P[st];\n                int newP = max(oldP, d);\n                double delta = 1.0 * newP * newP - 1.0 * oldP * oldP;\n                if (oldP == 0) delta += alpha * rootPen[st];\n\n                if (delta < bestSc - 1e-12 || (fabs(delta - bestSc) <= 1e-12 && d < bestD)) {\n                    bestSc = delta;\n                    bestD = d;\n                    bestSt = st;\n                }\n            }\n\n            if (bestSt == -1) return false;\n            assign[k] = bestSt;\n            P[bestSt] = max(P[bestSt], bestD);\n        }\n\n        return true;\n    }\n\n    void shrinkPArray(int P[], bool full) {\n        vector<int> cnt(K, 0);\n\n        for (int i = 0; i < N; i++) {\n            int pi = P[i];\n            if (pi <= 0) continue;\n            for (auto& pr : byStation[i]) {\n                int d = pr.first, k = pr.second;\n                if (d > pi) break;\n                cnt[k]++;\n            }\n        }\n\n        int maxPass = full ? 1000 : 2;\n        for (int pass = 0; pass < maxPass; pass++) {\n            bool changed = false;\n            for (int i = 0; i < N; i++) {\n                int old = P[i];\n                if (old <= 0) continue;\n\n                int req = 0;\n                for (auto& pr : byStation[i]) {\n                    int d = pr.first, k = pr.second;\n                    if (d > old) break;\n                    if (cnt[k] == 1 && d > req) req = d;\n                }\n\n                if (req < old) {\n                    for (auto& pr : byStation[i]) {\n                        int d = pr.first, k = pr.second;\n                        if (d > old) break;\n                        if (d > req) cnt[k]--;\n                    }\n                    P[i] = req;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void shrinkPVec(vector<int>& P, bool full) {\n        int arr[MAXN];\n        for (int i = 0; i < N; i++) arr[i] = P[i];\n        shrinkPArray(arr, full);\n        for (int i = 0; i < N; i++) P[i] = arr[i];\n    }\n\n    void rebalancePower(const vector<char>& active, vector<int>& assign, vector<int>& P, int passes) {\n        vector<array<uint16_t, RAD + 1>> freq(N);\n        for (int i = 0; i < N; i++) freq[i].fill(0);\n\n        vector<int> maxD(N, 0);\n        for (int k = 0; k < K; k++) {\n            int s = assign[k];\n            int d = distSR[s][k];\n            freq[s][d]++;\n            if (d > maxD[s]) maxD[s] = d;\n        }\n\n        vector<int> ord(K);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            sort(ord.begin(), ord.end(), [&](int l, int r){\n                int dl = distSR[assign[l]][l];\n                int dr = distSR[assign[r]][r];\n                if (dl != dr) return dl > dr;\n                return l < r;\n            });\n\n            bool changed = false;\n\n            for (int k : ord) {\n                int s = assign[k];\n                int ds = distSR[s][k];\n                int oldPs = maxD[s];\n\n                int newPs = oldPs;\n                if (ds == oldPs && freq[s][ds] == 1) {\n                    int v = oldPs - 1;\n                    while (v > 0 && freq[s][v] == 0) --v;\n                    newPs = v;\n                }\n\n                ll bestDelta = 0;\n                int bestT = -1, bestDt = 0;\n\n                for (auto& pr : cand[k]) {\n                    int dt = pr.first, t = pr.second;\n                    if (t == s || !active[t]) continue;\n\n                    int oldPt = maxD[t];\n                    int newPt = max(oldPt, dt);\n                    ll delta = 1LL * newPs * newPs + 1LL * newPt * newPt\n                             - 1LL * oldPs * oldPs - 1LL * oldPt * oldPt;\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestT = t;\n                        bestDt = dt;\n                    }\n                }\n\n                if (bestT != -1) {\n                    if (freq[s][ds] > 0) freq[s][ds]--;\n                    if (ds == oldPs && freq[s][ds] == 0) maxD[s] = newPs;\n\n                    assign[k] = bestT;\n                    freq[bestT][bestDt]++;\n                    if (bestDt > maxD[bestT]) maxD[bestT] = bestDt;\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        P = maxD;\n    }\n\n    void makeTerminalsAndPower(const vector<int>& P, int terminals[], int& t, ll& power) {\n        power = 0;\n        t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n    }\n\n    // ---------- steiner ----------\n    ll pruneAlive(vector<char>& alive, const vector<int>& terminals) {\n        vector<int> deg(N, 0);\n        vector<char> isTerm(N, 0);\n        for (int v : terminals) isTerm[v] = 1;\n\n        ll cost = 0;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            cost += edges[eid].w;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        return cost;\n    }\n\n    ll treeifyAndPrune(vector<char>& alive, const vector<int>& terminals) {\n        vector<char> tree(M, 0);\n        DSU dsu(N);\n\n        for (int eid : edgeOrder) {\n            if (!alive[eid]) continue;\n            auto& e = edges[eid];\n            if (dsu.merge(e.u, e.v)) tree[eid] = 1;\n        }\n\n        int rt = dsu.find(terminals[0]);\n        for (int t : terminals) {\n            if (dsu.find(t) != rt) return INF;\n        }\n\n        alive.swap(tree);\n        return pruneAlive(alive, terminals);\n    }\n\n    ll improveByEdgeExchange(vector<char>& alive, const vector<int>& terminals) {\n        ll cur = treeifyAndPrune(alive, terminals);\n        if (cur >= INF / 2) return INF;\n\n        vector<int> parV(N), parE(N);\n\n        for (int it = 0; it < 20; it++) {\n            vector<vector<pair<int,int>>> tadj(N);\n            for (int eid = 0; eid < M; eid++) {\n                if (!alive[eid]) continue;\n                int u = edges[eid].u, v = edges[eid].v;\n                tadj[u].push_back({v, eid});\n                tadj[v].push_back({u, eid});\n            }\n\n            bool changed = false;\n\n            for (int eid : edgeOrder) {\n                if (alive[eid]) continue;\n\n                int s = edges[eid].u;\n                int t = edges[eid].v;\n\n                fill(parV.begin(), parV.end(), -1);\n                fill(parE.begin(), parE.end(), -1);\n\n                queue<int> q;\n                parV[s] = s;\n                q.push(s);\n\n                while (!q.empty() && parV[t] == -1) {\n                    int v = q.front(); q.pop();\n                    for (auto [to, te] : tadj[v]) {\n                        if (parV[to] != -1) continue;\n                        parV[to] = v;\n                        parE[to] = te;\n                        q.push(to);\n                    }\n                }\n\n                if (parV[t] == -1) continue;\n\n                int curv = t;\n                int mx = -1;\n                while (curv != s) {\n                    int pe = parE[curv];\n                    if (mx == -1 || edges[pe].w > edges[mx].w) mx = pe;\n                    curv = parV[curv];\n                }\n\n                if (mx != -1 && edges[eid].w < edges[mx].w) {\n                    alive[mx] = 0;\n                    alive[eid] = 1;\n                    cur += 1LL * edges[eid].w - edges[mx].w;\n                    changed = true;\n                    break;\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        cur = treeifyAndPrune(alive, terminals);\n        return cur;\n    }\n\n    ll steinerKMB(const int terminals[], int t, vector<char>* outB) {\n        if (outB) outB->assign(M, 0);\n        if (t <= 1) return 0;\n\n        ll minD[MAXN];\n        int parent[MAXN];\n        bool used[MAXN];\n\n        for (int i = 0; i < t; i++) {\n            minD[i] = INF;\n            parent[i] = -1;\n            used[i] = false;\n        }\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 (!used[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            if (v == -1) return INF;\n            used[v] = true;\n\n            int tv = terminals[v];\n            for (int j = 0; j < t; j++) {\n                if (used[j]) continue;\n                ll nd = spDist[tv][terminals[j]];\n                if (nd < minD[j]) {\n                    minD[j] = nd;\n                    parent[j] = v;\n                }\n            }\n        }\n\n        unsigned char marked[MAXM] = {};\n        unsigned char alive[MAXM] = {};\n\n        for (int i = 1; i < t; i++) {\n            int s = terminals[parent[i]];\n            int cur = terminals[i];\n            while (cur != s) {\n                int eid = prevEdge[s][cur];\n                if (eid < 0) return INF;\n                marked[eid] = 1;\n                cur = prevNode[s][cur];\n            }\n        }\n\n        DSU dsu(N);\n        ll cost = 0;\n        for (int eid : edgeOrder) {\n            if (!marked[eid]) continue;\n            auto& e = edges[eid];\n            if (dsu.merge(e.u, e.v)) {\n                alive[eid] = 1;\n                cost += e.w;\n            }\n        }\n\n        int rt = dsu.find(terminals[0]);\n        for (int i = 1; i < t; i++) {\n            if (dsu.find(terminals[i]) != rt) return INF;\n        }\n\n        int deg[MAXN] = {};\n        bool isTerm[MAXN] = {};\n        for (int i = 0; i < t; i++) isTerm[terminals[i]] = true;\n        for (int eid = 0; eid < M; eid++) {\n            if (!alive[eid]) continue;\n            deg[edges[eid].u]++;\n            deg[edges[eid].v]++;\n        }\n\n        deque<int> q;\n        for (int v = 0; v < N; v++) if (!isTerm[v] && deg[v] == 1) q.push_back(v);\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop_front();\n            if (isTerm[v] || deg[v] != 1) continue;\n\n            int rem = -1, to = -1;\n            for (int eid : incident[v]) {\n                if (!alive[eid]) continue;\n                rem = eid;\n                to = (edges[eid].u == v ? edges[eid].v : edges[eid].u);\n                break;\n            }\n            if (rem == -1) continue;\n\n            alive[rem] = 0;\n            cost -= edges[rem].w;\n            deg[v]--;\n            deg[to]--;\n            if (!isTerm[to] && deg[to] == 1) q.push_back(to);\n        }\n\n        if (outB) {\n            outB->assign(M, 0);\n            for (int eid = 0; eid < M; eid++) if (alive[eid]) (*outB)[eid] = 1;\n        }\n\n        return cost;\n    }\n\n    ll steinerRootUnion(const vector<int>& terminals, vector<char>& outB) {\n        outB.assign(M, 0);\n        for (int t : terminals) {\n            if (t == 0) continue;\n            int cur = t;\n            while (cur != 0) {\n                int eid = prevEdge[0][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[0][cur];\n            }\n        }\n        return treeifyAndPrune(outB, terminals);\n    }\n\n    ll steinerSPH(const vector<int>& terminals, int startTerm, vector<char>& outB) {\n        outB.assign(M, 0);\n        if ((int)terminals.size() <= 1) return 0;\n\n        vector<char> isTerm(N, 0), inTree(N, 0);\n        for (int t : terminals) isTerm[t] = 1;\n        if (!isTerm[startTerm]) startTerm = 0;\n        inTree[startTerm] = 1;\n\n        while (true) {\n            ll bestD = INF;\n            int bestSrc = -1, bestTerm = -1;\n\n            for (int t : terminals) {\n                if (inTree[t]) continue;\n                for (int v = 0; v < N; v++) {\n                    if (!inTree[v]) continue;\n                    ll d = spDist[v][t];\n                    if (d < bestD) {\n                        bestD = d;\n                        bestSrc = v;\n                        bestTerm = t;\n                    }\n                }\n            }\n\n            if (bestTerm == -1) break;\n\n            int cur = bestTerm;\n            inTree[cur] = 1;\n            while (cur != bestSrc) {\n                int eid = prevEdge[bestSrc][cur];\n                if (eid < 0) return INF;\n                outB[eid] = 1;\n                cur = prevNode[bestSrc][cur];\n                inTree[cur] = 1;\n            }\n        }\n\n        return treeifyAndPrune(outB, terminals);\n    }\n\n    ll steinerBestFinal(const int terminals[], int t, vector<char>* outB) {\n        if (outB) outB->assign(M, 0);\n        if (t <= 1) return 0;\n\n        vector<int> tv(terminals, terminals + t);\n\n        ll best = INF;\n        vector<char> bestB(M, 0);\n        vector<vector<char>> candBs;\n\n        auto consider = [&](ll c, const vector<char>& b) {\n            if (c >= INF / 2) return;\n            candBs.push_back(b);\n            if (c < best) {\n                best = c;\n                bestB = b;\n            }\n        };\n\n        {\n            vector<char> b;\n            ll c = steinerKMB(terminals, t, &b);\n            consider(c, b);\n        }\n\n        {\n            vector<char> b;\n            ll c = steinerRootUnion(tv, b);\n            consider(c, b);\n        }\n\n        int far = -1, near = -1, med = -1;\n        ll farD = -1, nearD = INF, medSum = INF;\n        for (int v : tv) {\n            ll d = spDist[0][v];\n            if (d > farD) farD = d, far = v;\n            if (v != 0 && d < nearD) nearD = d, near = v;\n        }\n        for (int v : tv) {\n            ll s = 0;\n            for (int u : tv) s += spDist[v][u];\n            if (s < medSum) medSum = s, med = v;\n        }\n\n        vector<int> starts = {0};\n        if (far != -1) starts.push_back(far);\n        if (near != -1) starts.push_back(near);\n        if (med != -1) starts.push_back(med);\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        for (int s : starts) {\n            vector<char> b;\n            ll c = steinerSPH(tv, s, b);\n            consider(c, b);\n        }\n\n        // union hybrid\n        if (!candBs.empty()) {\n            vector<char> uni(M, 0);\n            for (auto& b : candBs) {\n                for (int eid = 0; eid < M; eid++) if (b[eid]) uni[eid] = 1;\n            }\n            ll c = treeifyAndPrune(uni, tv);\n            if (c < best) {\n                best = c;\n                bestB = uni;\n            }\n        }\n\n        if (outB) *outB = bestB;\n        return best;\n    }\n\n    // ---------- evaluate ----------\n    ll evaluateFast(const vector<char>& active) {\n        Key key = makeKey(active);\n        auto it = cacheFast.find(key);\n        if (it != cacheFast.end()) return it->second;\n        if (cacheFast.size() > 150000) cacheFast.clear();\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) {\n            cacheFast.emplace(key, INF);\n            return INF;\n        }\n\n        ll power = 0;\n        int terminals[MAXN], t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge = steinerKMB(terminals, t, nullptr);\n        ll ret = (edge >= INF / 2 ? INF : power + edge);\n        cacheFast.emplace(key, ret);\n        return ret;\n    }\n\n    ll evaluateExactKMB(const vector<char>& active) {\n        Key key = makeKey(active);\n        auto it = cacheExact.find(key);\n        if (it != cacheExact.end()) return it->second;\n        if (cacheExact.size() > 100000) cacheExact.clear();\n\n        int P[MAXN];\n        if (!buildPNearest(active, P)) {\n            cacheExact.emplace(key, INF);\n            return INF;\n        }\n\n        shrinkPArray(P, true);\n\n        ll power = 0;\n        int terminals[MAXN], t = 0;\n        terminals[t++] = 0;\n        for (int i = 0; i < N; i++) {\n            power += 1LL * P[i] * P[i];\n            if (i != 0 && P[i] > 0) terminals[t++] = i;\n        }\n\n        ll edge = steinerKMB(terminals, t, nullptr);\n        ll ret = (edge >= INF / 2 ? INF : power + edge);\n        cacheExact.emplace(key, ret);\n        return ret;\n    }\n\n    // ---------- init helpers ----------\n    double initScore(int d, int st, double lambda) const {\n        return 1.0 * d * d + lambda * rootPen[st];\n    }\n\n    vector<char> makeInitStateAssign(double lambda) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto& pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    vector<char> makeInitStateRepair(double lambda, const vector<int>& order) {\n        vector<char> active(N, 0);\n        active[0] = 1;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            int k = order[idx];\n            bool ok = false;\n            for (auto& pr : cand[k]) {\n                if (active[pr.second]) { ok = true; break; }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto& pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n        return active;\n    }\n\n    void repairActive(vector<char>& active, double lambda) {\n        active[0] = 1;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (auto& pr : cand[k]) {\n                if (active[pr.second]) { ok = true; break; }\n            }\n            if (ok) continue;\n\n            int bestSt = cand[k][0].second;\n            double bestSc = 1e100;\n            for (auto& pr : cand[k]) {\n                int d = pr.first, st = pr.second;\n                double sc = initScore(d, st, lambda);\n                if (sc < bestSc) {\n                    bestSc = sc;\n                    bestSt = st;\n                }\n            }\n            active[bestSt] = 1;\n        }\n    }\n\n    vector<char> mixStates(const vector<char>& A, const vector<char>& B, int mode) {\n        vector<char> C(N, 0);\n        if (mode == 0) {\n            for (int i = 0; i < N; i++) C[i] = (A[i] & B[i]);\n        } else if (mode == 1) {\n            for (int i = 0; i < N; i++) C[i] = (A[i] | B[i]);\n        } else {\n            for (int i = 0; i < N; i++) C[i] = ((rng() & 1) ? A[i] : B[i]);\n        }\n        C[0] = 1;\n        return C;\n    }\n\n    // ---------- coverage ops ----------\n    bool initCoverCnt(const vector<char>& active, vector<int>& cnt) {\n        cnt.assign(K, 0);\n        for (int i = 0; i < N; i++) {\n            if (!active[i]) continue;\n            for (int k : coverResidents[i]) cnt[k]++;\n        }\n        for (int k = 0; k < K; k++) if (cnt[k] == 0) return false;\n        return true;\n    }\n\n    bool canOffCoverage(int st, const vector<int>& cnt) const {\n        for (int k : coverResidents[st]) if (cnt[k] == 1) return false;\n        return true;\n    }\n\n    bool canSwapCoverage(int offSt, int onSt, const vector<int>& cnt) const {\n        for (int k : coverResidents[offSt]) {\n            if (cnt[k] == 1 && distSR[onSt][k] > RAD) return false;\n        }\n        return true;\n    }\n\n    void applyOnCoverage(int st, vector<char>& active, vector<int>& cnt) {\n        if (active[st]) return;\n        active[st] = 1;\n        for (int k : coverResidents[st]) cnt[k]++;\n    }\n\n    void applyOffCoverage(int st, vector<char>& active, vector<int>& cnt) {\n        if (!active[st]) return;\n        active[st] = 0;\n        for (int k : coverResidents[st]) cnt[k]--;\n    }\n\n    void applySwapCoverage(int offSt, int onSt, vector<char>& active, vector<int>& cnt) {\n        active[offSt] = 0;\n        active[onSt] = 1;\n        for (int k : coverResidents[offSt]) cnt[k]--;\n        for (int k : coverResidents[onSt]) cnt[k]++;\n    }\n\n    int pickOn(const vector<char>& active) {\n        for (int tr = 0; tr < 24; tr++) {\n            int i = 1 + (rng() % (N - 1));\n            if (active[i]) return i;\n        }\n        for (int i = 1; i < N; i++) if (active[i]) return i;\n        return -1;\n    }\n\n    int pickOff(const vector<char>& active) {\n        for (int tr = 0; tr < 24; tr++) {\n            int i = 1 + (rng() % (N - 1));\n            if (!active[i]) return i;\n        }\n        for (int i = 1; i < N; i++) if (!active[i]) return i;\n        return -1;\n    }\n\n    // ---------- search ----------\n    pair<vector<char>, ll> greedyPrune(vector<char> active, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) {\n            repairActive(active, 0.05);\n            if (!initCoverCnt(active, cnt)) return {active, evaluateFast(active)};\n        }\n\n        ll cur = evaluateFast(active);\n\n        while (elapsed() < endTime) {\n            int P[MAXN];\n            if (!buildPNearest(active, P)) break;\n\n            vector<pair<ll,int>> rem;\n            rem.reserve(N);\n            for (int i = 1; i < N; i++) {\n                if (!active[i]) continue;\n                if (!canOffCoverage(i, cnt)) continue;\n                ll score = 1LL * P[i] * P[i] + spDist[0][i] / 8;\n                rem.push_back({score, i});\n            }\n            if (rem.empty()) break;\n\n            sort(rem.begin(), rem.end(), [](auto& L, auto& R){\n                if (L.first != R.first) return L.first > R.first;\n                return L.second < R.second;\n            });\n\n            ll best = cur;\n            int bestI = -1;\n            int tries = min<int>(12, rem.size());\n\n            for (int z = 0; z < tries && elapsed() < endTime; z++) {\n                int i = rem[z].second;\n                applyOffCoverage(i, active, cnt);\n                ll c = evaluateFast(active);\n                applyOnCoverage(i, active, cnt);\n                if (c < best) {\n                    best = c;\n                    bestI = i;\n                }\n            }\n\n            if (bestI == -1) break;\n            applyOffCoverage(bestI, active, cnt);\n            cur = best;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> hillClimbFeasible(vector<char> active, int rounds, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) {\n            repairActive(active, 0.05);\n            if (!initCoverCnt(active, cnt)) return {active, evaluateFast(active)};\n        }\n\n        ll cur = evaluateFast(active);\n\n        for (int rd = 0; rd < rounds && elapsed() < endTime; rd++) {\n            bool improved = false;\n\n            vector<int> ord;\n            ord.reserve(N - 1);\n            for (int i = 1; i < N; i++) ord.push_back(i);\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int i : ord) {\n                if (elapsed() >= endTime) break;\n                if (active[i] && !canOffCoverage(i, cnt)) continue;\n\n                active[i] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n\n                if (c < cur) {\n                    if (active[i]) applyOffCoverage(i, active, cnt);\n                    else applyOnCoverage(i, active, cnt);\n                    cur = c;\n                    improved = true;\n                    break;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> localSearchSwapFeasible(vector<char> active, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) {\n            repairActive(active, 0.05);\n            if (!initCoverCnt(active, cnt)) return {active, evaluateFast(active)};\n        }\n\n        ll cur = evaluateFast(active);\n\n        while (elapsed() < endTime) {\n            bool improved = false;\n\n            // 1-flip first improvement\n            vector<int> ord;\n            ord.reserve(N - 1);\n            for (int i = 1; i < N; i++) ord.push_back(i);\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int i : ord) {\n                if (elapsed() >= endTime) break;\n                if (active[i] && !canOffCoverage(i, cnt)) continue;\n\n                active[i] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n\n                if (c < cur) {\n                    if (active[i]) applyOffCoverage(i, active, cnt);\n                    else applyOnCoverage(i, active, cnt);\n                    cur = c;\n                    improved = true;\n                    break;\n                }\n            }\n\n            if (improved) continue;\n\n            // swap sampled\n            vector<int> on, off;\n            on.reserve(N); off.reserve(N);\n            for (int i = 1; i < N; i++) {\n                if (active[i]) on.push_back(i);\n                else off.push_back(i);\n            }\n            if (on.empty() || off.empty()) break;\n\n            ll best = cur;\n            int bi = -1, bj = -1;\n            int trials = min<int>(2200, (int)(1LL * on.size() * off.size()));\n\n            for (int tr = 0; tr < trials && elapsed() < endTime; tr++) {\n                int i = on[rng() % on.size()];\n                int j = off[rng() % off.size()];\n                if (!canSwapCoverage(i, j, cnt)) continue;\n\n                active[i] ^= 1;\n                active[j] ^= 1;\n                ll c = evaluateFast(active);\n                active[i] ^= 1;\n                active[j] ^= 1;\n\n                if (c < best) {\n                    best = c;\n                    bi = i;\n                    bj = j;\n                }\n            }\n\n            if (bi != -1) {\n                applySwapCoverage(bi, bj, active, cnt);\n                cur = best;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> annealSegment(vector<char> active, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.08);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) {\n            repairActive(active, 0.08);\n            if (!initCoverCnt(active, cnt)) return {active, evaluateFast(active)};\n        }\n\n        ll cur = evaluateFast(active);\n        if (cur >= INF / 2) return {active, cur};\n\n        vector<char> bestState = active;\n        ll best = cur;\n\n        double segStart = elapsed();\n        double segLen = max(1e-9, endTime - segStart);\n        const double T0 = 2.0e7;\n        const double T1 = 2.0e4;\n\n        while (elapsed() < endTime) {\n            double p = (elapsed() - segStart) / segLen;\n            p = max(0.0, min(1.0, p));\n            double temp = T0 * pow(T1 / T0, p);\n\n            bool doSwap = (rng() % 100 < 28);\n\n            if (!doSwap) {\n                int i = 1 + (rng() % (N - 1));\n                bool wasOn = active[i];\n\n                if (wasOn) {\n                    if (!canOffCoverage(i, cnt)) continue;\n                    applyOffCoverage(i, active, cnt);\n                    ll nxt = evaluateFast(active);\n                    ll delta = nxt - cur;\n\n                    bool acc = false;\n                    if (delta <= 0) acc = true;\n                    else {\n                        double z = -(double)delta / temp;\n                        if (z > -50.0 && rand01() < exp(z)) acc = true;\n                    }\n\n                    if (acc) cur = nxt;\n                    else applyOnCoverage(i, active, cnt);\n                } else {\n                    applyOnCoverage(i, active, cnt);\n                    ll nxt = evaluateFast(active);\n                    ll delta = nxt - cur;\n\n                    bool acc = false;\n                    if (delta <= 0) acc = true;\n                    else {\n                        double z = -(double)delta / temp;\n                        if (z > -50.0 && rand01() < exp(z)) acc = true;\n                    }\n\n                    if (acc) cur = nxt;\n                    else applyOffCoverage(i, active, cnt);\n                }\n            } else {\n                int offSt = pickOn(active);\n                int onSt = pickOff(active);\n                if (offSt == -1 || onSt == -1) continue;\n                if (!canSwapCoverage(offSt, onSt, cnt)) continue;\n\n                applySwapCoverage(offSt, onSt, active, cnt);\n                ll nxt = evaluateFast(active);\n                ll delta = nxt - cur;\n\n                bool acc = false;\n                if (delta <= 0) acc = true;\n                else {\n                    double z = -(double)delta / temp;\n                    if (z > -50.0 && rand01() < exp(z)) acc = true;\n                }\n\n                if (acc) cur = nxt;\n                else applySwapCoverage(onSt, offSt, active, cnt);\n            }\n\n            if (cur < best) {\n                best = cur;\n                bestState = active;\n            }\n        }\n\n        return {bestState, best};\n    }\n\n    pair<vector<char>, ll> exactRefineGuided(vector<char> active, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) {\n            repairActive(active, 0.05);\n            if (!initCoverCnt(active, cnt)) return {active, evaluateExactKMB(active)};\n        }\n\n        ll cur = evaluateExactKMB(active);\n        if (cur >= INF / 2) return {active, cur};\n\n        int rounds = 0;\n        while (elapsed() < endTime && rounds < 10) {\n            rounds++;\n            bool improved = false;\n\n            int Ptmp[MAXN];\n            bool okP = buildPNearest(active, Ptmp);\n\n            vector<int> remCand;\n            for (int i = 1; i < N; i++) {\n                if (active[i] && canOffCoverage(i, cnt)) remCand.push_back(i);\n            }\n\n            if (okP) {\n                sort(remCand.begin(), remCand.end(), [&](int i, int j){\n                    ll si = 4LL * Ptmp[i] * Ptmp[i] + spDist[0][i] / 10;\n                    ll sj = 4LL * Ptmp[j] * Ptmp[j] + spDist[0][j] / 10;\n                    if (si != sj) return si > sj;\n                    return i < j;\n                });\n            } else {\n                shuffle(remCand.begin(), remCand.end(), rng);\n            }\n\n            // remove\n            int removeTry = min<int>(22, remCand.size());\n            for (int idx = 0; idx < removeTry && elapsed() < endTime; idx++) {\n                int i = remCand[idx];\n                active[i] = 0;\n                ll c = evaluateExactKMB(active);\n                active[i] = 1;\n                if (c < cur) {\n                    applyOffCoverage(i, active, cnt);\n                    cur = c;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) continue;\n\n            // add\n            vector<int> addCand;\n            for (int j : addOrderStatic) {\n                if (!active[j]) addCand.push_back(j);\n                if ((int)addCand.size() >= 16) break;\n            }\n\n            for (int j : addCand) {\n                if (elapsed() >= endTime) break;\n                active[j] = 1;\n                ll c = evaluateExactKMB(active);\n                active[j] = 0;\n                if (c < cur) {\n                    applyOnCoverage(j, active, cnt);\n                    cur = c;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) continue;\n\n            // swap\n            int remLim = min<int>(8, remCand.size());\n            int addLim = min<int>(9, addCand.size());\n\n            ll best = cur;\n            int bi = -1, bj = -1;\n            int evals = 0;\n\n            for (int ii = 0; ii < remLim && elapsed() < endTime; ii++) {\n                int i = remCand[ii];\n                for (int jj = 0; jj < addLim && elapsed() < endTime; jj++) {\n                    if (evals >= 48) break;\n                    int j = addCand[jj];\n                    if (!canSwapCoverage(i, j, cnt)) continue;\n\n                    active[i] = 0;\n                    active[j] = 1;\n                    ll c = evaluateExactKMB(active);\n                    active[i] = 1;\n                    active[j] = 0;\n                    evals++;\n\n                    if (c < best) {\n                        best = c;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n                if (evals >= 48) break;\n            }\n\n            if (bi != -1) {\n                applySwapCoverage(bi, bj, active, cnt);\n                cur = best;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return {active, cur};\n    }\n\n    pair<vector<char>, ll> finalRemovePolish(vector<char> active, double endTime) {\n        active[0] = 1;\n        repairActive(active, 0.05);\n\n        vector<int> cnt;\n        if (!initCoverCnt(active, cnt)) return {active, INF};\n\n        ll cur = evaluateExactKMB(active);\n        if (cur >= INF / 2) return {active, cur};\n\n        while (elapsed() < endTime) {\n            int P[MAXN];\n            if (!buildPNearest(active, P)) break;\n\n            vector<pair<ll,int>> rem;\n            rem.reserve(N);\n            for (int i = 1; i < N; i++) {\n                if (!active[i]) continue;\n                if (!canOffCoverage(i, cnt)) continue;\n                ll score = 1LL * P[i] * P[i] + spDist[0][i] / 8;\n                rem.push_back({score, i});\n            }\n            if (rem.empty()) break;\n\n            sort(rem.begin(), rem.end(), [](auto& L, auto& R){\n                if (L.first != R.first) return L.first > R.first;\n                return L.second < R.second;\n            });\n\n            ll best = cur;\n            int bestI = -1;\n            int tries = min<int>(14, rem.size());\n\n            for (int z = 0; z < tries && elapsed() < endTime; z++) {\n                int i = rem[z].second;\n                applyOffCoverage(i, active, cnt);\n                ll c = evaluateExactKMB(active);\n                applyOnCoverage(i, active, cnt);\n                if (c < best) {\n                    best = c;\n                    bestI = i;\n                }\n            }\n\n            if (bestI == -1) break;\n            applyOffCoverage(bestI, active, cnt);\n            cur = best;\n        }\n\n        return {active, cur};\n    }\n\n    // ---------- final build ----------\n    Solution buildSolutionFromActive(\n        const vector<char>& activeIn,\n        bool strongEdge,\n        bool doRebalance,\n        bool needB,\n        bool tryWeighted,\n        bool tryIncremental\n    ) {\n        vector<char> active = activeIn;\n        active[0] = 1;\n\n        Solution best;\n        vector<vector<int>> Ppool;\n\n        auto addP = [&](const vector<int>& Q) {\n            for (auto& R : Ppool) if (R == Q) return;\n            Ppool.push_back(Q);\n        };\n\n        vector<int> assign, P;\n        if (buildAssignNearest(active, assign, P)) {\n            addP(P);\n            if (doRebalance) {\n                auto a2 = assign, p2 = P;\n                rebalancePower(active, a2, p2, 2);\n                addP(p2);\n            }\n        }\n\n        if (tryWeighted) {\n            static const double LAMS[] = {8.0, 25.0, 60.0};\n            for (double lam : LAMS) {\n                vector<int> aw, pw;\n                if (buildAssignWeighted(active, lam, aw, pw)) {\n                    addP(pw);\n                    if (doRebalance) {\n                        auto a2 = aw, p2 = pw;\n                        rebalancePower(active, a2, p2, 2);\n                        addP(p2);\n                    }\n                }\n            }\n        }\n\n        if (tryIncremental) {\n            static const double ALPHAS[] = {0.0, 15.0, 35.0};\n            for (double alpha : ALPHAS) {\n                vector<int> ai, pi;\n                if (buildAssignIncremental(active, alpha, ai, pi)) {\n                    addP(pi);\n                    if (doRebalance && alpha > 0.0) {\n                        auto a2 = ai, p2 = pi;\n                        rebalancePower(active, a2, p2, 2);\n                        addP(p2);\n                    }\n                }\n            }\n        }\n\n        if (Ppool.empty()) return best;\n\n        vector<vector<int>> shrunk(Ppool.size());\n        vector<pair<ll,int>> weakRank;\n\n        for (int idx = 0; idx < (int)Ppool.size(); idx++) {\n            shrunk[idx] = Ppool[idx];\n            shrinkPVec(shrunk[idx], true);\n\n            int terminals[MAXN], t = 0;\n            ll power = 0;\n            makeTerminalsAndPower(shrunk[idx], terminals, t, power);\n\n            ll e = steinerKMB(terminals, t, nullptr);\n            if (e >= INF / 2) continue;\n            weakRank.push_back({power + e, idx});\n        }\n\n        if (weakRank.empty()) return best;\n        sort(weakRank.begin(), weakRank.end());\n\n        auto acceptSolution = [&](const vector<int>& Q, ll edge, vector<char>* pb) {\n            ll power = 0;\n            for (int v : Q) power += 1LL * v * v;\n            ll total = power + edge;\n            if (!best.feasible || total < best.cost) {\n                best.feasible = true;\n                best.cost = total;\n                best.P = Q;\n                if (needB && pb) best.B = *pb;\n                else best.B.clear();\n            }\n        };\n\n        if (!strongEdge) {\n            int idx = weakRank[0].second;\n            int terminals[MAXN], t = 0;\n            ll power = 0;\n            makeTerminalsAndPower(shrunk[idx], terminals, t, power);\n\n            vector<char> Btmp;\n            ll edge = steinerKMB(terminals, t, needB ? &Btmp : nullptr);\n            if (edge < INF / 2) acceptSolution(shrunk[idx], edge, needB ? &Btmp : nullptr);\n            return best;\n        }\n\n        int top = min<int>(tryWeighted || tryIncremental ? 3 : 2, weakRank.size());\n        for (int r = 0; r < top; r++) {\n            int idx = weakRank[r].second;\n            const auto& Q = shrunk[idx];\n\n            int terminals[MAXN], t = 0;\n            ll powerDummy = 0;\n            makeTerminalsAndPower(Q, terminals, t, powerDummy);\n            vector<int> tv(terminals, terminals + t);\n\n            vector<char> Btmp;\n            ll edge = steinerBestFinal(terminals, t, &Btmp);\n            if (edge >= INF / 2) continue;\n\n            ll improved = improveByEdgeExchange(Btmp, tv);\n            if (improved < edge) edge = improved;\n\n            if (edge < INF / 2) acceptSolution(Q, edge, &Btmp);\n        }\n\n        if (!best.feasible) {\n            int idx = weakRank[0].second;\n            int terminals[MAXN], t = 0;\n            ll power = 0;\n            makeTerminalsAndPower(shrunk[idx], terminals, t, power);\n\n            vector<char> Btmp;\n            ll edge = steinerKMB(terminals, t, needB ? &Btmp : nullptr);\n            if (edge < INF / 2) acceptSolution(shrunk[idx], edge, needB ? &Btmp : nullptr);\n        }\n\n        return best;\n    }\n\n    void ensureB(Solution& sol) {\n        if ((int)sol.B.size() == M) return;\n        if ((int)sol.P.size() != N) sol.P.assign(N, 0);\n\n        int terminals[MAXN], t = 0;\n        terminals[t++] = 0;\n        for (int i = 1; i < N; i++) if (sol.P[i] > 0) terminals[t++] = i;\n\n        vector<char> B;\n        ll c = steinerKMB(terminals, t, &B);\n        if (c >= INF / 2 || (int)B.size() != M) B.assign(M, 0);\n        sol.B = move(B);\n    }\n\n    void solve() {\n        readInput();\n        startTime = chrono::steady_clock::now();\n\n        precomputeDistances();\n        precomputeShortestPaths();\n        buildStaticAddOrder();\n\n        cacheFast.reserve(1 << 16);\n        cacheExact.reserve(1 << 15);\n        cacheFast.max_load_factor(0.7f);\n        cacheExact.max_load_factor(0.7f);\n\n        vector<char> allOn(N, 1);\n        allOn[0] = 1;\n\n        ll bestFastCost = evaluateFast(allOn);\n        vector<char> bestFastState = allOn;\n\n        vector<pair<ll, vector<char>>> pool;\n        if (bestFastCost < INF / 2) pushPool(pool, allOn, bestFastCost, 14);\n\n        const double T_INIT  = 0.40;\n        const double T_SWAP  = 0.95;\n        const double T_KICK  = 1.45;\n        const double T_MIX   = 1.58;\n        const double T_EXACT = 1.90;\n\n        // initial states\n        vector<int> ord(K), ordRev, ordRnd1, ordRnd2;\n        iota(ord.begin(), ord.end(), 0);\n        ordRev = ord;\n        reverse(ordRev.begin(), ordRev.end());\n        ordRnd1 = ord; shuffle(ordRnd1.begin(), ordRnd1.end(), rng);\n        ordRnd2 = ord; shuffle(ordRnd2.begin(), ordRnd2.end(), rng);\n\n        vector<vector<char>> inits;\n        addUniqueState(inits, allOn);\n        for (double lam : {0.00, 0.02, 0.05, 0.10, 0.20}) addUniqueState(inits, makeInitStateAssign(lam));\n        for (double lam : {0.00, 0.04, 0.10, 0.20}) {\n            addUniqueState(inits, makeInitStateRepair(lam, ord));\n            addUniqueState(inits, makeInitStateRepair(lam, ordRev));\n        }\n        addUniqueState(inits, makeInitStateRepair(0.08, ordRnd1));\n        addUniqueState(inits, makeInitStateRepair(0.12, ordRnd2));\n\n        // init phase\n        for (auto st : inits) {\n            if (elapsed() >= T_INIT) break;\n            repairActive(st, 0.05);\n\n            auto gp = greedyPrune(st, min(T_INIT, elapsed() + 0.02));\n            auto hc = hillClimbFeasible(gp.first, 8, T_INIT);\n\n            if (hc.second < bestFastCost) {\n                bestFastCost = hc.second;\n                bestFastState = hc.first;\n            }\n            if (hc.second < INF / 2) pushPool(pool, hc.first, hc.second, 14);\n        }\n\n        if (pool.empty()) {\n            ll c = evaluateFast(bestFastState);\n            if (c < INF / 2) pushPool(pool, bestFastState, c, 14);\n        }\n\n        // top intensify\n        if (elapsed() < T_SWAP) {\n            int use = min<int>(2, pool.size());\n            for (int i = 0; i < use && elapsed() < T_SWAP; i++) {\n                double lim = min(T_SWAP, elapsed() + (i == 0 ? 0.12 : 0.10));\n                auto res = localSearchSwapFeasible(pool[i].second, lim);\n                if (res.second < bestFastCost) {\n                    bestFastCost = res.second;\n                    bestFastState = res.first;\n                }\n                if (res.second < INF / 2) pushPool(pool, res.first, res.second, 14);\n            }\n        }\n\n        // kick + short climbs (+rare tiny SA)\n        while (elapsed() < T_KICK) {\n            vector<char> trial;\n            if (!pool.empty() && (rng() % 100) < 80) {\n                int lim = min<int>(5, pool.size());\n                trial = pool[rng() % lim].second;\n            } else {\n                trial = bestFastState;\n            }\n\n            int flips = 2 + (rng() % 3); // 2..4\n            for (int t = 0; t < flips; t++) {\n                int idx = 1 + (rng() % (N - 1));\n                trial[idx] ^= 1;\n            }\n            repairActive(trial, 0.08);\n\n            auto res = hillClimbFeasible(trial, 6, T_KICK);\n\n            if (elapsed() < T_KICK && (rng() % 100) < 20) {\n                double lim = min(T_KICK, elapsed() + 0.02);\n                auto sw = localSearchSwapFeasible(res.first, lim);\n                if (sw.second < res.second) res = sw;\n            } else if (elapsed() < T_KICK && (rng() % 100) < 10) {\n                double lim = min(T_KICK, elapsed() + 0.03);\n                auto sa = annealSegment(res.first, lim);\n                if (sa.second < res.second) res = sa;\n            }\n\n            if (res.second < bestFastCost) {\n                bestFastCost = res.second;\n                bestFastState = res.first;\n            }\n            if (res.second < INF / 2) pushPool(pool, res.first, res.second, 14);\n        }\n\n        // recombination\n        if (elapsed() < T_MIX && pool.size() >= 2) {\n            sort(pool.begin(), pool.end(), [](auto& L, auto& R){ return L.first < R.first; });\n\n            vector<vector<char>> seeds;\n            seeds.push_back(pool[0].second);\n            seeds.push_back(pool[1].second);\n            if ((int)pool.size() >= 3) seeds.push_back(pool[2].second);\n\n            vector<vector<char>> mixes;\n            mixes.push_back(mixStates(seeds[0], seeds[1], 0)); // AND\n            mixes.push_back(mixStates(seeds[0], seeds[1], 1)); // OR\n            mixes.push_back(mixStates(seeds[0], seeds[1], 2)); // random\n            if ((int)seeds.size() >= 3) mixes.push_back(mixStates(seeds[0], seeds[2], 2));\n\n            for (auto st : mixes) {\n                if (elapsed() >= T_MIX) break;\n                repairActive(st, 0.08);\n                auto hc = hillClimbFeasible(st, 4, T_MIX);\n                if (hc.second < bestFastCost) {\n                    bestFastCost = hc.second;\n                    bestFastState = hc.first;\n                }\n                if (hc.second < INF / 2) pushPool(pool, hc.first, hc.second, 14);\n            }\n        }\n\n        // exact candidates\n        vector<vector<char>> exactCand;\n        addUniqueState(exactCand, bestFastState);\n        addUniqueState(exactCand, allOn);\n        for (int i = 0; i < (int)pool.size() && i < 10; i++) addUniqueState(exactCand, pool[i].second);\n\n        vector<pair<ll, vector<char>>> exactPool;\n        for (auto st : exactCand) {\n            if (elapsed() > T_EXACT - 0.20) break;\n            repairActive(st, 0.05);\n            ll c = evaluateExactKMB(st);\n            if (c < INF / 2) pushPool(exactPool, st, c, 12);\n        }\n\n        if (exactPool.empty()) {\n            ll c = evaluateExactKMB(allOn);\n            if (c < INF / 2) pushPool(exactPool, allOn, c, 12);\n        }\n\n        sort(exactPool.begin(), exactPool.end(),\n             [](auto& L, auto& R){ return L.first < R.first; });\n\n        // exact polish top\n        vector<vector<char>> polished;\n        int polishCnt = min<int>(3, exactPool.size());\n        for (int i = 0; i < polishCnt && elapsed() < T_EXACT; i++) {\n            double slice = (i == 0 ? 0.12 : 0.09);\n            auto res = exactRefineGuided(exactPool[i].second, min(T_EXACT, elapsed() + slice));\n            ll c = evaluateExactKMB(res.first);\n            if (c < INF / 2) {\n                pushPool(exactPool, res.first, c, 12);\n                polished.push_back(res.first);\n            }\n        }\n\n        if (elapsed() < T_EXACT && !exactPool.empty()) {\n            sort(exactPool.begin(), exactPool.end(),\n                 [](auto& L, auto& R){ return L.first < R.first; });\n            auto rr = finalRemovePolish(exactPool[0].second, T_EXACT);\n            if (rr.second < INF / 2) {\n                pushPool(exactPool, rr.first, rr.second, 12);\n                polished.push_back(rr.first);\n            }\n        }\n\n        sort(exactPool.begin(), exactPool.end(),\n             [](auto& L, auto& R){ return L.first < R.first; });\n\n        vector<char> bestExactState = !exactPool.empty() ? exactPool[0].second : bestFastState;\n\n        // final states\n        vector<vector<char>> finals;\n        addUniqueState(finals, bestExactState);\n        addUniqueState(finals, bestFastState);\n        addUniqueState(finals, allOn);\n        for (auto& st : polished) addUniqueState(finals, st);\n        for (int i = 0; i < (int)exactPool.size() && i < 6; i++) addUniqueState(finals, exactPool[i].second);\n        for (int i = 0; i < (int)pool.size() && i < 4; i++) addUniqueState(finals, pool[i].second);\n\n        // rank by exact KMB\n        vector<pair<ll, vector<char>>> rankStates;\n        for (auto st : finals) {\n            if (elapsed() > 1.94) break;\n            repairActive(st, 0.05);\n            ll c = evaluateExactKMB(st);\n            if (c < INF / 2) rankStates.push_back({c, st});\n        }\n\n        if (rankStates.empty()) {\n            ll c = evaluateExactKMB(bestExactState);\n            if (c < INF / 2) rankStates.push_back({c, bestExactState});\n        }\n\n        sort(rankStates.begin(), rankStates.end(),\n             [](auto& L, auto& R){ return L.first < R.first; });\n\n        Solution bestSol;\n\n        // strong build on top states\n        int strongTry = min<int>(4, rankStates.size());\n        for (int i = 0; i < strongTry && elapsed() < 1.985; i++) {\n            auto st = rankStates[i].second;\n            bool rich = (i < 2);\n\n            auto sol1 = buildSolutionFromActive(st, true, false, true, rich, rich);\n            if (sol1.feasible && (!bestSol.feasible || sol1.cost < bestSol.cost)) bestSol = sol1;\n\n            if (i < 2 && elapsed() < 1.985) {\n                auto sol2 = buildSolutionFromActive(st, true, true, true, true, true);\n                if (sol2.feasible && (!bestSol.feasible || sol2.cost < bestSol.cost)) bestSol = sol2;\n            }\n        }\n\n        // one extra refinement from current P-support\n        if (bestSol.feasible && elapsed() < 1.99) {\n            vector<char> st(N, 0);\n            st[0] = 1;\n            for (int i = 1; i < N; i++) if (bestSol.P[i] > 0) st[i] = 1;\n\n            auto sol = buildSolutionFromActive(st, true, true, true, true, true);\n            if (sol.feasible && sol.cost < bestSol.cost) bestSol = sol;\n        }\n\n        // fallback\n        if (!bestSol.feasible) {\n            auto sol = buildSolutionFromActive(bestExactState, false, false, true, false, false);\n            if (sol.feasible) bestSol = sol;\n        }\n        if (!bestSol.feasible) {\n            auto sol = buildSolutionFromActive(allOn, true, true, true, true, true);\n            if (sol.feasible) bestSol = sol;\n        }\n        if (!bestSol.feasible) {\n            bestSol.feasible = true;\n            bestSol.P.assign(N, 0);\n            bestSol.B.assign(M, 0);\n        }\n\n        ensureB(bestSol);\n\n        // output\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << bestSol.P[i];\n        }\n        cout << '\\n';\n\n        for (int j = 0; j < M; j++) {\n            if (j) cout << ' ';\n            cout << int(bestSol.B[j]);\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}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int TOT = N * (N + 1) / 2; // 465\nstatic constexpr int MAXV = TOT - 1;\nstatic constexpr int INFK = 1e9;\n\nusing Board = array<array<int, N>, N>;\n\nstruct Move {\n    int x1, y1, x2, y2;\n};\n\nstruct Action {\n    uint8_t mode; // row order mode\n    uint8_t pm;   // path mode\n};\n\nusing Schedule = array<Action, N>;\n\nstruct EvalRes {\n    int K = INFK;\n    int E = INFK;\n    vector<Move> ops;\n};\n\nstruct SchedCand {\n    bool mirror = false;\n    Schedule sch{};\n    int k = INFK;\n    uint64_t key = 0;\n};\n\nstatic int POS_ID[N][N];\nstatic uint64_t ZOB[TOT][TOT];\n\nstatic uint64_t splitmix64(uint64_t& x) {\n    uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstatic void init_tables() {\n    for (int x = 0; x < N; ++x) for (int y = 0; y < N; ++y) POS_ID[x][y] = -1;\n    int id = 0;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) POS_ID[x][y] = id++;\n    }\n\n    uint64_t seed = 0x1234567890abcdefULL;\n    for (int p = 0; p < TOT; ++p) {\n        for (int v = 0; v < TOT; ++v) {\n            ZOB[p][v] = splitmix64(seed);\n        }\n    }\n}\n\nstatic inline bool same_unordered(const Move& a, const Move& b) {\n    return (a.x1 == b.x1 && a.y1 == b.y1 && a.x2 == b.x2 && a.y2 == b.y2) ||\n           (a.x1 == b.x2 && a.y1 == b.y2 && a.x2 == b.x1 && a.y2 == b.y1);\n}\n\nstatic vector<Move> compress_ops(const vector<Move>& ops) {\n    vector<Move> st;\n    st.reserve(ops.size());\n    for (const auto& mv : ops) {\n        if (!st.empty() && same_unordered(st.back(), mv)) st.pop_back();\n        else st.push_back(mv);\n    }\n    return st;\n}\n\nstatic inline int calcE(const Board& b) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            int p = b[x][y];\n            if (p > b[x + 1][y]) ++E;\n            if (p > b[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nstatic int calcE_after_ops(const Board& init, const vector<Move>& ops) {\n    Board b = init;\n    for (const auto& m : ops) swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    return calcE(b);\n}\n\nstatic Board mirror_board(const Board& init) {\n    Board b{};\n    for (int x = 0; x < N; ++x) for (int y = 0; y <= x; ++y) b[x][y] = init[x][x - y];\n    return b;\n}\n\nstatic void unmirror_ops(vector<Move>& ops) {\n    for (auto& m : ops) {\n        m.y1 = m.x1 - m.y1;\n        m.y2 = m.x2 - m.y2;\n    }\n}\n\nstatic inline int parent_threshold(const Board& b, int x, int y) {\n    if (x == 0) return -1;\n    int t = -1;\n    if (y > 0) t = max(t, b[x - 1][y - 1]);\n    if (y < x) t = max(t, b[x - 1][y]);\n    return t;\n}\n\nstatic inline void find_min_cone(const Board& b, int x, int y, int& sx, int& sy, int& val) {\n    val = INT_MAX;\n    sx = x;\n    sy = y;\n    for (int r = x; r < N; ++r) {\n        int cmax = y + (r - x);\n        for (int c = y; c <= cmax; ++c) {\n            int v = b[r][c];\n            if (v < val) {\n                val = v;\n                sx = r;\n                sy = c;\n            }\n        }\n    }\n}\n\n// row mode:\n// 0 asc\n// 1 desc\n// 2 edges-in\n// 3 center-out\n// 4 min source depth\n// 5 max source depth\n// 6 min source value\n// 7 parent-threshold asc\n// 8 parent-threshold desc\nstatic inline void build_order(const Board& b, int x, int mode, int ord[], int& len) {\n    len = x + 1;\n    if (mode < 0 || mode > 8) mode = 0;\n\n    if (mode == 0) {\n        for (int i = 0; i <= x; ++i) ord[i] = i;\n        return;\n    }\n    if (mode == 1) {\n        for (int i = 0; i <= x; ++i) ord[i] = x - i;\n        return;\n    }\n    if (mode == 2) {\n        int l = 0, r = x, k = 0;\n        while (l <= r) {\n            ord[k++] = l++;\n            if (l <= r) ord[k++] = r--;\n        }\n        return;\n    }\n    if (mode == 3) {\n        int k = 0;\n        int mid = x / 2;\n        ord[k++] = mid;\n        for (int d = 1; k <= x; ++d) {\n            int L = mid - d;\n            int R = mid + d;\n            if (L >= 0) ord[k++] = L;\n            if (k > x) break;\n            if (R <= x) ord[k++] = R;\n        }\n        return;\n    }\n\n    array<tuple<int, int, int>, N> key{};\n    for (int y = 0; y <= x; ++y) {\n        if (mode == 4 || mode == 5 || mode == 6) {\n            int sx, sy, val;\n            find_min_cone(b, x, y, sx, sy, val);\n            int dep = sx - x;\n            if (mode == 4) key[y] = {dep, val, y};\n            else if (mode == 5) key[y] = {-dep, val, y};\n            else key[y] = {val, dep, y};\n        } else {\n            int t = parent_threshold(b, x, y);\n            if (mode == 7) key[y] = {t, y, y};\n            else key[y] = {-t, y, y};\n        }\n    }\n\n    sort(key.begin(), key.begin() + len, [](const auto& a, const auto& b2) {\n        if (get<0>(a) != get<0>(b2)) return get<0>(a) < get<0>(b2);\n        if (get<1>(a) != get<1>(b2)) return get<1>(a) < get<1>(b2);\n        return get<2>(a) < get<2>(b2);\n    });\n\n    for (int i = 0; i < len; ++i) ord[i] = get<2>(key[i]);\n}\n\nstruct EdgeStack {\n    int st[12000];\n    int sz = 0;\n    inline void push_edge(int eid) {\n        if (sz > 0 && st[sz - 1] == eid) --sz;\n        else st[sz++] = eid;\n    }\n};\n\nstatic inline void apply_swap(\n    Board& b, int x1, int y1, int x2, int y2,\n    vector<Move>* ops, EdgeStack* es\n) {\n    swap(b[x1][y1], b[x2][y2]);\n\n    if (ops) {\n        Move mv{x1, y1, x2, y2};\n        if (!ops->empty() && same_unordered(ops->back(), mv)) ops->pop_back();\n        else ops->push_back(mv);\n    } else if (es) {\n        int p1 = POS_ID[x1][y1], p2 = POS_ID[x2][y2];\n        if (p1 > p2) swap(p1, p2);\n        int eid = p1 * TOT + p2;\n        es->push_edge(eid);\n    }\n}\n\n// Greedy path modes:\n// 0 left-priority\n// 1 right-priority\n// 2 larger-parent-down\n// 3 smaller-parent-down\nstatic int pull_greedy(\n    Board& b, int sx, int sy, int tx, int ty, int mode,\n    vector<Move>* ops, EdgeStack* es\n) {\n    int cx = sx, cy = sy;\n    int steps = 0;\n    while (cx > tx) {\n        int rem = cx - tx;\n        int delta = cy - ty;\n\n        bool canL = (delta > 0);\n        bool canR = (delta < rem);\n\n        bool goL;\n        if (canL && !canR) goL = true;\n        else if (!canL && canR) goL = false;\n        else {\n            int lv = b[cx - 1][cy - 1];\n            int rv = b[cx - 1][cy];\n            if (mode == 0) goL = true;\n            else if (mode == 1) goL = false;\n            else if (mode == 3) goL = (lv <= rv);\n            else goL = (lv >= rv);\n        }\n\n        int nx = cx - 1;\n        int ny = goL ? (cy - 1) : cy;\n        apply_swap(b, cx, cy, nx, ny, ops, es);\n        cx = nx;\n        cy = ny;\n        ++steps;\n    }\n    return steps;\n}\n\nstatic inline int dp_penalty(const Board& b, int r, int c, int mode) {\n    int v = b[r][c];\n    int small = MAXV - v;\n    if (mode == 4) return small;\n    if (mode == 5) return small * (N - r);\n\n    // mode == 6\n    int needAbove = r * (r + 1) / 2;\n    int late = max(0, needAbove - v);\n    return small + late * 8 + (N - r) * 2;\n}\n\n// DP path modes: 4/5/6\nstatic int pull_dp(\n    Board& b, int sx, int sy, int tx, int ty, int mode,\n    vector<Move>* ops, EdgeStack* es\n) {\n    int depth = sx - tx;\n    if (depth <= 1) return pull_greedy(b, sx, sy, tx, ty, 2, ops, es);\n\n    static int dist[N][N];\n    static int pred[N][N];\n    constexpr int INF = 1e9;\n\n    for (int r = tx; r <= sx; ++r) {\n        int cmin = ty;\n        int cmax = ty + (r - tx);\n        for (int c = cmin; c <= cmax; ++c) {\n            dist[r][c] = INF;\n            pred[r][c] = -1;\n        }\n    }\n    dist[tx][ty] = 0;\n\n    for (int r = tx + 1; r <= sx; ++r) {\n        int cmin = ty;\n        int cmax = ty + (r - tx);\n        for (int c = cmin; c <= cmax; ++c) {\n            int best = INF, bp = -1, bpv = -1;\n\n            if (c <= ty + (r - 1 - tx) && dist[r - 1][c] < INF) {\n                int cand = dist[r - 1][c] + dp_penalty(b, r - 1, c, mode);\n                int pv = b[r - 1][c];\n                if (cand < best || (cand == best && pv > bpv)) {\n                    best = cand;\n                    bp = c;\n                    bpv = pv;\n                }\n            }\n            if (c - 1 >= ty && dist[r - 1][c - 1] < INF) {\n                int cand = dist[r - 1][c - 1] + dp_penalty(b, r - 1, c - 1, mode);\n                int pv = b[r - 1][c - 1];\n                if (cand < best || (cand == best && pv > bpv)) {\n                    best = cand;\n                    bp = c - 1;\n                    bpv = pv;\n                }\n            }\n\n            dist[r][c] = best;\n            pred[r][c] = bp;\n        }\n    }\n\n    int cx = sx, cy = sy;\n    int steps = 0;\n    while (cx > tx) {\n        int pcy = pred[cx][cy];\n        if (pcy < 0) pcy = (cy > ty ? cy - 1 : cy);\n        apply_swap(b, cx, cy, cx - 1, pcy, ops, es);\n        cy = pcy;\n        --cx;\n        ++steps;\n    }\n    return steps;\n}\n\nstatic inline int do_pull(\n    Board& b, int sx, int sy, int tx, int ty, int pm,\n    vector<Move>* ops, EdgeStack* es\n) {\n    if (pm >= 4) return pull_dp(b, sx, sy, tx, ty, pm, ops, es);\n    return pull_greedy(b, sx, sy, tx, ty, pm, ops, es);\n}\n\nstatic int process_row(\n    Board& b, int x, int mode, int pm,\n    vector<Move>* ops, EdgeStack* es\n) {\n    int ord[N], len = 0;\n    build_order(b, x, mode, ord, len);\n\n    int steps = 0;\n    for (int i = 0; i < len; ++i) {\n        int y = ord[i];\n        int sx, sy, val;\n        find_min_cone(b, x, y, sx, sy, val);\n        steps += do_pull(b, sx, sy, x, y, pm, ops, es);\n    }\n    return steps;\n}\n\nstatic int estimate_depth_sum(const Board& b, int x) {\n    if (x >= N) return 0;\n    int s = 0;\n    for (int y = 0; y <= x; ++y) {\n        int sx, sy, val;\n        find_min_cone(b, x, y, sx, sy, val);\n        s += (sx - x);\n    }\n    return s;\n}\n\nstatic uint64_t hash_schedule(bool mirror, const Schedule& sch) {\n    uint64_t h = mirror ? 0x9e3779b97f4a7c15ULL : 0x123456789abcdef0ULL;\n    auto mix = [&](uint64_t x) {\n        h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    };\n    for (int x = 0; x < N; ++x) {\n        uint64_t v = ((uint64_t)sch[x].mode << 8) ^ (uint64_t)sch[x].pm;\n        mix(v);\n    }\n    return h;\n}\n\nstatic Schedule make_const_schedule(int mode, int pm) {\n    Schedule s{};\n    for (int x = 0; x < N; ++x) s[x] = Action{(uint8_t)mode, (uint8_t)pm};\n    return s;\n}\n\nstatic int run_schedule_eval(const Board& init, bool mirror, const Schedule& sch) {\n    Board b = mirror ? mirror_board(init) : init;\n    EdgeStack es;\n\n    for (int x = 0; x < N; ++x) {\n        process_row(b, x, (int)sch[x].mode, (int)sch[x].pm, nullptr, &es);\n        if (es.sz > 10000) return INFK;\n    }\n\n    int E = calcE(b);\n    if (E != 0) return INFK;\n    return es.sz;\n}\n\nstatic EvalRes run_schedule_output(const Board& init, bool mirror, const Schedule& sch) {\n    Board b = mirror ? mirror_board(init) : init;\n    vector<Move> ops;\n    ops.reserve(6500);\n\n    for (int x = 0; x < N; ++x) {\n        process_row(b, x, (int)sch[x].mode, (int)sch[x].pm, &ops, nullptr);\n    }\n\n    if (mirror) unmirror_ops(ops);\n    ops = compress_ops(ops);\n\n    EvalRes r;\n    r.K = (int)ops.size();\n    r.E = calcE(b);\n    r.ops = std::move(ops);\n    return r;\n}\n\ntemplate<class ElapsedFunc>\nstatic bool adapt_schedule_eval(\n    const Board& init, bool mirror, const Schedule& base, int alpha,\n    Schedule& out, int& outK,\n    ElapsedFunc&& elapsed, double deadline\n) {\n    Board b = mirror ? mirror_board(init) : init;\n    EdgeStack total;\n    out = base;\n\n    for (int x = 0; x < N; ++x) {\n        if (elapsed() > deadline) return false;\n\n        bool usedMode[9] = {};\n        bool usedPm[7] = {};\n        vector<int> modes;\n        vector<int> pms;\n        modes.reserve(9);\n        pms.reserve(7);\n\n        auto addM = [&](int m) {\n            if (0 <= m && m <= 8 && !usedMode[m]) {\n                usedMode[m] = true;\n                modes.push_back(m);\n            }\n        };\n        auto addP = [&](int p) {\n            if (0 <= p && p <= 6 && !usedPm[p]) {\n                usedPm[p] = true;\n                pms.push_back(p);\n            }\n        };\n\n        addM((int)base[x].mode);\n        for (int m : {0, 2, 3, 4, 6, 7, 5, 8, 1}) addM(m);\n\n        addP((int)base[x].pm);\n        addP(2); addP(4);\n        if (x >= 8) addP(5);\n        if (x >= 20) addP(6);\n        addP(0);\n\n        int limit = (x < 8 ? 20 : (x < 20 ? 32 : 44));\n\n        long long bestScore = (1LL << 62);\n        int bestRowK = INFK;\n        Action bestA{(uint8_t)modes[0], (uint8_t)pms[0]};\n\n        int tested = 0;\n        for (int m : modes) {\n            for (int pm : pms) {\n                if (elapsed() > deadline) return false;\n                Board tb = b;\n                EdgeStack row;\n                process_row(tb, x, m, pm, nullptr, &row);\n                int rowK = row.sz;\n                int h = (x + 1 < N ? estimate_depth_sum(tb, x + 1) : 0);\n                long long sc = 1000LL * rowK + 1LL * alpha * h;\n\n                if (sc < bestScore || (sc == bestScore && rowK < bestRowK)) {\n                    bestScore = sc;\n                    bestRowK = rowK;\n                    bestA = Action{(uint8_t)m, (uint8_t)pm};\n                }\n\n                ++tested;\n                if (tested >= limit) break;\n            }\n            if (tested >= limit) break;\n        }\n\n        out[x] = bestA;\n        process_row(b, x, (int)bestA.mode, (int)bestA.pm, nullptr, &total);\n        if (total.sz > 10000) {\n            outK = INFK;\n            return true;\n        }\n    }\n\n    int E = calcE(b);\n    outK = (E == 0 ? total.sz : INFK);\n    return true;\n}\n\nstatic void add_sched_pool(vector<SchedCand>& pool, const SchedCand& c, int pool_max) {\n    for (auto& e : pool) {\n        if (e.key == c.key) {\n            if (c.k < e.k) e = c;\n            return;\n        }\n    }\n\n    if ((int)pool.size() < pool_max) {\n        pool.push_back(c);\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < (int)pool.size(); ++i) {\n        if (pool[i].k > pool[worst].k) worst = i;\n    }\n    if (c.k < pool[worst].k) pool[worst] = c;\n}\n\nstatic uint64_t hash_board(const Board& b) {\n    uint64_t h = 0;\n    int id = 0;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            h ^= ZOB[id++][b[x][y]];\n        }\n    }\n    return h;\n}\n\n// canonicalization by repeated-state segment removal\nstatic vector<Move> canonicalize_ops_by_state(const Board& init, const vector<Move>& ops) {\n    Board b = init;\n    uint64_t h = hash_board(b);\n\n    vector<Move> out;\n    out.reserve(ops.size());\n\n    vector<uint64_t> states;\n    states.reserve(ops.size() + 1);\n    states.push_back(h);\n\n    unordered_map<uint64_t, int> pos;\n    pos.reserve(ops.size() * 2 + 16);\n    pos[h] = 0;\n\n    for (const auto& m : ops) {\n        int p1 = POS_ID[m.x1][m.y1];\n        int p2 = POS_ID[m.x2][m.y2];\n\n        int v1 = b[m.x1][m.y1];\n        int v2 = b[m.x2][m.y2];\n\n        h ^= ZOB[p1][v1] ^ ZOB[p1][v2] ^ ZOB[p2][v1] ^ ZOB[p2][v2];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n\n        auto it = pos.find(h);\n        if (it == pos.end()) {\n            out.push_back(m);\n            states.push_back(h);\n            pos.emplace(h, (int)out.size());\n        } else {\n            int keep = it->second;\n            while ((int)out.size() > keep) {\n                uint64_t hh = states.back();\n                pos.erase(hh);\n                states.pop_back();\n                out.pop_back();\n            }\n        }\n    }\n\n    return out;\n}\n\nstatic vector<Move> normalize_ops(const Board& init, vector<Move> ops) {\n    ops = compress_ops(ops);\n    ops = canonicalize_ops_by_state(init, ops);\n    ops = compress_ops(ops);\n    return ops;\n}\n\nstatic uint64_t hash_ops(const vector<Move>& ops) {\n    uint64_t h = 0xcbf29ce484222325ULL;\n    for (const auto& m : ops) {\n        uint64_t x = (uint64_t)m.x1\n                   | ((uint64_t)m.y1 << 6)\n                   | ((uint64_t)m.x2 << 12)\n                   | ((uint64_t)m.y2 << 18);\n        h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    }\n    return h;\n}\n\nstatic bool check_skip1(const Board& init, const vector<Move>& ops, int s1) {\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == s1) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b) == 0;\n}\n\nstatic bool check_skip2(const Board& init, const vector<Move>& ops, int s1, int s2) {\n    if (s1 > s2) swap(s1, s2);\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == s1 || i == s2) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b) == 0;\n}\n\nstatic bool check_skip3(const Board& init, const vector<Move>& ops, int a, int b0, int c) {\n    if (a > b0) swap(a, b0);\n    if (b0 > c) swap(b0, c);\n    if (a > b0) swap(a, b0);\n\n    Board b = init;\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (i == a || i == b0 || i == c) continue;\n        const auto& m = ops[i];\n        swap(b[m.x1][m.y1], b[m.x2][m.y2]);\n    }\n    return calcE(b) == 0;\n}\n\ntemplate<class ElapsedFunc>\nstatic void prune_ops(\n    const Board& init, vector<Move>& ops,\n    ElapsedFunc&& elapsed, double deadline,\n    mt19937& rng\n) {\n    if (ops.empty()) return;\n\n    ops = normalize_ops(init, std::move(ops));\n\n    // single forward\n    for (int i = 0; i < (int)ops.size(); ++i) {\n        if (elapsed() > deadline) return;\n        if (check_skip1(init, ops, i)) {\n            ops.erase(ops.begin() + i);\n            --i;\n        }\n    }\n\n    // adjacent pair\n    for (int i = 0; i + 1 < (int)ops.size(); ++i) {\n        if (elapsed() > deadline) return;\n        if (check_skip2(init, ops, i, i + 1)) {\n            ops.erase(ops.begin() + i, ops.begin() + i + 2);\n            i = max(-1, i - 2);\n        }\n    }\n\n    // random pair\n    for (int t = 0; t < 60; ++t) {\n        if (elapsed() > deadline) return;\n        int n = (int)ops.size();\n        if (n < 2) break;\n        int i = (int)(rng() % n), j = (int)(rng() % n);\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n        if (check_skip2(init, ops, i, j)) {\n            ops.erase(ops.begin() + j);\n            ops.erase(ops.begin() + i);\n        }\n    }\n\n    // random triple\n    for (int t = 0; t < 20; ++t) {\n        if (elapsed() > deadline) return;\n        int n = (int)ops.size();\n        if (n < 3) break;\n        int a = (int)(rng() % n), b0 = (int)(rng() % n), c = (int)(rng() % n);\n        if (a == b0 || b0 == c || a == c) continue;\n        if (check_skip3(init, ops, a, b0, c)) {\n            array<int, 3> idx{a, b0, c};\n            sort(idx.begin(), idx.end());\n            ops.erase(ops.begin() + idx[2]);\n            ops.erase(ops.begin() + idx[1]);\n            ops.erase(ops.begin() + idx[0]);\n        }\n    }\n\n    // single backward\n    for (int i = (int)ops.size() - 1; i >= 0; --i) {\n        if (elapsed() > deadline) return;\n        if (check_skip1(init, ops, i)) {\n            ops.erase(ops.begin() + i);\n        }\n    }\n\n    ops = normalize_ops(init, std::move(ops));\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    init_tables();\n\n    Board init{};\n    uint64_t seed = 1469598103934665603ULL;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n            seed ^= (uint64_t)(init[x][y] + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32) ^ 0x9e3779b9U));\n\n    using Clock = chrono::steady_clock;\n    const auto st = Clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(Clock::now() - st).count();\n    };\n\n    constexpr double SEARCH_T = 1.50;\n    constexpr double REFINE_T = 1.74;\n    constexpr double FINAL_T  = 1.90;\n\n    const int POOL_MAX = 20;\n    vector<SchedCand> pool;\n    pool.reserve(POOL_MAX + 12);\n\n    unordered_map<uint64_t, int> eval_cache; // fast schedule hash -> K (or INFK)\n    eval_cache.reserve(1 << 15);\n\n    auto eval_fast = [&](bool mirror, const Schedule& sch) -> int {\n        uint64_t key = hash_schedule(mirror, sch);\n        auto it = eval_cache.find(key);\n        if (it != eval_cache.end()) return it->second;\n\n        int k = run_schedule_eval(init, mirror, sch);\n        eval_cache.emplace(key, k);\n        return k;\n    };\n\n    auto try_add = [&](bool mirror, const Schedule& sch) {\n        int k = eval_fast(mirror, sch);\n        if (k >= INFK || k > 10000) return;\n        SchedCand c;\n        c.mirror = mirror;\n        c.sch = sch;\n        c.k = k;\n        c.key = hash_schedule(mirror, sch);\n        add_sched_pool(pool, c, POOL_MAX);\n    };\n\n    auto sort_pool = [&]() {\n        sort(pool.begin(), pool.end(), [](const SchedCand& a, const SchedCand& b) {\n            return a.k < b.k;\n        });\n    };\n\n    // safe baseline\n    try_add(false, make_const_schedule(0, 2));\n    try_add(true,  make_const_schedule(0, 2));\n\n    vector<int> modes_pref = {0, 2, 3, 4, 6, 7};\n    vector<int> pms_pref   = {2, 4, 5, 6};\n\n    // deterministic uniform seeds\n    for (int mir = 0; mir < 2 && elapsed() < SEARCH_T; ++mir) {\n        for (int m : modes_pref) {\n            if (elapsed() > SEARCH_T) break;\n            for (int pm : pms_pref) {\n                if (elapsed() > SEARCH_T) break;\n                try_add((bool)mir, make_const_schedule(m, pm));\n            }\n        }\n    }\n\n    auto make_zoned_mode_schedule = [&](int m0, int m1, int m2, int pm) {\n        Schedule s{};\n        for (int x = 0; x < N; ++x) {\n            int m = (x < 8 ? m0 : (x < 20 ? m1 : m2));\n            s[x] = Action{(uint8_t)m, (uint8_t)pm};\n        }\n        return s;\n    };\n    auto make_zoned_pm_schedule = [&](int mode, int p0, int p1, int p2) {\n        Schedule s{};\n        for (int x = 0; x < N; ++x) {\n            int pm = (x < 8 ? p0 : (x < 20 ? p1 : p2));\n            s[x] = Action{(uint8_t)mode, (uint8_t)pm};\n        }\n        return s;\n    };\n\n    vector<tuple<int,int,int>> mode_patterns = {\n        {0,2,4}, {3,2,0}, {7,2,5}, {0,6,5}, {2,3,2}\n    };\n    vector<array<int,3>> pm_patterns = {\n        array<int,3>{2,2,2},\n        array<int,3>{4,4,4},\n        array<int,3>{5,5,5},\n        array<int,3>{6,6,6},\n        array<int,3>{4,2,2},\n        array<int,3>{5,4,2},\n        array<int,3>{2,4,6}\n    };\n\n    // zoned seeds\n    for (int mir = 0; mir < 2 && elapsed() < SEARCH_T; ++mir) {\n        for (auto [a,b,c] : mode_patterns) {\n            if (elapsed() > SEARCH_T) break;\n            for (int pm : pms_pref) {\n                if (elapsed() > SEARCH_T) break;\n                try_add((bool)mir, make_zoned_mode_schedule(a,b,c,pm));\n            }\n        }\n    }\n    for (int mir = 0; mir < 2 && elapsed() < SEARCH_T; ++mir) {\n        for (int m : vector<int>{0,2,3,4}) {\n            if (elapsed() > SEARCH_T) break;\n            for (auto pp : pm_patterns) {\n                if (elapsed() > SEARCH_T) break;\n                try_add((bool)mir, make_zoned_pm_schedule(m, pp[0], pp[1], pp[2]));\n            }\n        }\n    }\n\n    if (pool.empty()) try_add(false, make_const_schedule(0, 2));\n    sort_pool();\n\n    // adaptive seeds\n    if (!pool.empty() && elapsed() < SEARCH_T) {\n        int top_adapt = min(2, (int)pool.size());\n        int alphas[] = {450, 750};\n\n        for (int i = 0; i < top_adapt && elapsed() < SEARCH_T; ++i) {\n            for (int a : alphas) {\n                if (elapsed() > SEARCH_T) break;\n                Schedule out;\n                int outK = INFK;\n                bool ok = adapt_schedule_eval(init, pool[i].mirror, pool[i].sch, a, out, outK, elapsed, SEARCH_T);\n                if (!ok) break;\n                if (outK < INFK) try_add(pool[i].mirror, out);\n            }\n        }\n    }\n\n    if (pool.empty()) try_add(false, make_const_schedule(0, 2));\n    sort_pool();\n\n    // hill climb\n    auto hill_climb = [&](SchedCand cur) {\n        for (int pass = 0; pass < 2 && elapsed() < SEARCH_T; ++pass) {\n            bool improved = false;\n\n            for (int dir = 0; dir < 2 && elapsed() < SEARCH_T; ++dir) {\n                for (int t = 0; t < N && elapsed() < SEARCH_T; ++t) {\n                    int x = (dir == 0 ? t : (N - 1 - t));\n\n                    // mode optimize\n                    int bestK = cur.k;\n                    uint8_t bestM = cur.sch[x].mode;\n                    for (int m = 0; m <= 8; ++m) {\n                        if (m == cur.sch[x].mode) continue;\n                        Schedule tmp = cur.sch;\n                        tmp[x].mode = (uint8_t)m;\n                        int nk = eval_fast(cur.mirror, tmp);\n                        if (nk < bestK) {\n                            bestK = nk;\n                            bestM = (uint8_t)m;\n                        }\n                    }\n                    if (bestM != cur.sch[x].mode) {\n                        cur.sch[x].mode = bestM;\n                        cur.k = bestK;\n                        improved = true;\n                    }\n\n                    // pm optimize\n                    bool used[7] = {};\n                    vector<int> pms;\n                    auto addP = [&](int p) {\n                        if (0 <= p && p <= 6 && !used[p]) {\n                            used[p] = true;\n                            pms.push_back(p);\n                        }\n                    };\n                    addP((int)cur.sch[x].pm);\n                    addP(2);\n                    addP(4);\n                    if (x >= 8) addP(5);\n                    if (x >= 20) addP(6);\n                    addP(0);\n\n                    bestK = cur.k;\n                    uint8_t bestP = cur.sch[x].pm;\n                    for (int pm : pms) {\n                        if (pm == cur.sch[x].pm) continue;\n                        Schedule tmp = cur.sch;\n                        tmp[x].pm = (uint8_t)pm;\n                        int nk = eval_fast(cur.mirror, tmp);\n                        if (nk < bestK) {\n                            bestK = nk;\n                            bestP = (uint8_t)pm;\n                        }\n                    }\n                    if (bestP != cur.sch[x].pm) {\n                        cur.sch[x].pm = bestP;\n                        cur.k = bestK;\n                        improved = true;\n                    }\n                }\n            }\n\n            // lower-row local tries\n            for (int tr = 0; tr < 8 && elapsed() < SEARCH_T; ++tr) {\n                Schedule tmp = cur.sch;\n                int l = 12 + (int)(rng() % (N - 12));\n                int len = 1 + (int)(rng() % 4);\n                if ((rng() % 100) < 70) {\n                    int m = (int)(rng() % 9);\n                    for (int x = l; x < N && x < l + len; ++x) tmp[x].mode = (uint8_t)m;\n                } else {\n                    int pm = (int)(rng() % 7);\n                    for (int x = l; x < N && x < l + len; ++x) tmp[x].pm = (uint8_t)pm;\n                }\n                int nk = eval_fast(cur.mirror, tmp);\n                if (nk < cur.k) {\n                    cur.sch = tmp;\n                    cur.k = nk;\n                    improved = true;\n                }\n            }\n\n            // mirror toggle\n            if (elapsed() < SEARCH_T) {\n                int nk = eval_fast(!cur.mirror, cur.sch);\n                if (nk < cur.k) {\n                    cur.mirror = !cur.mirror;\n                    cur.k = nk;\n                    improved = true;\n                }\n            }\n\n            cur.key = hash_schedule(cur.mirror, cur.sch);\n            add_sched_pool(pool, cur, POOL_MAX);\n\n            if (!improved) break;\n        }\n\n        cur.key = hash_schedule(cur.mirror, cur.sch);\n        return cur;\n    };\n\n    int starts = min(3, (int)pool.size());\n    for (int i = 0; i < starts && elapsed() < SEARCH_T; ++i) {\n        SchedCand c = hill_climb(pool[i]);\n        add_sched_pool(pool, c, POOL_MAX);\n    }\n\n    if (pool.empty()) try_add(false, make_const_schedule(0, 2));\n    sort_pool();\n\n    // mutation\n    int iter = 0;\n    while (elapsed() < SEARCH_T && !pool.empty()) {\n        if ((iter & 15) == 0) sort_pool();\n\n        int top = min(8, (int)pool.size());\n        const auto& base = pool[(int)(rng() % top)];\n        SchedCand c = base;\n\n        if ((rng() % 100) < 12) c.mirror = !c.mirror;\n\n        int mut = 1 + (int)(rng() % 4);\n        if ((rng() % 100) < 20) mut += 2;\n\n        for (int i = 0; i < mut; ++i) {\n            int x;\n            if ((rng() % 100) < 70) x = 12 + (int)(rng() % (N - 12));\n            else x = (int)(rng() % N);\n\n            int typ = (int)(rng() % 100);\n            if (typ < 60) c.sch[x].mode = (uint8_t)(rng() % 9);\n            else if (typ < 90) c.sch[x].pm = (uint8_t)(rng() % 7);\n            else {\n                c.sch[x].mode = (uint8_t)(rng() % 9);\n                c.sch[x].pm = (uint8_t)(rng() % 7);\n            }\n        }\n\n        if ((rng() % 100) < 25) {\n            int l = (int)(rng() % N);\n            int len = 1 + (int)(rng() % 5);\n            if ((rng() % 100) < 70) {\n                uint8_t m = (uint8_t)(rng() % 9);\n                for (int x = l; x < N && x < l + len; ++x) c.sch[x].mode = m;\n            } else {\n                uint8_t pm = (uint8_t)(rng() % 7);\n                for (int x = l; x < N && x < l + len; ++x) c.sch[x].pm = pm;\n            }\n        }\n\n        int nk = eval_fast(c.mirror, c.sch);\n        if (nk < INFK) {\n            c.k = nk;\n            c.key = hash_schedule(c.mirror, c.sch);\n            if (nk <= base.k + 4 || (int)pool.size() < POOL_MAX || (rng() % 100) < 10) {\n                add_sched_pool(pool, c, POOL_MAX);\n            }\n        }\n\n        ++iter;\n    }\n\n    if (pool.empty()) try_add(false, make_const_schedule(0, 2));\n    sort_pool();\n\n    // ===== exact normalized objective refine =====\n    unordered_map<uint64_t, int> exact_norm_cache;\n    exact_norm_cache.reserve(1 << 13);\n\n    auto exact_norm_cost = [&](bool mirror, const Schedule& sch) -> int {\n        uint64_t key = hash_schedule(mirror, sch) ^ 0xA5A5A5A5A5A5A5A5ULL;\n        auto it = exact_norm_cache.find(key);\n        if (it != exact_norm_cache.end()) return it->second;\n\n        EvalRes r = run_schedule_output(init, mirror, sch);\n        if (r.E != 0 || r.K > 10000) {\n            exact_norm_cache[key] = INFK;\n            return INFK;\n        }\n        auto ops = normalize_ops(init, std::move(r.ops));\n        int k = (int)ops.size();\n        if (k > 10000) k = INFK;\n        exact_norm_cache[key] = k;\n        return k;\n    };\n\n    vector<SchedCand> specials;\n    if (!pool.empty() && elapsed() < REFINE_T) {\n        int refine_top = min(2, (int)pool.size());\n        for (int si = 0; si < refine_top && elapsed() < REFINE_T; ++si) {\n            SchedCand cur = pool[si];\n            int curFast = cur.k;\n            int curExact = exact_norm_cost(cur.mirror, cur.sch);\n            if (curExact >= INFK) continue;\n\n            for (int pass = 0; pass < 2 && elapsed() < REFINE_T; ++pass) {\n                bool improved = false;\n                for (int dir = 0; dir < 2 && elapsed() < REFINE_T; ++dir) {\n                    for (int t = 0; t < N && elapsed() < REFINE_T; ++t) {\n                        int x = (dir == 0 ? t : (N - 1 - t));\n\n                        // collect promising neighbors by fast score\n                        vector<pair<int, Action>> candFast;\n                        candFast.reserve(24);\n                        bool seen[9][7] = {};\n\n                        auto pushCand = [&](int m, int pm, int nk) {\n                            if (m < 0 || m > 8 || pm < 0 || pm > 6) return;\n                            if (seen[m][pm]) return;\n                            seen[m][pm] = true;\n                            candFast.push_back({nk, Action{(uint8_t)m, (uint8_t)pm}});\n                        };\n\n                        // mode-only\n                        for (int m : { (int)cur.sch[x].mode, 0,2,3,4,6,7,5,8,1 }) {\n                            if (m == cur.sch[x].mode) continue;\n                            Schedule tmp = cur.sch;\n                            tmp[x].mode = (uint8_t)m;\n                            int nk = eval_fast(cur.mirror, tmp);\n                            if (nk < INFK && nk <= curFast + 40) pushCand(m, (int)cur.sch[x].pm, nk);\n                        }\n\n                        // pm-only\n                        for (int pm : { (int)cur.sch[x].pm, 2,4,5,6,0,1,3 }) {\n                            if (pm == cur.sch[x].pm) continue;\n                            Schedule tmp = cur.sch;\n                            tmp[x].pm = (uint8_t)pm;\n                            int nk = eval_fast(cur.mirror, tmp);\n                            if (nk < INFK && nk <= curFast + 40) pushCand((int)cur.sch[x].mode, pm, nk);\n                        }\n\n                        if (candFast.empty()) continue;\n                        sort(candFast.begin(), candFast.end(), [](auto& a, auto& b) {\n                            return a.first < b.first;\n                        });\n\n                        int trials = min(3, (int)candFast.size());\n                        for (int i = 0; i < trials && elapsed() < REFINE_T; ++i) {\n                            int nk = candFast[i].first;\n                            Action a = candFast[i].second;\n\n                            Schedule tmp = cur.sch;\n                            tmp[x] = a;\n                            int ex = exact_norm_cost(cur.mirror, tmp);\n\n                            if (ex < curExact || (ex == curExact && nk < curFast)) {\n                                cur.sch = tmp;\n                                curFast = nk;\n                                curExact = ex;\n                                improved = true;\n                            }\n                        }\n                    }\n                }\n\n                // mirror toggle exact check\n                if (elapsed() < REFINE_T) {\n                    int nk = eval_fast(!cur.mirror, cur.sch);\n                    if (nk < INFK && nk <= curFast + 30) {\n                        int ex = exact_norm_cost(!cur.mirror, cur.sch);\n                        if (ex < curExact || (ex == curExact && nk < curFast)) {\n                            cur.mirror = !cur.mirror;\n                            curFast = nk;\n                            curExact = ex;\n                            improved = true;\n                        }\n                    }\n                }\n\n                cur.k = curFast;\n                cur.key = hash_schedule(cur.mirror, cur.sch);\n                add_sched_pool(pool, cur, POOL_MAX);\n\n                if (!improved) break;\n            }\n\n            specials.push_back(cur);\n        }\n    }\n\n    if (pool.empty()) try_add(false, make_const_schedule(0, 2));\n    sort_pool();\n\n    vector<vector<Move>> sols;\n    sols.reserve(16);\n    unordered_map<uint64_t, int> seen_sol;\n    seen_sol.reserve(64);\n\n    auto push_solution = [&](vector<Move> ops) {\n        ops = normalize_ops(init, std::move(ops));\n        if ((int)ops.size() > 10000) return;\n        if (calcE_after_ops(init, ops) != 0) return;\n\n        uint64_t h = hash_ops(ops);\n        auto it = seen_sol.find(h);\n        if (it == seen_sol.end()) {\n            seen_sol[h] = (int)sols.size();\n            sols.push_back(std::move(ops));\n        } else {\n            int idx = it->second;\n            if (ops.size() < sols[idx].size()) sols[idx] = std::move(ops);\n        }\n    };\n\n    // candidate schedules (pool + specials)\n    vector<SchedCand> finals;\n    finals.reserve(20);\n    unordered_set<uint64_t> used_sched;\n    used_sched.reserve(64);\n\n    int top_final = min(12, (int)pool.size());\n    for (int i = 0; i < top_final; ++i) {\n        if (used_sched.insert(pool[i].key).second) finals.push_back(pool[i]);\n    }\n    for (auto& s : specials) {\n        if (used_sched.insert(s.key).second) finals.push_back(s);\n    }\n\n    for (int i = 0; i < (int)finals.size() && elapsed() < FINAL_T - 0.10; ++i) {\n        EvalRes r = run_schedule_output(init, finals[i].mirror, finals[i].sch);\n        if (r.K <= 10000 && r.E == 0) push_solution(std::move(r.ops));\n    }\n\n    // adaptive extras from top pool\n    if (!pool.empty() && elapsed() < FINAL_T - 0.28) {\n        int top_ad = min(2, (int)pool.size());\n        int alphas[] = {500, 750};\n        for (int i = 0; i < top_ad && elapsed() < FINAL_T - 0.12; ++i) {\n            for (int a : alphas) {\n                if (elapsed() > FINAL_T - 0.12) break;\n                Schedule out;\n                int outK = INFK;\n                bool ok = adapt_schedule_eval(init, pool[i].mirror, pool[i].sch, a, out, outK, elapsed, FINAL_T - 0.10);\n                if (!ok) break;\n                if (outK < INFK) {\n                    EvalRes rr = run_schedule_output(init, pool[i].mirror, out);\n                    if (rr.K <= 10000 && rr.E == 0) push_solution(std::move(rr.ops));\n                }\n            }\n        }\n    }\n\n    auto safe_fallback = [&]() -> vector<Move> {\n        vector<Move> best;\n        Schedule safe = make_const_schedule(0, 2);\n        for (int mir = 0; mir < 2; ++mir) {\n            EvalRes r = run_schedule_output(init, (bool)mir, safe);\n            if (r.K > 10000 || r.E != 0) continue;\n            auto ops = normalize_ops(init, std::move(r.ops));\n            if ((int)ops.size() > 10000) continue;\n            if (calcE_after_ops(init, ops) != 0) continue;\n            if (best.empty() || ops.size() < best.size()) best = std::move(ops);\n        }\n        return best;\n    };\n\n    if (sols.empty()) {\n        auto fb = safe_fallback();\n        if (!fb.empty()) sols.push_back(std::move(fb));\n    }\n\n    if (sols.empty()) {\n        cout << 0 << '\\n';\n        return 0;\n    }\n\n    sort(sols.begin(), sols.end(), [](const vector<Move>& a, const vector<Move>& b) {\n        return a.size() < b.size();\n    });\n\n    vector<Move> bestOps = sols[0];\n\n    // prune top candidates\n    int prune_n = min(2, (int)sols.size());\n    for (int i = 0; i < prune_n && elapsed() < FINAL_T; ++i) {\n        vector<Move> cand = sols[i];\n        prune_ops(init, cand, elapsed, FINAL_T, rng);\n        cand = normalize_ops(init, std::move(cand));\n        if ((int)cand.size() <= 10000 && calcE_after_ops(init, cand) == 0 && cand.size() < bestOps.size()) {\n            bestOps = std::move(cand);\n        }\n    }\n\n    bestOps = normalize_ops(init, std::move(bestOps));\n\n    // final guard\n    if (bestOps.empty() || bestOps.size() > 10000 || calcE_after_ops(init, bestOps) != 0) {\n        bestOps = safe_fallback();\n        if (bestOps.empty() || bestOps.size() > 10000 || calcE_after_ops(init, bestOps) != 0) {\n            bestOps.clear();\n        }\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (const auto& m : bestOps) {\n        cout << m.x1 << ' ' << m.y1 << ' ' << m.x2 << ' ' << m.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pos { int r, c; };\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick(int n_ = 0) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int idx) const {\n        if (idx < 0) return 0;\n        int s = 0;\n        for (++idx; idx > 0; idx -= idx & -idx) s += bit[idx];\n        return s;\n    }\n};\n\nstatic inline bool bit_test(uint64_t lo, uint64_t hi, int b) {\n    if (b < 64) return (lo >> b) & 1ULL;\n    return (hi >> (b - 64)) & 1ULL;\n}\nstatic inline void bit_set(uint64_t& lo, uint64_t& hi, int b) {\n    if (b < 64) lo |= (1ULL << b);\n    else hi |= (1ULL << (b - 64));\n}\nstatic inline void bit_clear(uint64_t& lo, uint64_t& hi, int b) {\n    if (b < 64) lo &= ~(1ULL << b);\n    else hi &= ~(1ULL << (b - 64));\n}\nstatic inline int pop_below(uint64_t lo, uint64_t hi, int k) {\n    if (k <= 0) return 0;\n    if (k < 64) {\n        uint64_t m = (1ULL << k) - 1ULL;\n        return __builtin_popcountll(lo & m);\n    }\n    if (k == 64) return __builtin_popcountll(lo);\n    int kk = k - 64;\n    uint64_t m = (1ULL << kk) - 1ULL;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & m);\n}\ntemplate <class F>\nstatic inline void for_each_bit(uint64_t lo, uint64_t hi, F f) {\n    while (lo) {\n        int b = __builtin_ctzll(lo);\n        lo &= lo - 1;\n        f(b);\n    }\n    while (hi) {\n        int b = __builtin_ctzll(hi);\n        hi &= hi - 1;\n        f(b + 64);\n    }\n}\n\nstruct BeamState {\n    uint64_t rlo, rhi; // removed cells\n    uint64_t flo, fhi; // frontier\n    uint64_t llo, lhi; // removed labels\n    int cost;          // inversions in decided prefix\n    int cross;         // unavoidable inv from prefix to remaining\n    int forced;        // remaining bad mustBefore pairs\n    int parent;\n    int mv;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D, N;\n    if (!(cin >> D >> N)) return 0;\n\n    const int er = 0;\n    const int ec = (D - 1) / 2;\n\n    vector<vector<char>> obstacle(D, vector<char>(D, 0));\n    for (int i = 0; i < N; i++) {\n        int r, c;\n        cin >> r >> c;\n        obstacle[r][c] = 1;\n    }\n\n    auto inb = [&](int r, int c) -> bool {\n        return (0 <= r && r < D && 0 <= c && c < D);\n    };\n\n    // Build free cells (excluding entrance + obstacles)\n    vector<vector<int>> id(D, vector<int>(D, -1));\n    vector<Pos> cells;\n    for (int i = 0; i < D; i++) for (int j = 0; j < D; j++) {\n        if (i == er && j == ec) continue;\n        if (obstacle[i][j]) continue;\n        id[i][j] = (int)cells.size();\n        cells.push_back({i, j});\n    }\n\n    const int M = (int)cells.size();\n    const int ENT = M;\n\n    // Graph\n    vector<vector<int>> adj(M + 1);\n    vector<uint64_t> neiLo(M, 0), neiHi(M, 0);\n    vector<char> adjEnt(M, 0);\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = cells[i];\n        for (int d = 0; d < 4; d++) {\n            int nr = r + dr[d], nc = c + dc[d];\n            if (!inb(nr, nc) || obstacle[nr][nc]) continue;\n            if (nr == er && nc == ec) {\n                adj[i].push_back(ENT);\n                adj[ENT].push_back(i);\n                adjEnt[i] = 1;\n            } else {\n                int j = id[nr][nc];\n                if (j >= 0) {\n                    adj[i].push_back(j);\n                    if (j < 64) neiLo[i] |= (1ULL << j);\n                    else neiHi[i] |= (1ULL << (j - 64));\n                }\n            }\n        }\n    }\n\n    uint64_t allLo = 0, allHi = 0;\n    for (int i = 0; i < M; i++) bit_set(allLo, allHi, i);\n\n    uint64_t entLo = 0, entHi = 0;\n    for (int i = 0; i < M; i++) if (adjEnt[i]) bit_set(entLo, entHi, i);\n\n    auto compute_articulation = [&](const vector<char>& active, vector<char>& isArt) {\n        vector<int> disc(M + 1, -1), low(M + 1, 0), par(M + 1, -1);\n        fill(isArt.begin(), isArt.end(), 0);\n        int timer = 0;\n\n        function<void(int)> dfs = [&](int u) {\n            disc[u] = low[u] = ++timer;\n            for (int v : adj[u]) {\n                if (v != ENT && !active[v]) continue;\n                if (disc[v] == -1) {\n                    par[v] = u;\n                    dfs(v);\n                    low[u] = min(low[u], low[v]);\n                    if (u != ENT && low[v] >= disc[u]) isArt[u] = 1;\n                } else if (v != par[u]) {\n                    low[u] = min(low[u], disc[v]);\n                }\n            }\n        };\n        dfs(ENT);\n    };\n\n    auto bfs_dist = [&](const vector<char>& active) -> vector<int> {\n        vector<int> dist(M, -1);\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            int du = (u == ENT ? 0 : dist[u]);\n            for (int v : adj[u]) {\n                if (v != ENT && !active[v]) continue;\n                if (vis[v]) continue;\n                vis[v] = 1;\n                if (v != ENT) dist[v] = du + 1;\n                q.push(v);\n            }\n        }\n        return dist;\n    };\n\n    auto reachable_count = [&](const vector<char>& active, int ban) -> int {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n        int cnt = 0;\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                if (v == ENT || v == ban || !active[v] || vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n                cnt++;\n            }\n        }\n        return cnt;\n    };\n\n    vector<char> allActive(M, 1);\n    vector<int> distStatic = bfs_dist(allActive);\n\n    // mustBefore[u][v]: if remove u in full graph, v disconnects from entrance\n    vector<vector<unsigned char>> mustBefore(M, vector<unsigned char>(M, 0));\n    vector<int> domOut(M, 0), domIn(M, 0);\n    long long totalMustPairs = 0;\n\n    for (int ban = 0; ban < M; ban++) {\n        vector<char> vis(M + 1, 0);\n        queue<int> q;\n        vis[ENT] = 1;\n        q.push(ENT);\n        while (!q.empty()) {\n            int u = q.front(); q.pop();\n            for (int v : adj[u]) {\n                if (v == ban || vis[v]) continue;\n                vis[v] = 1;\n                q.push(v);\n            }\n        }\n        for (int v = 0; v < M; v++) {\n            if (v == ban) continue;\n            if (!vis[v]) {\n                mustBefore[ban][v] = 1;\n                domOut[ban]++;\n                domIn[v]++;\n                totalMustPairs++;\n            }\n        }\n    }\n\n    vector<uint64_t> descLo(M, 0), descHi(M, 0), ancLo(M, 0), ancHi(M, 0);\n    for (int u = 0; u < M; u++) for (int v = 0; v < M; v++) if (mustBefore[u][v]) {\n        bit_set(descLo[u], descHi[u], v);\n        bit_set(ancLo[v], ancHi[v], u);\n    }\n\n    // Reverse-peeling priority\n    vector<char> alive(M, 1), isArt(M + 1, 0);\n    vector<int> peelStep(M, -1);\n\n    for (int step = 0; step < M; step++) {\n        compute_articulation(alive, isArt);\n        vector<int> dist = bfs_dist(alive);\n\n        int best = -1, bestD = -1, bestMan = -1;\n        for (int c = 0; c < M; c++) {\n            if (!alive[c] || isArt[c]) continue;\n            int d = dist[c];\n            int man = abs(cells[c].r - er) + abs(cells[c].c - ec);\n            if (best == -1 ||\n                d > bestD ||\n                (d == bestD && man > bestMan) ||\n                (d == bestD && man == bestMan &&\n                 (cells[c].r > cells[best].r ||\n                  (cells[c].r == cells[best].r && cells[c].c > cells[best].c)))) {\n                best = c;\n                bestD = d;\n                bestMan = man;\n            }\n        }\n\n        if (best == -1) {\n            for (int c = 0; c < M; c++) if (alive[c]) { best = c; break; }\n        }\n\n        peelStep[best] = step;\n        alive[best] = 0;\n    }\n\n    vector<int> prio(M);\n    for (int c = 0; c < M; c++) prio[c] = M - 1 - peelStep[c];\n\n    vector<int> orderByPrio(M);\n    iota(orderByPrio.begin(), orderByPrio.end(), 0);\n    sort(orderByPrio.begin(), orderByPrio.end(), [&](int a, int b) {\n        if (prio[a] != prio[b]) return prio[a] < prio[b];\n        return a < b;\n    });\n\n    vector<int> orderByDom(M);\n    iota(orderByDom.begin(), orderByDom.end(), 0);\n    sort(orderByDom.begin(), orderByDom.end(), [&](int a, int b) {\n        if (domOut[a] != domOut[b]) return domOut[a] > domOut[b];\n        if (domIn[a] != domIn[b]) return domIn[a] < domIn[b];\n        if (prio[a] != prio[b]) return prio[a] < prio[b];\n        if (distStatic[a] != distStatic[b]) return distStatic[a] < distStatic[b];\n        return a < b;\n    });\n\n    vector<int> domRank(M, -1);\n    for (int i = 0; i < M; i++) domRank[orderByDom[i]] = i;\n\n    double mustDensity = 0.0;\n    if (M >= 2) mustDensity = (double)totalMustPairs / (double)(M * (M - 1));\n    int maxDomOut = 0;\n    for (int x : domOut) maxDomOut = max(maxDomOut, x);\n\n    // Tuned: trigger critical handling a bit earlier\n    bool semiCritical = (mustDensity > 0.02 || maxDomOut >= 12);\n    bool critical = (mustDensity > 0.04 || maxDomOut >= 18);\n\n    // ---------- Online insertion ----------\n    vector<char> inU(M, 1);\n    uint64_t Ulo = allLo, Uhi = allHi;\n    vector<int> labelAt(M, -1);\n    vector<int> assigned;\n    assigned.reserve(M);\n\n    Fenwick unseen(M);\n    for (int x = 0; x < M; x++) unseen.add(x, 1);\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        if (!(cin >> t)) return 0;\n\n        int rem = M - step;\n        int qrank = unseen.sumPrefix(t - 1);\n\n        compute_articulation(inU, isArt);\n\n        vector<int> safe;\n        safe.reserve(rem);\n        for (int c = 0; c < M; c++) if (inU[c] && !isArt[c]) safe.push_back(c);\n\n        if (safe.empty()) {\n            for (int c = 0; c < M; c++) {\n                if (!inU[c]) continue;\n                if (reachable_count(inU, c) == rem - 1) safe.push_back(c);\n            }\n        }\n\n        vector<int> remRankP(M, -1), remRankD(M, -1), safeRankP(M, -1);\n        int rp = 0;\n        for (int c : orderByPrio) if (inU[c]) remRankP[c] = rp++;\n\n        if (semiCritical) {\n            int rd = 0;\n            for (int c : orderByDom) if (inU[c]) remRankD[c] = rd++;\n        }\n\n        // rank among current legal safe cells by prio\n        {\n            vector<int> ss = safe;\n            sort(ss.begin(), ss.end(), [&](int a, int b) {\n                if (prio[a] != prio[b]) return prio[a] < prio[b];\n                return a < b;\n            });\n            for (int i = 0; i < (int)ss.size(); i++) safeRankP[ss[i]] = i;\n        }\n        int safeCnt = (int)safe.size();\n        int qsafe = 0;\n        if (safeCnt > 1 && rem > 1) {\n            qsafe = (int)((1LL * qrank * (safeCnt - 1) + (rem - 2) / 2) / (rem - 1));\n        }\n\n        // one-step flexibility cache for critical maps\n        vector<int> nextSafe(M, -1);\n        if (critical && rem >= 6) {\n            vector<char> active2;\n            vector<char> art2(M + 1);\n            for (int c : safe) {\n                active2 = inU;\n                active2[c] = 0;\n                compute_articulation(active2, art2);\n                int cnt = 0;\n                for (int x = 0; x < M; x++) if (active2[x] && !art2[x]) cnt++;\n                nextSafe[c] = cnt;\n            }\n        }\n\n        bool low = (2 * qrank < rem);\n\n        auto better_tie = [&](int a, int b) -> bool {\n            if (b == -1) return true;\n            if (low) {\n                if (prio[a] != prio[b]) return prio[a] < prio[b];\n                if (semiCritical && domRank[a] != domRank[b]) return domRank[a] < domRank[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] < distStatic[b];\n            } else {\n                if (prio[a] != prio[b]) return prio[a] > prio[b];\n                if (semiCritical && domRank[a] != domRank[b]) return domRank[a] > domRank[b];\n                if (distStatic[a] != distStatic[b]) return distStatic[a] > distStatic[b];\n            }\n            if (domOut[a] != domOut[b]) return domOut[a] > domOut[b];\n            if (cells[a].r != cells[b].r) return cells[a].r < cells[b].r;\n            return cells[a].c < cells[b].c;\n        };\n\n        int best = -1;\n        long long bestScore = (1LL << 62);\n        int bestMandPast = INT_MAX;\n        long long bestExpMand = (1LL << 62);\n        int bestSafeMis = INT_MAX;\n        int bestFlex = INT_MAX;\n\n        for (int c : safe) {\n            int rP = remRankP[c];\n            int invP = 0, invD = 0, mandPast = 0;\n\n            for (int a : assigned) {\n                int la = labelAt[a];\n\n                if (prio[a] < prio[c] && la > t) invP++;\n                if (prio[a] > prio[c] && la < t) invP++;\n\n                if (semiCritical) {\n                    if (domRank[a] < domRank[c] && la > t) invD++;\n                    if (domRank[a] > domRank[c] && la < t) invD++;\n                }\n\n                if (mustBefore[a][c] && la > t) mandPast++;\n                if (mustBefore[c][a] && t > la) mandPast++;\n            }\n\n            long long mainScore = (long long)invP + llabs((long long)rP - qrank);\n            long long domScore = 0;\n            if (semiCritical) {\n                int rD = remRankD[c];\n                domScore = (long long)invD + llabs((long long)rD - qrank);\n            }\n\n            long long expMandNum = 0;\n            int expMandNorm = 0;\n            if (semiCritical && rem > 1) {\n                uint64_t tmpLo = Ulo, tmpHi = Uhi;\n                bit_clear(tmpLo, tmpHi, c);\n                int descCnt = __builtin_popcountll(descLo[c] & tmpLo) + __builtin_popcountll(descHi[c] & tmpHi);\n                int ancCnt  = __builtin_popcountll(ancLo[c]  & tmpLo) + __builtin_popcountll(ancHi[c]  & tmpHi);\n                int smaller = qrank;\n                int larger  = rem - 1 - smaller;\n                expMandNum = 1LL * descCnt * smaller + 1LL * ancCnt * larger;\n                expMandNorm = (int)((expMandNum + (rem - 2)) / (rem - 1));\n            }\n\n            int safeMis = abs(safeRankP[c] - qsafe);\n            int flexPenalty = 0;\n            if (critical && rem >= 6) {\n                flexPenalty = (rem - 1) - max(0, nextSafe[c]);\n            }\n\n            long long score;\n            if (critical) {\n                score = 12LL * mainScore + 6LL * domScore + 4LL * mandPast + expMandNorm + 2LL * safeMis + flexPenalty;\n            } else if (semiCritical) {\n                score = 8LL * mainScore + 2LL * domScore + 2LL * mandPast + safeMis + (expMandNorm > 0 ? 1 : 0);\n            } else {\n                score = mainScore;\n            }\n\n            if (best == -1 ||\n                score < bestScore ||\n                (score == bestScore && mandPast < bestMandPast) ||\n                (score == bestScore && mandPast == bestMandPast && expMandNum < bestExpMand) ||\n                (score == bestScore && mandPast == bestMandPast && expMandNum == bestExpMand && safeMis < bestSafeMis) ||\n                (score == bestScore && mandPast == bestMandPast && expMandNum == bestExpMand && safeMis == bestSafeMis && flexPenalty < bestFlex) ||\n                (score == bestScore && mandPast == bestMandPast && expMandNum == bestExpMand && safeMis == bestSafeMis && flexPenalty == bestFlex && better_tie(c, best))) {\n                best = c;\n                bestScore = score;\n                bestMandPast = mandPast;\n                bestExpMand = expMandNum;\n                bestSafeMis = safeMis;\n                bestFlex = flexPenalty;\n            }\n        }\n\n        if (best == -1) {\n            for (int c = 0; c < M; c++) if (inU[c]) { best = c; break; }\n        }\n\n        inU[best] = 0;\n        bit_clear(Ulo, Uhi, best);\n        labelAt[best] = t;\n        assigned.push_back(best);\n        unseen.add(t, -1);\n\n        cout << cells[best].r << ' ' << cells[best].c << '\\n' << flush;\n    }\n\n    // ---------- Offline ----------\n    auto offStart = chrono::steady_clock::now();\n    auto off_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - offStart).count();\n    };\n    const long long OFFLINE_LIMIT = 1890;\n\n    auto accessible = [&](int c, uint64_t rlo, uint64_t rhi) -> bool {\n        if (adjEnt[c]) return true;\n        if ((neiLo[c] & rlo) != 0ULL) return true;\n        if ((neiHi[c] & rhi) != 0ULL) return true;\n        return false;\n    };\n\n    auto verify_order = [&](const vector<int>& ord) -> bool {\n        if ((int)ord.size() != M) return false;\n        vector<char> used(M, 0);\n        uint64_t rlo = 0, rhi = 0;\n        for (int c : ord) {\n            if (c < 0 || c >= M || used[c]) return false;\n            if (!accessible(c, rlo, rhi)) return false;\n            used[c] = 1;\n            bit_set(rlo, rhi, c);\n        }\n        return true;\n    };\n\n    auto inversion_count = [&](const vector<int>& ord) -> long long {\n        Fenwick fw(M);\n        long long inv = 0;\n        int seen = 0;\n        for (int c : ord) {\n            int x = labelAt[c];\n            int le = fw.sumPrefix(x);\n            inv += (long long)seen - le;\n            fw.add(x, 1);\n            seen++;\n        }\n        return inv;\n    };\n\n    vector<uint64_t> badOutLo(M, 0), badOutHi(M, 0), badInLo(M, 0), badInHi(M, 0);\n    int forcedAll = 0;\n    for (int u = 0; u < M; u++) for (int v = 0; v < M; v++) {\n        if (mustBefore[u][v] && labelAt[u] > labelAt[v]) {\n            bit_set(badOutLo[u], badOutHi[u], v);\n            bit_set(badInLo[v], badInHi[v], u);\n            forcedAll++;\n        }\n    }\n\n    int domW = (mustDensity > 0.05 ? 2 : 1);\n\n    auto greedy_order = [&](int mode) -> vector<int> {\n        vector<int> ord;\n        ord.reserve(M);\n\n        uint64_t rlo = 0, rhi = 0;\n        uint64_t flo = entLo, fhi = entHi;\n\n        for (int depth = 0; depth < M; depth++) {\n            int best = -1;\n\n            for_each_bit(flo, fhi, [&](int c) {\n                if (best == -1) { best = c; return; }\n                if (mode == 0) {\n                    if (labelAt[c] < labelAt[best] ||\n                        (labelAt[c] == labelAt[best] && prio[c] < prio[best]) ||\n                        (labelAt[c] == labelAt[best] && prio[c] == prio[best] && c < best))\n                        best = c;\n                } else if (mode == 1) {\n                    int ka = labelAt[c] - domW * domOut[c];\n                    int kb = labelAt[best] - domW * domOut[best];\n                    if (ka < kb ||\n                        (ka == kb && labelAt[c] < labelAt[best]) ||\n                        (ka == kb && labelAt[c] == labelAt[best] && prio[c] < prio[best]) ||\n                        (ka == kb && labelAt[c] == labelAt[best] && prio[c] == prio[best] && c < best))\n                        best = c;\n                } else {\n                    if (prio[c] < prio[best] ||\n                        (prio[c] == prio[best] && labelAt[c] < labelAt[best]) ||\n                        (prio[c] == prio[best] && labelAt[c] == labelAt[best] && c < best))\n                        best = c;\n                }\n            });\n\n            if (best == -1) {\n                for (int c = 0; c < M; c++) if (!bit_test(rlo, rhi, c)) { best = c; break; }\n            }\n\n            ord.push_back(best);\n            bit_set(rlo, rhi, best);\n\n            bit_clear(flo, fhi, best);\n            flo |= neiLo[best];\n            fhi |= neiHi[best];\n            flo |= entLo;\n            fhi |= entHi;\n            flo &= ~rlo;\n            fhi &= ~rhi;\n        }\n\n        return ord;\n    };\n\n    auto randomized_greedy = [&](int mode, uint64_t seed, int topK) -> vector<int> {\n        uint64_t x = (seed ? seed : 88172645463325252ULL);\n        auto rnd = [&]() -> uint64_t {\n            x ^= x << 7;\n            x ^= x >> 9;\n            return x;\n        };\n\n        auto key_of = [&](int c) -> long long {\n            if (mode == 0) return 16LL * labelAt[c] + prio[c];\n            if (mode == 1) return 16LL * labelAt[c] + prio[c] - 2LL * domW * domOut[c];\n            return 16LL * prio[c] + labelAt[c];\n        };\n\n        vector<int> ord;\n        ord.reserve(M);\n\n        uint64_t rlo = 0, rhi = 0;\n        uint64_t flo = entLo, fhi = entHi;\n\n        for (int depth = 0; depth < M; depth++) {\n            vector<pair<long long, int>> cand;\n            cand.reserve(16);\n            for_each_bit(flo, fhi, [&](int c) {\n                cand.push_back({key_of(c), c});\n            });\n\n            int chosen = -1;\n            if (!cand.empty()) {\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                int k = min<int>(topK, cand.size());\n                int tot = k * (k + 1) / 2;\n                int t = (int)(rnd() % max(1, tot));\n                int idx = 0, acc = 0;\n                for (int p = 0; p < k; p++) {\n                    acc += (k - p);\n                    if (t < acc) { idx = p; break; }\n                }\n                chosen = cand[idx].second;\n            } else {\n                for (int c = 0; c < M; c++) if (!bit_test(rlo, rhi, c)) { chosen = c; break; }\n            }\n\n            ord.push_back(chosen);\n            bit_set(rlo, rhi, chosen);\n\n            bit_clear(flo, fhi, chosen);\n            flo |= neiLo[chosen];\n            fhi |= neiHi[chosen];\n            flo |= entLo;\n            fhi |= entHi;\n            flo &= ~rlo;\n            fhi &= ~rhi;\n        }\n\n        return ord;\n    };\n\n    // mode:\n    // 0: cross + forced\n    // 1: cross\n    // 2: cost\n    // 3: cost + cross\n    auto run_beam = [&](int BEAM_WIDTH, int mode, long long deadline_ms) -> vector<int> {\n        auto eval = [&](const BeamState& s) -> long long {\n            if (mode == 0) return (long long)s.cross + s.forced;\n            if (mode == 1) return (long long)s.cross;\n            if (mode == 2) return (long long)s.cost;\n            return (long long)s.cost + s.cross;\n        };\n\n        vector<BeamState> pool;\n        pool.reserve(1 + (size_t)BEAM_WIDTH * (M + 2));\n        pool.push_back({0ULL, 0ULL, entLo, entHi, 0ULL, 0ULL, 0, 0, forcedAll, -1, -1});\n        vector<int> beam = {0};\n\n        for (int depth = 0; depth < M; depth++) {\n            if (off_ms() > deadline_ms) return {};\n            vector<BeamState> nxt;\n            nxt.reserve((size_t)beam.size() * 14);\n\n            for (int sid : beam) {\n                const BeamState& st = pool[sid];\n                uint64_t remLo = allLo & ~st.rlo;\n                uint64_t remHi = allHi & ~st.rhi;\n\n                for_each_bit(st.flo, st.fhi, [&](int c) {\n                    BeamState nx;\n\n                    nx.rlo = st.rlo; nx.rhi = st.rhi;\n                    bit_set(nx.rlo, nx.rhi, c);\n\n                    nx.flo = st.flo; nx.fhi = st.fhi;\n                    bit_clear(nx.flo, nx.fhi, c);\n                    nx.flo |= neiLo[c];\n                    nx.fhi |= neiHi[c];\n                    nx.flo |= entLo;\n                    nx.fhi |= entHi;\n                    nx.flo &= ~nx.rlo;\n                    nx.fhi &= ~nx.rhi;\n\n                    nx.llo = st.llo; nx.lhi = st.lhi;\n                    int lab = labelAt[c];\n                    int removedSmaller = pop_below(st.llo, st.lhi, lab);\n\n                    nx.cost = st.cost + (depth - removedSmaller);\n                    nx.cross = st.cross + (lab - removedSmaller);\n                    bit_set(nx.llo, nx.lhi, lab);\n\n                    int subOut = __builtin_popcountll(badOutLo[c] & remLo) + __builtin_popcountll(badOutHi[c] & remHi);\n                    int subIn  = __builtin_popcountll(badInLo[c]  & remLo) + __builtin_popcountll(badInHi[c]  & remHi);\n                    nx.forced = st.forced - subOut - subIn;\n\n                    nx.parent = sid;\n                    nx.mv = c;\n                    nxt.push_back(nx);\n                });\n            }\n\n            if (nxt.empty()) return {};\n\n            sort(nxt.begin(), nxt.end(), [](const BeamState& a, const BeamState& b) {\n                if (a.rlo != b.rlo) return a.rlo < b.rlo;\n                if (a.rhi != b.rhi) return a.rhi < b.rhi;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.cross != b.cross) return a.cross < b.cross;\n                return a.forced < b.forced;\n            });\n\n            vector<BeamState> uniq;\n            uniq.reserve(nxt.size());\n            for (const auto& s : nxt) {\n                if (uniq.empty() || s.rlo != uniq.back().rlo || s.rhi != uniq.back().rhi) {\n                    uniq.push_back(s);\n                }\n            }\n\n            auto cmpEval = [&](const BeamState& a, const BeamState& b) {\n                long long ea = eval(a), eb = eval(b);\n                if (ea != eb) return ea < eb;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.cross != b.cross) return a.cross < b.cross;\n                if (a.forced != b.forced) return a.forced < b.forced;\n                if (a.rlo != b.rlo) return a.rlo < b.rlo;\n                return a.rhi < b.rhi;\n            };\n\n            if ((int)uniq.size() > BEAM_WIDTH) {\n                nth_element(uniq.begin(), uniq.begin() + BEAM_WIDTH, uniq.end(), cmpEval);\n                uniq.resize(BEAM_WIDTH);\n            }\n            sort(uniq.begin(), uniq.end(), cmpEval);\n\n            beam.clear();\n            beam.reserve(uniq.size());\n            for (const auto& s : uniq) {\n                pool.push_back(s);\n                beam.push_back((int)pool.size() - 1);\n            }\n        }\n\n        if (beam.empty()) return {};\n\n        int bestSid = beam[0];\n        for (int sid : beam) {\n            if (pool[sid].cost < pool[bestSid].cost ||\n                (pool[sid].cost == pool[bestSid].cost && pool[sid].cross < pool[bestSid].cross)) {\n                bestSid = sid;\n            }\n        }\n\n        vector<int> ord;\n        ord.reserve(M);\n        while (bestSid != -1 && pool[bestSid].parent != -1) {\n            ord.push_back(pool[bestSid].mv);\n            bestSid = pool[bestSid].parent;\n        }\n        reverse(ord.begin(), ord.end());\n        if ((int)ord.size() != M) return {};\n        return ord;\n    };\n\n    auto local_adjacent = [&](vector<int>& ord, int maxIter, long long deadline_ms) {\n        if ((int)ord.size() != M || !verify_order(ord)) return;\n\n        for (int it = 0; it < maxIter; it++) {\n            if (off_ms() > deadline_ms) return;\n            bool changed = false;\n\n            uint64_t rlo = 0, rhi = 0;\n            for (int i = 0; i + 1 < M; i++) {\n                int a = ord[i], b = ord[i + 1];\n\n                if (labelAt[a] > labelAt[b]) {\n                    if (accessible(b, rlo, rhi)) {\n                        uint64_t lo2 = rlo, hi2 = rhi;\n                        bit_set(lo2, hi2, b);\n                        if (accessible(a, lo2, hi2)) {\n                            swap(ord[i], ord[i + 1]);\n                            changed = true;\n                            bit_set(rlo, rhi, b);\n                            continue;\n                        }\n                    }\n                }\n\n                bit_set(rlo, rhi, ord[i]);\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto optimize_windows = [&](vector<int>& ord, int L, int passLim, long long deadline_ms) {\n        if ((int)ord.size() != M || L <= 1 || M < L) return;\n        if (!verify_order(ord)) return;\n\n        int S = 1 << L;\n        vector<uint64_t> subLo(S), subHi(S);\n        vector<int> dp(S), pmask(S), pick(S);\n\n        for (int pass = 0; pass < passLim; pass++) {\n            if (off_ms() > deadline_ms) return;\n            bool changed = false;\n\n            uint64_t preLo = 0, preHi = 0;\n            for (int l = 0; l + L <= M; l++) {\n                if (off_ms() > deadline_ms) return;\n\n                vector<int> w(L), lab(L), lessMask(L, 0);\n                for (int i = 0; i < L; i++) {\n                    w[i] = ord[l + i];\n                    lab[i] = labelAt[w[i]];\n                }\n\n                int curInv = 0;\n                for (int i = 0; i < L; i++) for (int j = i + 1; j < L; j++) {\n                    if (lab[i] > lab[j]) curInv++;\n                }\n\n                for (int i = 0; i < L; i++) {\n                    int m = 0;\n                    for (int j = 0; j < L; j++) if (lab[j] < lab[i]) m |= (1 << j);\n                    lessMask[i] = m;\n                }\n\n                fill(subLo.begin(), subLo.end(), 0ULL);\n                fill(subHi.begin(), subHi.end(), 0ULL);\n                for (int mask = 1; mask < S; mask++) {\n                    int b = __builtin_ctz((unsigned)mask);\n                    int pm = mask & (mask - 1);\n                    subLo[mask] = subLo[pm];\n                    subHi[mask] = subHi[pm];\n                    bit_set(subLo[mask], subHi[mask], w[b]);\n                }\n\n                const int INF = 1e9;\n                fill(dp.begin(), dp.end(), INF);\n                fill(pmask.begin(), pmask.end(), -1);\n                fill(pick.begin(), pick.end(), -1);\n                dp[0] = 0;\n\n                for (int mask = 0; mask < S; mask++) {\n                    if (dp[mask] >= INF) continue;\n                    int k = __builtin_popcount((unsigned)mask);\n                    uint64_t rlo = preLo | subLo[mask];\n                    uint64_t rhi = preHi | subHi[mask];\n\n                    for (int i = 0; i < L; i++) if (((mask >> i) & 1) == 0) {\n                        int v = w[i];\n                        if (!accessible(v, rlo, rhi)) continue;\n                        int chosenLess = __builtin_popcount((unsigned)(mask & lessMask[i]));\n                        int add = k - chosenLess;\n                        int nm = mask | (1 << i);\n                        int cand = dp[mask] + add;\n                        if (cand < dp[nm]) {\n                            dp[nm] = cand;\n                            pmask[nm] = mask;\n                            pick[nm] = i;\n                        }\n                    }\n                }\n\n                int full = S - 1;\n                if (dp[full] < curInv) {\n                    vector<int> seq(L);\n                    int mask = full;\n                    for (int pos = L - 1; pos >= 0; pos--) {\n                        int i = pick[mask];\n                        seq[pos] = w[i];\n                        mask = pmask[mask];\n                    }\n                    for (int i = 0; i < L; i++) ord[l + i] = seq[i];\n                    changed = true;\n                }\n\n                bit_set(preLo, preHi, ord[l]);\n            }\n\n            if (!changed) break;\n        }\n    };\n\n    auto relocate_best_improve = [&](vector<int>& ord, int rounds, int maxTry, long long deadline_ms) {\n        if ((int)ord.size() != M || !verify_order(ord)) return;\n\n        struct Move { int delta, type, i, j; }; // type0: j->i ; type1: i->j\n\n        for (int rd = 0; rd < rounds; rd++) {\n            if (off_ms() > deadline_ms) return;\n\n            vector<Move> moves;\n            moves.reserve(12000);\n\n            // Type0\n            for (int j = 1; j < M; j++) {\n                int x = labelAt[ord[j]];\n                int less = 0, greater = 0;\n                for (int i = j - 1; i >= 0; i--) {\n                    int y = labelAt[ord[i]];\n                    if (y < x) less++;\n                    else greater++;\n                    int delta = less - greater;\n                    if (delta < 0) moves.push_back({delta, 0, i, j});\n                }\n            }\n\n            // Type1\n            for (int i = 0; i + 1 < M; i++) {\n                int x = labelAt[ord[i]];\n                int less = 0, greater = 0;\n                for (int j = i + 1; j < M; j++) {\n                    int y = labelAt[ord[j]];\n                    if (y < x) less++;\n                    else greater++;\n                    int delta = greater - less;\n                    if (delta < 0) moves.push_back({delta, 1, i, j});\n                }\n            }\n\n            if (moves.empty()) break;\n            sort(moves.begin(), moves.end(), [&](const Move& a, const Move& b) {\n                if (a.delta != b.delta) return a.delta < b.delta;\n                if (a.type != b.type) return a.type < b.type;\n                if (a.i != b.i) return a.i < b.i;\n                return a.j < b.j;\n            });\n\n            bool applied = false;\n            int tries = 0;\n\n            for (const auto& mv : moves) {\n                if (off_ms() > deadline_ms) return;\n                if (tries >= maxTry) break;\n                if (mv.delta >= 0) break;\n\n                vector<int> tmp = ord;\n                if (mv.type == 0) {\n                    int v = tmp[mv.j];\n                    tmp.erase(tmp.begin() + mv.j);\n                    tmp.insert(tmp.begin() + mv.i, v);\n                } else {\n                    int v = tmp[mv.i];\n                    tmp.erase(tmp.begin() + mv.i);\n                    tmp.insert(tmp.begin() + mv.j, v);\n                }\n                tries++;\n\n                if (verify_order(tmp)) {\n                    ord.swap(tmp);\n                    applied = true;\n                    break;\n                }\n            }\n\n            if (!applied) break;\n        }\n    };\n\n    auto anneal_adjacent = [&](vector<int> ord, int ITER, uint64_t seed, long long deadline_ms) -> vector<int> {\n        if ((int)ord.size() != M || M <= 1 || ITER <= 0) return ord;\n        if (!verify_order(ord)) return ord;\n\n        uint64_t x = (seed ? seed : 88172645463325252ULL);\n        auto rnd = [&]() -> uint64_t {\n            x ^= x << 7;\n            x ^= x >> 9;\n            return x;\n        };\n\n        long long curInv = inversion_count(ord);\n        long long bestInv = curInv;\n        vector<int> bestOrd = ord;\n\n        vector<uint64_t> preLo(M + 1), preHi(M + 1);\n        auto rebuild = [&]() {\n            preLo[0] = 0;\n            preHi[0] = 0;\n            for (int i = 0; i < M; i++) {\n                preLo[i + 1] = preLo[i];\n                preHi[i + 1] = preHi[i];\n                bit_set(preLo[i + 1], preHi[i + 1], ord[i]);\n            }\n        };\n        rebuild();\n\n        for (int it = 0; it < ITER; it++) {\n            if (off_ms() > deadline_ms) break;\n\n            int i = (int)(rnd() % (M - 1));\n            int a = ord[i], b = ord[i + 1];\n\n            uint64_t rlo = preLo[i], rhi = preHi[i];\n            if (!accessible(b, rlo, rhi)) continue;\n            bit_set(rlo, rhi, b);\n            if (!accessible(a, rlo, rhi)) continue;\n\n            int delta = (labelAt[a] > labelAt[b]) ? -1 : +1;\n\n            bool accept = false;\n            if (delta < 0) accept = true;\n            else {\n                int p = (int)(65LL * (ITER - it) / ITER);\n                if ((int)(rnd() % 1000) < p) accept = true;\n            }\n\n            if (accept) {\n                swap(ord[i], ord[i + 1]);\n                curInv += delta;\n                rebuild();\n\n                if (curInv < bestInv) {\n                    bestInv = curInv;\n                    bestOrd = ord;\n                }\n            }\n        }\n\n        return bestOrd;\n    };\n\n    auto hash_order = [&](const vector<int>& ord) -> uint64_t {\n        uint64_t h = 1469598103934665603ULL;\n        for (int v : ord) {\n            h ^= (uint64_t)(v + 1);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    };\n\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < M; i++) {\n        seed ^= (uint64_t)(labelAt[i] + 1 + 131 * i);\n        seed *= 1099511628211ULL;\n    }\n\n    vector<vector<int>> cands;\n    unordered_set<uint64_t> seen;\n    seen.reserve(64);\n\n    auto add_candidate = [&](vector<int> ord, int polishLevel) {\n        if (ord.empty()) return;\n        if (!verify_order(ord)) return;\n\n        if (polishLevel >= 1) local_adjacent(ord, 40, OFFLINE_LIMIT - 520);\n        if (polishLevel >= 2 && off_ms() < OFFLINE_LIMIT - 650) optimize_windows(ord, 9, 1, OFFLINE_LIMIT - 560);\n        if (polishLevel >= 1) local_adjacent(ord, 20, OFFLINE_LIMIT - 500);\n\n        if (!verify_order(ord)) return;\n        uint64_t h = hash_order(ord);\n        if (seen.insert(h).second) cands.push_back(move(ord));\n    };\n\n    // base candidates\n    add_candidate(greedy_order(0), 2);\n    if (semiCritical) add_candidate(greedy_order(1), 2);\n    if (critical) add_candidate(greedy_order(2), 2);\n\n    // randomized greedy candidates\n    if (off_ms() < 500) {\n        int runs = critical ? 8 : 5;\n        for (int r = 0; r < runs; r++) {\n            if (off_ms() > OFFLINE_LIMIT - 1000) break;\n            int mode = critical ? (r % 3) : (r % 2);\n            int topK = 3 + (r & 1);\n            add_candidate(randomized_greedy(mode, seed + 0x9e3779b97f4a7c15ULL * (r + 1), topK), 1);\n        }\n    }\n\n    // beam candidates\n    if (critical) {\n        add_candidate(run_beam(2700, 0, OFFLINE_LIMIT - 980), 2);\n        if (off_ms() < OFFLINE_LIMIT - 900) add_candidate(run_beam(1700, 1, OFFLINE_LIMIT - 760), 2);\n        if (off_ms() < OFFLINE_LIMIT - 760) add_candidate(run_beam(1000, 3, OFFLINE_LIMIT - 620), 1);\n    } else {\n        add_candidate(run_beam(2300, 1, OFFLINE_LIMIT - 980), 2);\n        if (off_ms() < OFFLINE_LIMIT - 900) add_candidate(run_beam(1300, 0, OFFLINE_LIMIT - 760), 2);\n        if (off_ms() < OFFLINE_LIMIT - 760) add_candidate(run_beam(900, 3, OFFLINE_LIMIT - 620), 1);\n        if (off_ms() < OFFLINE_LIMIT - 700) add_candidate(run_beam(700, 2, OFFLINE_LIMIT - 560), 1);\n    }\n\n    if (cands.empty()) cands.push_back(greedy_order(0));\n\n    vector<pair<long long, int>> ranking;\n    for (int i = 0; i < (int)cands.size(); i++) {\n        if (!verify_order(cands[i])) continue;\n        ranking.push_back({inversion_count(cands[i]), i});\n    }\n    sort(ranking.begin(), ranking.end());\n\n    // strong refinement on top candidates\n    int topKRef = min(3, (int)ranking.size());\n    for (int k = 0; k < topKRef; k++) {\n        if (off_ms() > OFFLINE_LIMIT - 140) break;\n\n        vector<int> ord = cands[ranking[k].second];\n        if (!verify_order(ord)) continue;\n\n        local_adjacent(ord, 220, OFFLINE_LIMIT - 180);\n\n        if (critical && off_ms() < OFFLINE_LIMIT - 780) optimize_windows(ord, 13, 1, OFFLINE_LIMIT - 260);\n        if (off_ms() < OFFLINE_LIMIT - 640) optimize_windows(ord, 12, 1, OFFLINE_LIMIT - 230);\n        if (off_ms() < OFFLINE_LIMIT - 540) optimize_windows(ord, 11, 1, OFFLINE_LIMIT - 200);\n        if (off_ms() < OFFLINE_LIMIT - 440) optimize_windows(ord, 10, 1, OFFLINE_LIMIT - 170);\n        if (off_ms() < OFFLINE_LIMIT - 350) optimize_windows(ord, 9, 1, OFFLINE_LIMIT - 150);\n\n        if (off_ms() < OFFLINE_LIMIT - 260) {\n            relocate_best_improve(ord, critical ? 4 : 3, 140, OFFLINE_LIMIT - 120);\n        }\n\n        long long rem = OFFLINE_LIMIT - off_ms() - 60;\n        if (rem > 100) {\n            int cap = (k == 0 ? 22000 : (k == 1 ? 14000 : 9000));\n            int iter = (int)min<long long>(cap, rem * 90);\n            iter = max(iter, 3000);\n            ord = anneal_adjacent(ord, iter, seed + 0x517cc1b727220a95ULL * (k + 1), OFFLINE_LIMIT - 40);\n        }\n\n        local_adjacent(ord, 100, OFFLINE_LIMIT - 25);\n\n        if (verify_order(ord)) {\n            uint64_t h = hash_order(ord);\n            if (seen.insert(h).second) cands.push_back(move(ord));\n        }\n    }\n\n    vector<int> finalOrd;\n    long long bestInv = (1LL << 62);\n    for (auto& ord : cands) {\n        if (!verify_order(ord)) continue;\n        long long inv = inversion_count(ord);\n        if (inv < bestInv) {\n            bestInv = inv;\n            finalOrd = ord;\n        }\n    }\n\n    if (finalOrd.empty() || !verify_order(finalOrd)) finalOrd = greedy_order(0);\n\n    for (int c : finalOrd) {\n        cout << cells[c].r << ' ' << cells[c].c << '\\n';\n    }\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nconstexpr int NMAX = 50;\nconstexpr int CMAX = 101;\nconstexpr int INF = 1e9;\n\nstruct Problem {\n    int n = 0, m = 0;\n    array<array<int, NMAX>, NMAX> initGrid{};\n    array<int, CMAX> initCnt{};\n    array<array<int, CMAX>, CMAX> initEdgeCnt{};\n    array<array<bool, CMAX>, CMAX> targetAdj{};\n    array<bool, CMAX> canZero{};\n    array<int, CMAX> depth{};\n    array<int, CMAX> deg{};\n};\n\nstruct State {\n    struct ChangeRec {\n        int i, j;\n        int a, b;\n        int psz;\n        int u[10], v[10], d[10];\n    };\n\n    const Problem* pb = nullptr;\n\n    array<array<int, NMAX>, NMAX> g{};\n    array<int, CMAX> cnt{};\n    array<array<int, CMAX>, CMAX> edgeCnt{};\n    int zeroCount = 0;\n    int nonCanMass = 0; // sum cnt[c] for c>0 && !canZero[c]\n\n    array<array<int, NMAX>, NMAX> vis{};\n    int visToken = 1;\n\n    vector<int> order;\n\n    State() = default;\n    explicit State(const Problem* p) { init(p); }\n\n    void init(const Problem* p) {\n        pb = p;\n        g = pb->initGrid;\n        cnt = pb->initCnt;\n        edgeCnt = pb->initEdgeCnt;\n        zeroCount = cnt[0];\n\n        nonCanMass = 0;\n        for (int c = 1; c <= pb->m; c++) if (!pb->canZero[c]) nonCanMass += cnt[c];\n\n        for (auto& row : vis) row.fill(0);\n        visToken = 1;\n\n        order.resize(pb->n * pb->n);\n        iota(order.begin(), order.end(), 0);\n    }\n\n    inline bool in(int x, int y) const {\n        return (0 <= x && x < pb->n && 0 <= y && y < pb->n);\n    }\n\n    inline bool near_zero_cell(int i, int j) const {\n        if (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1) return true;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n        for (int d = 0; d < 4; d++) {\n            int ni = i + dx[d], nj = j + dy[d];\n            if (in(ni, nj) && g[ni][nj] == 0) return true;\n        }\n        return false;\n    }\n\n    int frontier_potential() const {\n        int pot = 0;\n        for (int i = 0; i < pb->n; i++) {\n            for (int j = 0; j < pb->n; j++) {\n                int c = g[i][j];\n                if (c <= 0 || !pb->canZero[c]) continue;\n                if (near_zero_cell(i, j)) ++pot;\n            }\n        }\n        return pot;\n    }\n\n    bool connected_after_remove(int ri, int rj, int color, int si, int sj) {\n        int need = cnt[color] - 1;\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        vis[si][sj] = visToken;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        if (reached == need) return true;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != color) continue;\n                if (vis[nx][ny] == visToken) continue;\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n                if (reached == need) return true;\n            }\n        }\n        return reached == need;\n    }\n\n    bool zero_connected_after_remove(int ri, int rj) {\n        int need = cnt[0] - 1;\n        if (need <= 0) return true;\n\n        if (++visToken == INT_MAX) {\n            for (auto& row : vis) row.fill(0);\n            visToken = 1;\n        }\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        int reached = 0;\n\n        for (int i = 0; i < pb->n; i++) {\n            for (int j = 0; j < pb->n; j++) {\n                if (i != 0 && i != pb->n - 1 && j != 0 && j != pb->n - 1) continue;\n                if (i == ri && j == rj) continue;\n                if (g[i][j] != 0) continue;\n                if (vis[i][j] == visToken) continue;\n                vis[i][j] = visToken;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached == 0) return false;\n\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (nx == ri && ny == rj) continue;\n                if (g[nx][ny] != 0) continue;\n                if (vis[nx][ny] == visToken) continue;\n                vis[nx][ny] = visToken;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        return reached == need;\n    }\n\n    bool try_change_rec(int i, int j, int b, ChangeRec& rec) {\n        int a = g[i][j];\n        if (a == b) return false;\n        if (a > 0 && cnt[a] <= 1) return false;\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        // new color local connectivity\n        if (b == 0) {\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary) {\n                bool adj0 = false;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj) && g[ni][nj] == 0) { adj0 = true; break; }\n                }\n                if (!adj0) return false;\n            }\n        } else {\n            bool adjb = false;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (in(ni, nj) && g[ni][nj] == b) { adjb = true; break; }\n            }\n            if (!adjb) return false;\n        }\n\n        // edge delta\n        int pu[10], pv[10], pd[10], psz = 0;\n        auto add_delta = [&](int x, int y, int d) {\n            if (x == y) return;\n            if (x > y) swap(x, y);\n            for (int t = 0; t < psz; t++) {\n                if (pu[t] == x && pv[t] == y) {\n                    pd[t] += d;\n                    return;\n                }\n            }\n            pu[psz] = x;\n            pv[psz] = y;\n            pd[psz] = d;\n            ++psz;\n        };\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + dx[d], nj = j + dy[d];\n            int x = in(ni, nj) ? g[ni][nj] : 0;\n            add_delta(a, x, -1);\n            add_delta(b, x, +1);\n        }\n\n        // adjacency graph exact\n        for (int t = 0; t < psz; t++) {\n            int u = pu[t], v = pv[t];\n            int nc = edgeCnt[u][v] + pd[t];\n            if (nc < 0) return false;\n            if ((nc > 0) != pb->targetAdj[u][v]) return false;\n        }\n\n        // old color connectivity\n        if (a > 0) {\n            int rem = cnt[a] - 1;\n            if (rem > 0) {\n                int same = 0, si = -1, sj = -1;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj) && g[ni][nj] == a) {\n                        ++same;\n                        if (si == -1) { si = ni; sj = nj; }\n                    }\n                }\n                if (same == 0) return false;\n                if (same >= 2 && rem > 1) {\n                    if (!connected_after_remove(i, j, a, si, sj)) return false;\n                }\n            }\n        } else {\n            int rem0 = cnt[0] - 1;\n            if (rem0 > 0) {\n                int adj0 = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj) && g[ni][nj] == 0) ++adj0;\n                }\n                bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n                bool needBFS = true;\n                if (!boundary && adj0 <= 1) needBFS = false;\n                if (boundary && adj0 == 0) needBFS = false;\n                if (needBFS && !zero_connected_after_remove(i, j)) return false;\n            }\n        }\n\n        // apply + record\n        rec.i = i; rec.j = j; rec.a = a; rec.b = b;\n        rec.psz = psz;\n        for (int t = 0; t < psz; t++) {\n            rec.u[t] = pu[t];\n            rec.v[t] = pv[t];\n            rec.d[t] = pd[t];\n        }\n\n        g[i][j] = b;\n        --cnt[a];\n        ++cnt[b];\n        if (a == 0) --zeroCount;\n        if (b == 0) ++zeroCount;\n\n        if (a > 0 && !pb->canZero[a]) --nonCanMass;\n        if (b > 0 && !pb->canZero[b]) ++nonCanMass;\n\n        for (int t = 0; t < psz; t++) edgeCnt[pu[t]][pv[t]] += pd[t];\n        return true;\n    }\n\n    inline void undo_change(const ChangeRec& rec) {\n        g[rec.i][rec.j] = rec.a;\n        ++cnt[rec.a];\n        --cnt[rec.b];\n        if (rec.a == 0) ++zeroCount;\n        if (rec.b == 0) --zeroCount;\n\n        if (rec.a > 0 && !pb->canZero[rec.a]) ++nonCanMass;\n        if (rec.b > 0 && !pb->canZero[rec.b]) --nonCanMass;\n\n        for (int t = 0; t < rec.psz; t++) edgeCnt[rec.u[t]][rec.v[t]] -= rec.d[t];\n    }\n\n    bool try_change(int i, int j, int b) {\n        ChangeRec rec;\n        return try_change_rec(i, j, b, rec);\n    }\n\n    bool try_swap(int i, int j, int ni, int nj) {\n        int a = g[i][j], b = g[ni][nj];\n        if (a <= 0 || b <= 0 || a == b) return false;\n\n        ChangeRec r1, r2;\n        if (try_change_rec(i, j, b, r1)) {\n            if (try_change_rec(ni, nj, a, r2)) return true;\n            undo_change(r1);\n        }\n        if (try_change_rec(ni, nj, a, r1)) {\n            if (try_change_rec(i, j, b, r2)) return true;\n            undo_change(r1);\n        }\n        return false;\n    }\n\n    int local_delete_burst(int ci, int cj, int limit) {\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        int qx[128], qy[128];\n        int head = 0, tail = 0;\n\n        auto push = [&](int x, int y) {\n            if (!in(x, y)) return;\n            if (tail < 128) {\n                qx[tail] = x;\n                qy[tail] = y;\n                ++tail;\n            }\n        };\n\n        push(ci, cj);\n        for (int d = 0; d < 4; d++) push(ci + dx[d], cj + dy[d]);\n\n        int changes = 0;\n        int steps = 0;\n        while (head < tail && steps < limit) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            ++steps;\n\n            int a = g[x][y];\n            if (a == 0 || !pb->canZero[a]) continue;\n            if (!near_zero_cell(x, y)) continue;\n\n            if (try_change(x, y, 0)) {\n                ++changes;\n                push(x, y);\n                for (int d = 0; d < 4; d++) push(x + dx[d], y + dy[d]);\n            }\n        }\n        return changes;\n    }\n\n    int improve(const vector<int>& value, mt19937& rng, Clock::time_point deadline,\n                int maxPass, bool allowRecolor, int eqProb = 0, int upProb = 0) {\n        int totalChanges = 0;\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (Clock::now() >= deadline) break;\n            bool changed = false;\n\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int t = 0; t < (int)order.size(); t++) {\n                if ((t & 127) == 0 && Clock::now() >= deadline) return totalChanges;\n\n                int idx = order[t];\n                int i = idx / pb->n;\n                int j = idx % pb->n;\n                int a = g[i][j];\n                if (a == 0) continue;\n\n                // delete first\n                if (pb->canZero[a]) {\n                    if (try_change(i, j, 0)) {\n                        changed = true;\n                        ++totalChanges;\n                        totalChanges += local_delete_burst(i, j, 5);\n                        continue;\n                    }\n                }\n\n                if (!allowRecolor) continue;\n\n                // recolor candidates\n                int cand[4], pri[4], vv[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b <= 0 || b == a) continue;\n\n                    bool ok = false;\n                    if (value[b] < value[a]) ok = true;\n                    else if (value[b] == value[a] && eqProb > 0 && (int)(rng() % eqProb) == 0) ok = true;\n                    else if (value[b] > value[a] && upProb > 0 && (int)(rng() % upProb) == 0) ok = true;\n                    if (!ok) continue;\n\n                    bool dup = false;\n                    for (int q = 0; q < k; q++) if (cand[q] == b) { dup = true; break; }\n                    if (dup) continue;\n\n                    cand[k] = b;\n                    vv[k] = value[b];\n                    pri[k] = (!pb->canZero[a] && pb->canZero[b]) ? 0 : 1;\n                    ++k;\n                }\n                if (k == 0) continue;\n\n                for (int x = 0; x < k; x++) {\n                    int r = x + (int)(rng() % (k - x));\n                    swap(cand[x], cand[r]);\n                    swap(vv[x], vv[r]);\n                    swap(pri[x], pri[r]);\n                }\n\n                for (int x = 1; x < k; x++) {\n                    int bc = cand[x], bv = vv[x], bp = pri[x];\n                    int y = x - 1;\n                    while (y >= 0 && (pri[y] > bp || (pri[y] == bp && vv[y] > bv))) {\n                        pri[y + 1] = pri[y];\n                        vv[y + 1] = vv[y];\n                        cand[y + 1] = cand[y];\n                        --y;\n                    }\n                    pri[y + 1] = bp;\n                    vv[y + 1] = bv;\n                    cand[y + 1] = bc;\n                }\n\n                for (int q = 0; q < k; q++) {\n                    if (try_change(i, j, cand[q])) {\n                        changed = true;\n                        ++totalChanges;\n\n                        int now = g[i][j];\n                        if (now > 0 && pb->canZero[now]) {\n                            if (try_change(i, j, 0)) ++totalChanges;\n                        }\n                        totalChanges += local_delete_burst(i, j, 4);\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return totalChanges;\n    }\n\n    int greedy_delete_queue(mt19937& rng, Clock::time_point deadline, int maxPop) {\n        int total = pb->n * pb->n;\n        deque<int> dq;\n        vector<unsigned char> inq(total, 0);\n\n        static const int dx[4] = {-1, 1, 0, 0};\n        static const int dy[4] = {0, 0, -1, 1};\n\n        auto same_deg = [&](int i, int j) {\n            int c = g[i][j];\n            if (c <= 0) return 4;\n            int s = 0;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (in(ni, nj) && g[ni][nj] == c) ++s;\n            }\n            return s;\n        };\n\n        auto push_cell = [&](int i, int j) {\n            int id = i * pb->n + j;\n            if (inq[id]) return;\n            inq[id] = 1;\n            int c = g[i][j];\n            if (c > 0 && same_deg(i, j) <= 1) dq.push_front(id);\n            else dq.push_back(id);\n        };\n\n        for (int i = 0; i < pb->n; i++) {\n            for (int j = 0; j < pb->n; j++) {\n                int a = g[i][j];\n                if (a == 0 || !pb->canZero[a]) continue;\n                if (near_zero_cell(i, j)) push_cell(i, j);\n            }\n        }\n\n        int pops = 0, changes = 0;\n        while (!dq.empty() && pops < maxPop) {\n            if ((pops & 255) == 0 && Clock::now() >= deadline) break;\n\n            int id = dq.front();\n            dq.pop_front();\n            inq[id] = 0;\n            ++pops;\n\n            int i = id / pb->n, j = id % pb->n;\n            int a = g[i][j];\n            if (a == 0 || !pb->canZero[a]) continue;\n            if (!near_zero_cell(i, j)) continue;\n\n            if (try_change(i, j, 0)) {\n                ++changes;\n                push_cell(i, j);\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (in(ni, nj)) push_cell(ni, nj);\n                }\n            }\n        }\n        return changes;\n    }\n\n    int random_neutral_moves(mt19937& rng, Clock::time_point deadline, int steps) {\n        int success = 0;\n        int total = pb->n * pb->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 s = 0; s < steps; s++) {\n            if ((s & 63) == 0 && Clock::now() >= deadline) break;\n            for (int rep = 0; rep < 8; rep++) {\n                int idx = (int)(rng() % total);\n                int i = idx / pb->n, j = idx % pb->n;\n                int a = g[i][j];\n                if (a <= 0) continue;\n\n                int dirs[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    int b = g[ni][nj];\n                    if (b > 0 && b != a) dirs[k++] = d;\n                }\n                if (k == 0) continue;\n\n                int d = dirs[(int)(rng() % k)];\n                int ni = i + dx[d], nj = j + dy[d];\n                int b = g[ni][nj];\n\n                int op = (int)(rng() % 100);\n                bool ok = false;\n                if (op < 24) ok = try_swap(i, j, ni, nj);\n                else if (op < 66) ok = try_change(i, j, b);\n                else ok = try_change(ni, nj, a);\n\n                if (ok) ++success;\n                break;\n            }\n        }\n        return success;\n    }\n\n    int random_expand_moves(mt19937& rng, Clock::time_point deadline, int attempts) {\n        int success = 0;\n        int total = pb->n * pb->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 t = 0; t < attempts; t++) {\n            if ((t & 63) == 0 && Clock::now() >= deadline) break;\n\n            int idx = (int)(rng() % total);\n            int i = idx / pb->n, j = idx % pb->n;\n            if (g[i][j] != 0) continue;\n\n            int zdeg = 0;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (in(ni, nj) && g[ni][nj] == 0) ++zdeg;\n            }\n            bool boundary = (i == 0 || i == pb->n - 1 || j == 0 || j == pb->n - 1);\n            if (!boundary && zdeg >= 2 && (int)(rng() % 3) != 0) continue;\n\n            int cand[4], k = 0;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (!in(ni, nj)) continue;\n                int b = g[ni][nj];\n                if (b <= 0) continue;\n                bool dup = false;\n                for (int q = 0; q < k; q++) if (cand[q] == b) { dup = true; break; }\n                if (!dup) cand[k++] = b;\n            }\n            if (k == 0) continue;\n\n            int key[4];\n            for (int q = 0; q < k; q++) {\n                int b = cand[q];\n                key[q] = (pb->canZero[b] ? 0 : 10000) + pb->depth[b] * 120 + (int)(rng() % 32);\n            }\n            for (int x = 1; x < k; x++) {\n                int bc = cand[x], bk = key[x], y = x - 1;\n                while (y >= 0 && key[y] > bk) {\n                    key[y + 1] = key[y];\n                    cand[y + 1] = cand[y];\n                    --y;\n                }\n                key[y + 1] = bk;\n                cand[y + 1] = bc;\n            }\n\n            for (int q = 0; q < k; q++) {\n                if (try_change(i, j, cand[q])) {\n                    ++success;\n                    break;\n                }\n            }\n        }\n        return success;\n    }\n\n    int random_shift_zero_moves(mt19937& rng, Clock::time_point deadline, int steps) {\n        int success = 0;\n        int total = pb->n * pb->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 s = 0; s < steps; s++) {\n            if ((s & 63) == 0 && Clock::now() >= deadline) break;\n            for (int rep = 0; rep < 8; rep++) {\n                int idx = (int)(rng() % total);\n                int i = idx / pb->n, j = idx % pb->n;\n                int a = g[i][j];\n                if (a <= 0 || !pb->canZero[a]) continue;\n\n                int zni[4], znj[4], k = 0;\n                for (int d = 0; d < 4; d++) {\n                    int ni = i + dx[d], nj = j + dy[d];\n                    if (!in(ni, nj)) continue;\n                    if (g[ni][nj] == 0) {\n                        zni[k] = ni;\n                        znj[k] = nj;\n                        ++k;\n                    }\n                }\n                if (k == 0) continue;\n\n                int t = (int)(rng() % k);\n                int qi = zni[t], qj = znj[t];\n\n                ChangeRec r1, r2;\n                bool ok = false;\n\n                if (try_change_rec(qi, qj, a, r1)) {\n                    if (try_change_rec(i, j, 0, r2)) ok = true;\n                    else undo_change(r1);\n                }\n\n                if (!ok) {\n                    if (try_change_rec(i, j, 0, r1)) {\n                        if (try_change_rec(qi, qj, a, r2)) ok = true;\n                        else undo_change(r1);\n                    }\n                }\n\n                if (ok) ++success;\n                break;\n            }\n        }\n        return success;\n    }\n\n    int promote_noncan_near_zero(mt19937& rng, Clock::time_point deadline, int attempts) {\n        int success = 0;\n        int total = pb->n * pb->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 t = 0; t < attempts; t++) {\n            if ((t & 127) == 0 && Clock::now() >= deadline) break;\n\n            int idx = (int)(rng() % total);\n            int i = idx / pb->n, j = idx % pb->n;\n            int a = g[i][j];\n            if (a <= 0 || pb->canZero[a]) continue;\n\n            bool near0 = near_zero_cell(i, j);\n            if (!near0 && (int)(rng() % 5) != 0) continue;\n\n            int cand[4], k = 0;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + dx[d], nj = j + dy[d];\n                if (!in(ni, nj)) continue;\n                int b = g[ni][nj];\n                if (b <= 0 || b == a || !pb->canZero[b]) continue;\n                bool dup = false;\n                for (int q = 0; q < k; q++) if (cand[q] == b) { dup = true; break; }\n                if (!dup) cand[k++] = b;\n            }\n            if (k == 0) continue;\n\n            int key[4];\n            for (int q = 0; q < k; q++) {\n                int b = cand[q];\n                key[q] = pb->depth[b] * 200 + cnt[b] * 4 + (int)(rng() % 19);\n            }\n            for (int x = 1; x < k; x++) {\n                int bc = cand[x], bk = key[x], y = x - 1;\n                while (y >= 0 && key[y] > bk) {\n                    key[y + 1] = key[y];\n                    cand[y + 1] = cand[y];\n                    --y;\n                }\n                key[y + 1] = bk;\n                cand[y + 1] = bc;\n            }\n\n            for (int q = 0; q < k; q++) {\n                if (try_change(i, j, cand[q])) {\n                    ++success;\n                    if (near0) {\n                        if (try_change(i, j, 0)) ++success;\n                    }\n                    break;\n                }\n            }\n        }\n        return success;\n    }\n};\n\nstatic vector<int> build_value(const Problem& pb, const State& st, int mode, mt19937& rng, int maxDepth) {\n    vector<int> value(pb.m + 1, 0);\n    value[0] = -1;\n\n    vector<int> cols(pb.m);\n    for (int i = 0; i < pb.m; i++) cols[i] = i + 1;\n    shuffle(cols.begin(), cols.end(), rng);\n\n    vector<int> prio(pb.m + 1, 0);\n    for (int i = 0; i < pb.m; i++) prio[cols[i]] = i;\n\n    for (int c = 1; c <= pb.m; c++) {\n        switch (mode) {\n            case 0: value[c] = pb.depth[c] * 10000 + prio[c]; break;\n            case 1: value[c] = prio[c]; break;\n            case 2: value[c] = (maxDepth - pb.depth[c]) * 10000 + prio[c]; break;\n            case 3: value[c] = (pb.canZero[c] ? 0 : 250000) + pb.depth[c] * 1200 + prio[c]; break;\n            case 4: value[c] = (pb.m - pb.deg[c]) * 5000 + pb.depth[c] * 60 + prio[c]; break;\n            case 5: value[c] = st.cnt[c] * 850 + pb.depth[c] * 35 + prio[c]; break;\n            case 6: value[c] = (pb.canZero[c] ? st.cnt[c] * 220 : 90000 + st.cnt[c] * 220)\n                              + pb.depth[c] * 80 + prio[c]; break;\n            default: value[c] = (pb.canZero[c] ? 0 : 450000) + pb.depth[c] * 220 + st.cnt[c] * 45 + prio[c]; break;\n        }\n    }\n    return value;\n}\n\nbool validate_solution(const State& st) {\n    const Problem& pb = *st.pb;\n    int n = pb.n, m = pb.m;\n\n    array<int, CMAX> realCnt{};\n    realCnt.fill(0);\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (c < 0 || c > m) return false;\n            ++realCnt[c];\n        }\n    }\n    for (int c = 1; c <= m; c++) if (realCnt[c] == 0) return false;\n\n    array<array<bool, CMAX>, CMAX> adj{};\n    for (auto& row : adj) row.fill(false);\n\n    auto add_adj = [&](int a, int b) {\n        if (a == b) return;\n        adj[a][b] = adj[b][a] = true;\n    };\n\n    for (int i = 0; i < n; i++) {\n        for (int j = 0; j < n; j++) {\n            int c = st.g[i][j];\n            if (i + 1 < n) add_adj(c, st.g[i + 1][j]);\n            if (j + 1 < n) add_adj(c, st.g[i][j + 1]);\n            if (i == 0) add_adj(0, c);\n            if (i == n - 1) add_adj(0, c);\n            if (j == 0) add_adj(0, c);\n            if (j == n - 1) add_adj(0, c);\n        }\n    }\n\n    for (int u = 0; u <= m; u++) {\n        for (int v = u + 1; v <= m; v++) {\n            if (adj[u][v] != pb.targetAdj[u][v]) return false;\n        }\n    }\n\n    static const int dx[4] = {-1, 1, 0, 0};\n    static const int dy[4] = {0, 0, -1, 1};\n    auto in = [&](int x, int y) { return (0 <= x && x < n && 0 <= y && y < n); };\n\n    array<array<int, NMAX>, NMAX> vis{};\n    for (auto& row : vis) row.fill(0);\n    int token = 1;\n\n    // non-zero connectivity\n    for (int color = 1; color <= m; color++) {\n        int si = -1, sj = -1;\n        for (int i = 0; i < n && si == -1; i++) {\n            for (int j = 0; j < n; j++) {\n                if (st.g[i][j] == color) {\n                    si = i; sj = j;\n                    break;\n                }\n            }\n        }\n        if (si == -1) return false;\n\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n        vis[si][sj] = token;\n        qx[tail] = si;\n        qy[tail] = sj;\n        ++tail;\n\n        int reached = 1;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != color) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[color]) return false;\n    }\n\n    // zero connectivity through outside\n    if (realCnt[0] > 0) {\n        ++token;\n        int qx[NMAX * NMAX], qy[NMAX * NMAX];\n        int head = 0, tail = 0;\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                if (i != 0 && i != n - 1 && j != 0 && j != n - 1) continue;\n                if (st.g[i][j] != 0) continue;\n                if (vis[i][j] == token) continue;\n                vis[i][j] = token;\n                qx[tail] = i;\n                qy[tail] = j;\n                ++tail;\n            }\n        }\n        if (tail == 0) return false;\n\n        int reached = tail;\n        while (head < tail) {\n            int x = qx[head], y = qy[head];\n            ++head;\n            for (int d = 0; d < 4; d++) {\n                int nx = x + dx[d], ny = y + dy[d];\n                if (!in(nx, ny)) continue;\n                if (vis[nx][ny] == token) continue;\n                if (st.g[nx][ny] != 0) continue;\n                vis[nx][ny] = token;\n                qx[tail] = nx;\n                qy[tail] = ny;\n                ++tail;\n                ++reached;\n            }\n        }\n        if (reached != realCnt[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Problem pb;\n    cin >> pb.n >> pb.m;\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) cin >> pb.initGrid[i][j];\n    }\n\n    pb.initCnt.fill(0);\n    for (auto& row : pb.initEdgeCnt) row.fill(0);\n    for (auto& row : pb.targetAdj) row.fill(false);\n    pb.canZero.fill(false);\n    pb.depth.fill(INF);\n    pb.deg.fill(0);\n\n    auto add_edge_count = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        pb.initEdgeCnt[a][b]++;\n    };\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            int c = pb.initGrid[i][j];\n            ++pb.initCnt[c];\n\n            if (i + 1 < pb.n) add_edge_count(c, pb.initGrid[i + 1][j]);\n            if (j + 1 < pb.n) add_edge_count(c, pb.initGrid[i][j + 1]);\n\n            if (i == 0) add_edge_count(0, c);\n            if (i == pb.n - 1) add_edge_count(0, c);\n            if (j == 0) add_edge_count(0, c);\n            if (j == pb.n - 1) add_edge_count(0, c);\n        }\n    }\n\n    for (int u = 0; u <= pb.m; u++) {\n        for (int v = u + 1; v <= pb.m; v++) {\n            if (pb.initEdgeCnt[u][v] > 0) pb.targetAdj[u][v] = pb.targetAdj[v][u] = true;\n        }\n    }\n\n    int canZeroCnt = 0;\n    for (int c = 1; c <= pb.m; c++) {\n        pb.canZero[c] = pb.targetAdj[0][c];\n        if (pb.canZero[c]) ++canZeroCnt;\n    }\n\n    for (int c = 0; c <= pb.m; c++) {\n        int d = 0;\n        for (int to = 0; to <= pb.m; to++) if (c != to && pb.targetAdj[c][to]) ++d;\n        pb.deg[c] = d;\n    }\n\n    // BFS depth from 0\n    queue<int> q;\n    pb.depth[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        for (int to = 0; to <= pb.m; to++) {\n            if (!pb.targetAdj[v][to]) continue;\n            if (pb.depth[to] != INF) continue;\n            pb.depth[to] = pb.depth[v] + 1;\n            q.push(to);\n        }\n    }\n    for (int c = 0; c <= pb.m; c++) if (pb.depth[c] == INF) pb.depth[c] = 50;\n    int maxDepth = 1;\n    for (int c = 1; c <= pb.m; c++) maxDepth = max(maxDepth, pb.depth[c]);\n\n    // RNG seed\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < pb.n; i++) for (int j = 0; j < pb.n; j++) {\n        h ^= (uint64_t)(pb.initGrid[i][j] + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));\n    }\n    h ^= (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n    auto start = Clock::now();\n    auto deadline = start + chrono::milliseconds(1910);\n\n    int exploreMs = 1500;\n    if (canZeroCnt <= 35) exploreMs = 1460;\n    else if (canZeroCnt >= 55) exploreMs = 1560;\n    auto exploreEnd = start + chrono::milliseconds(exploreMs);\n\n    struct Key { int z, p, nc; };\n    auto better_key = [&](const Key& A, const Key& B) {\n        if (A.z != B.z) return A.z > B.z;\n        if (A.p != B.p) return A.p > B.p;\n        return A.nc < B.nc;\n    };\n    auto equal_key = [&](const Key& A, const Key& B) {\n        return A.z == B.z && A.p == B.p && A.nc == B.nc;\n    };\n\n    State initState(&pb);\n\n    array<State, 3> elite;\n    array<Key, 3> ekey;\n    array<bool, 3> has{false, false, false};\n\n    auto make_key = [&](const State& s) -> Key {\n        return Key{ s.zeroCount, s.frontier_potential(), s.nonCanMass };\n    };\n\n    auto insert_elite = [&](const State& s) {\n        Key k = make_key(s);\n        auto lucky = [&]() { return (rng() & 15u) == 0u; }; // equal-key diversity\n        for (int pos = 0; pos < 3; pos++) {\n            if (!has[pos] || better_key(k, ekey[pos]) || (has[pos] && equal_key(k, ekey[pos]) && lucky())) {\n                for (int t = 2; t > pos; t--) {\n                    elite[t] = elite[t - 1];\n                    ekey[t] = ekey[t - 1];\n                    has[t] = has[t - 1];\n                }\n                elite[pos] = s;\n                ekey[pos] = k;\n                has[pos] = true;\n                return;\n            }\n        }\n    };\n\n    insert_elite(initState);\n\n    vector<int> dummy(pb.m + 1, 0);\n\n    auto local_opt = [&](State& st, int rounds, int polish, Clock::time_point phaseDeadline, bool late) {\n        for (int r = 0; r < rounds; r++) {\n            if (Clock::now() >= phaseDeadline) return;\n\n            int mode = 0;\n            int roll = (int)(rng() % 100);\n            if (!late) {\n                if (roll < 24) mode = 0;\n                else if (roll < 36) mode = 1;\n                else if (roll < 44) mode = 2;\n                else if (roll < 62) mode = 3;\n                else if (roll < 70) mode = 4;\n                else if (roll < 80) mode = 5;\n                else if (roll < 90) mode = 6;\n                else mode = 7;\n            } else {\n                if (roll < 50) mode = 7;\n                else if (roll < 80) mode = 0;\n                else if (roll < 95) mode = 3;\n                else mode = 5;\n            }\n\n            auto value = build_value(pb, st, mode, rng, maxDepth);\n\n            int passes = 8, eqProb = 6, upProb = 0;\n            switch (mode) {\n                case 0: passes = 11; eqProb = 8; upProb = 0; break;\n                case 1: passes = 7;  eqProb = 3; upProb = 14; break;\n                case 2: passes = 6;  eqProb = 4; upProb = 10; break;\n                case 3: passes = 10; eqProb = 8; upProb = 0; break;\n                case 4: passes = 8;  eqProb = 6; upProb = 12; break;\n                case 5: passes = 8;  eqProb = 6; upProb = 8; break;\n                case 6: passes = 8;  eqProb = 6; upProb = 8; break;\n                case 7: passes = 9;  eqProb = 7; upProb = 4; break;\n            }\n\n            st.improve(value, rng, phaseDeadline, passes, true, eqProb, upProb);\n\n            if (!late) {\n                if ((r & 1) == 0) st.random_shift_zero_moves(rng, phaseDeadline, 10 + (int)(rng() % 18));\n                if ((r % 3) == 0) st.random_neutral_moves(rng, phaseDeadline, 8 + (int)(rng() % 14));\n                if (st.nonCanMass > 220 && (r % 3) == 0) st.promote_noncan_near_zero(rng, phaseDeadline, 6);\n            } else {\n                if ((r & 1) == 0) st.random_shift_zero_moves(rng, phaseDeadline, 4 + (int)(rng() % 6));\n            }\n\n            st.greedy_delete_queue(rng, phaseDeadline, 4200 + polish * 1600);\n        }\n\n        if (st.nonCanMass > 220) st.promote_noncan_near_zero(rng, phaseDeadline, late ? 8 : 12);\n        st.random_shift_zero_moves(rng, phaseDeadline, 10 + (int)(rng() % 14));\n        int ch = st.greedy_delete_queue(rng, phaseDeadline, 8500 + polish * 2200);\n        st.improve(dummy, rng, phaseDeadline, 3 + polish, false, 0, 0);\n        if (ch > 0) st.greedy_delete_queue(rng, phaseDeadline, 5600 + polish * 1400);\n    };\n\n    // initial seeds\n    if (Clock::now() < exploreEnd) {\n        State s = initState;\n        local_opt(s, 6, 2, exploreEnd, false);\n        insert_elite(s);\n    }\n    if (Clock::now() < exploreEnd) {\n        State s = initState;\n        s.random_neutral_moves(rng, exploreEnd, 70);\n        s.random_shift_zero_moves(rng, exploreEnd, 35);\n        local_opt(s, 5, 1, exploreEnd, false);\n        insert_elite(s);\n    }\n    if (Clock::now() < exploreEnd) {\n        State s = initState;\n        s.random_expand_moves(rng, exploreEnd, 80);\n        s.random_shift_zero_moves(rng, exploreEnd, 30);\n        local_opt(s, 5, 1, exploreEnd, false);\n        insert_elite(s);\n    }\n\n    int stagnation = 0;\n\n    int k1 = 45, k2 = 82;\n    if (canZeroCnt <= 35) { k1 = 35; k2 = 72; }\n    else if (canZeroCnt >= 55) { k1 = 55; k2 = 88; }\n\n    while (Clock::now() < exploreEnd) {\n        Key prev = ekey[0];\n\n        State cand;\n        int pick = (int)(rng() % 100);\n        if (!has[1] || pick < 58) cand = elite[0];\n        else if (!has[2] || pick < 82) cand = elite[1];\n        else if (pick < 94) cand = elite[2];\n        else cand = initState;\n\n        int kickType = (int)(rng() % 100);\n        if (kickType < k1) {\n            cand.random_shift_zero_moves(rng, exploreEnd, 18 + (int)(rng() % 28));\n            cand.random_neutral_moves(rng, exploreEnd, 10 + (int)(rng() % 22));\n        } else if (kickType < k2) {\n            int ex = 28 + (int)(rng() % 60) + min(70, stagnation * 2);\n            cand.random_expand_moves(rng, exploreEnd, ex);\n            cand.random_shift_zero_moves(rng, exploreEnd, 14 + (int)(rng() % 24));\n            cand.random_neutral_moves(rng, exploreEnd, 10 + (int)(rng() % 18));\n        } else {\n            int ex = 85 + (int)(rng() % 140) + min(120, stagnation * 3);\n            cand.random_expand_moves(rng, exploreEnd, ex);\n            cand.random_shift_zero_moves(rng, exploreEnd, 30 + (int)(rng() % 40));\n            cand.random_neutral_moves(rng, exploreEnd, 24 + (int)(rng() % 34));\n        }\n\n        int rounds = 2 + (int)(rng() % 3);\n        int polish = 1;\n        if (stagnation > 10) { rounds++; polish = 2; }\n        if (stagnation > 18) rounds++;\n\n        local_opt(cand, rounds, polish, exploreEnd, false);\n        insert_elite(cand);\n\n        if (better_key(ekey[0], prev)) stagnation = 0;\n        else stagnation++;\n\n        if (stagnation >= 20 && Clock::now() < exploreEnd) {\n            State alt = elite[0];\n            alt.random_expand_moves(rng, exploreEnd, 170 + (int)(rng() % 140));\n            alt.random_shift_zero_moves(rng, exploreEnd, 70 + (int)(rng() % 60));\n            alt.random_neutral_moves(rng, exploreEnd, 60 + (int)(rng() % 50));\n            local_opt(alt, 5, 2, exploreEnd, false);\n\n            prev = ekey[0];\n            insert_elite(alt);\n            if (better_key(ekey[0], prev)) {\n                stagnation = 0;\n            } else {\n                State rst = initState;\n                local_opt(rst, 4, 1, exploreEnd, false);\n                prev = ekey[0];\n                insert_elite(rst);\n                if (better_key(ekey[0], prev)) stagnation = 0;\n                else stagnation = 10;\n            }\n        }\n    }\n\n    // Final portfolio polishing\n    vector<State> finals;\n    for (int i = 0; i < 3; i++) if (has[i]) finals.push_back(elite[i]);\n    while ((int)finals.size() < 3) finals.push_back(elite[0]);\n\n    auto late_step = [&](State& s, int variant) {\n        if (variant == 0) {\n            auto v7 = build_value(pb, s, 7, rng, maxDepth);\n            s.improve(v7, rng, deadline, 3, true, 7, 0);\n            auto v0 = build_value(pb, s, 0, rng, maxDepth);\n            s.improve(v0, rng, deadline, 2, true, 8, 0);\n            s.greedy_delete_queue(rng, deadline, 2600);\n            s.improve(dummy, rng, deadline, 1, false, 0, 0);\n        } else if (variant == 1) {\n            s.random_shift_zero_moves(rng, deadline, 5);\n            s.random_neutral_moves(rng, deadline, 4);\n            auto v3 = build_value(pb, s, 3, rng, maxDepth);\n            s.improve(v3, rng, deadline, 2, true, 7, 0);\n            s.greedy_delete_queue(rng, deadline, 2000);\n            s.improve(dummy, rng, deadline, 1, false, 0, 0);\n        } else {\n            s.random_expand_moves(rng, deadline, 18);\n            auto v0 = build_value(pb, s, 0, rng, maxDepth);\n            s.improve(v0, rng, deadline, 2, true, 8, 0);\n            s.random_shift_zero_moves(rng, deadline, 3);\n            s.greedy_delete_queue(rng, deadline, 2200);\n            s.improve(dummy, rng, deadline, 1, false, 0, 0);\n        }\n    };\n\n    int pattern[8] = {0, 0, 1, 0, 2, 0, 1, 0};\n    int turn = 0;\n    while (Clock::now() < deadline) {\n        int idx = pattern[turn & 7];\n        if (idx >= (int)finals.size()) idx = 0;\n        late_step(finals[idx], idx);\n        ++turn;\n    }\n\n    State ans = elite[0];\n    Key ansKey = make_key(ans);\n    for (auto& s : finals) {\n        Key k = make_key(s);\n        if (better_key(k, ansKey)) {\n            ans = s;\n            ansKey = k;\n        }\n    }\n\n    // safety fallback\n    if (!validate_solution(ans)) {\n        State fallback = initState;\n        Key fk = make_key(fallback);\n\n        auto try_take = [&](const State& s) {\n            if (!validate_solution(s)) return;\n            Key k = make_key(s);\n            if (better_key(k, fk)) {\n                fallback = s;\n                fk = k;\n            }\n        };\n\n        for (int i = 0; i < 3; i++) if (has[i]) try_take(elite[i]);\n        for (auto& s : finals) try_take(s);\n\n        ans = fallback;\n    }\n\n    for (int i = 0; i < pb.n; i++) {\n        for (int j = 0; j < pb.n; j++) {\n            if (j) cout << ' ';\n            cout << ans.g[i][j];\n        }\n        cout << '\\n';\n    }\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N = 0, D = 0, Q = 0;\n    int used = 0;\n    mt19937 rng;\n\n    // item-item comparison cache:\n    // 2: unknown, -1: a<b, 0: a=b, 1: a>b\n    vector<vector<int8_t>> cmp_cache;\n    vector<int> score_item; // wins-losses from fresh singleton comparisons\n\n    vector<double> harm;    // harmonic numbers\n\n    // current partition state\n    vector<int> assign;              // item -> bin\n    vector<vector<int>> bins;        // bin -> items\n    vector<double> bin_sum_est;      // estimated sum per bin\n\n    // estimated item info\n    vector<double> w_est;\n    vector<int> rank_pos;            // 0 = heaviest\n    double total_est = 0.0;\n\n    struct State {\n        vector<int> assign;\n        vector<vector<int>> bins;\n        vector<double> sum;\n    };\n\n    static int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 1, c = 0;\n        while (p < x) p <<= 1, ++c;\n        return c;\n    }\n\n    static int insertion_cost(int n) {\n        int c = 0;\n        for (int m = 1; m < n; ++m) c += ceil_log2_int(m + 1);\n        return c;\n    }\n\n    char ask_set(const vector<int>& L, const vector<int>& R) {\n        // judge requires both non-empty and disjoint\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n';\n        cout.flush();\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        if (s == \"-1\") exit(0);\n\n        ++used;\n        return s[0];\n    }\n\n    char ask_single_raw(int a, int b) {\n        vector<int> L{a}, R{b};\n        return ask_set(L, R);\n    }\n\n    // returns 1 if a>b, -1 if a<b, 0 equal\n    int cmp_item(int a, int b, bool update_score = true) {\n        int8_t v = cmp_cache[a][b];\n        if (v != 2) return (int)v;\n\n        char c = ask_single_raw(a, b);\n        int s = (c == '>') ? 1 : (c == '<' ? -1 : 0);\n\n        cmp_cache[a][b] = (int8_t)s;\n        cmp_cache[b][a] = (int8_t)(-s);\n\n        if (update_score) {\n            if (s > 0) { score_item[a]++; score_item[b]--; }\n            else if (s < 0) { score_item[a]--; score_item[b]++; }\n        }\n        return s;\n    }\n\n    vector<int> full_sort_items() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n        shuffle(items.begin(), items.end(), rng);\n\n        vector<int> ord;\n        ord.reserve(N);\n\n        for (int x : items) {\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                int s = cmp_item(x, ord[mid], true); // x ? ord[mid]\n                if (s > 0) hi = mid;          // x heavier\n                else if (s < 0) lo = mid + 1; // x lighter\n                else { lo = mid; hi = mid; break; }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    vector<int> sort_group_exact(const vector<int>& g) {\n        vector<int> ord;\n        ord.reserve(g.size());\n        for (int x : g) {\n            int lo = 0, hi = (int)ord.size();\n            while (lo < hi) {\n                int mid = (lo + hi) / 2;\n                int s = cmp_item(x, ord[mid], true);\n                if (s > 0) hi = mid;\n                else if (s < 0) lo = mid + 1;\n                else { lo = mid; hi = mid; break; }\n            }\n            ord.insert(ord.begin() + lo, x);\n        }\n        return ord;\n    }\n\n    // Low-Q ranking: impact-prioritized partitioning + partial polishing.\n    vector<int> partial_rank_focus(int budget_end) {\n        vector<int> all(N);\n        iota(all.begin(), all.end(), 0);\n        shuffle(all.begin(), all.end(), rng);\n\n        vector<vector<int>> groups(1, all);\n        vector<char> exact(1, 0);\n\n        // Stage 1: split groups by pivot where impact is high (heavy-rank + size).\n        while (used < budget_end) {\n            int rem = budget_end - used;\n            int best_idx = -1;\n            double best_key = -1.0;\n\n            int pref = 0; // start rank index of group\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (m >= 2 && m - 1 <= rem) {\n                    double rank_weight = harm[N] - harm[pref];\n                    double key = m * (rank_weight + 0.05);\n                    if (key > best_key) {\n                        best_key = key;\n                        best_idx = g;\n                    }\n                }\n                pref += m;\n            }\n            if (best_idx == -1) break;\n\n            vector<int> cur = groups[best_idx];\n            int m = (int)cur.size();\n            int pv = cur[uniform_int_distribution<int>(0, m - 1)(rng)];\n\n            vector<int> heavy, equalv, light;\n            equalv.push_back(pv);\n\n            for (int v : cur) {\n                if (v == pv) continue;\n                int s = cmp_item(v, pv, true);\n                if (s > 0) heavy.push_back(v);\n                else if (s < 0) light.push_back(v);\n                else equalv.push_back(v);\n            }\n\n            vector<vector<int>> repl;\n            vector<char> repl_exact;\n            if (!heavy.empty()) { repl.push_back(move(heavy)); repl_exact.push_back(0); }\n            if (!equalv.empty()) { repl.push_back(move(equalv)); repl_exact.push_back(0); }\n            if (!light.empty()) { repl.push_back(move(light)); repl_exact.push_back(0); }\n\n            groups.erase(groups.begin() + best_idx);\n            exact.erase(exact.begin() + best_idx);\n\n            groups.insert(groups.begin() + best_idx, repl.begin(), repl.end());\n            exact.insert(exact.begin() + best_idx, repl_exact.begin(), repl_exact.end());\n        }\n\n        // Stage 2: fully sort groups when affordable.\n        for (int g = 0; g < (int)groups.size(); ++g) {\n            int m = (int)groups[g].size();\n            if (m <= 1) { exact[g] = 1; continue; }\n            int need = insertion_cost(m);\n            if (used + need <= budget_end) {\n                groups[g] = sort_group_exact(groups[g]);\n                exact[g] = 1;\n            }\n        }\n\n        // Stage 3: leftover budget on unsorted impactful groups.\n        int stale = 0;\n        while (used < budget_end && stale < 3000) {\n            int best_idx = -1;\n            double best_key = -1.0;\n\n            int pref = 0;\n            for (int g = 0; g < (int)groups.size(); ++g) {\n                int m = (int)groups[g].size();\n                if (!exact[g] && m >= 2) {\n                    double rank_weight = harm[N] - harm[pref];\n                    double key = m * (rank_weight + 0.05);\n                    if (key > best_key) {\n                        best_key = key;\n                        best_idx = g;\n                    }\n                }\n                pref += m;\n            }\n            if (best_idx == -1) break;\n\n            auto& grp = groups[best_idx];\n            int m = (int)grp.size();\n            int a = grp[uniform_int_distribution<int>(0, m - 1)(rng)];\n            int b = a;\n            for (int t = 0; t < 8 && b == a; ++t) {\n                b = grp[uniform_int_distribution<int>(0, m - 1)(rng)];\n            }\n            if (a == b) { ++stale; continue; }\n\n            int before = used;\n            cmp_item(a, b, true);\n            if (used == before) ++stale;\n            else stale = 0;\n        }\n\n        // Flatten\n        vector<int> ord;\n        ord.reserve(N);\n        for (int g = 0; g < (int)groups.size(); ++g) {\n            if (exact[g]) {\n                for (int x : groups[g]) ord.push_back(x);\n            } else {\n                auto tmp = groups[g];\n                stable_sort(tmp.begin(), tmp.end(), [&](int a, int b) {\n                    if (score_item[a] != score_item[b]) return score_item[a] > score_item[b];\n                    return a < b;\n                });\n                for (int x : tmp) ord.push_back(x);\n            }\n        }\n        return ord;\n    }\n\n    void build_est_from_order(const vector<int>& order) {\n        w_est.assign(N, 1.0);\n        rank_pos.assign(N, N - 1);\n\n        total_est = 0.0;\n        for (int pos = 0; pos < N; ++pos) {\n            int id = order[pos];\n            rank_pos[id] = pos;\n            // Exponential order-stat shape\n            double w = harm[N] - harm[pos];\n            w_est[id] = w;\n            total_est += w;\n        }\n    }\n\n    void init_lpt(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        for (int id : order) {\n            int best = 0;\n            for (int b = 1; b < D; ++b) {\n                if (bin_sum_est[b] < bin_sum_est[best] - 1e-12) best = b;\n                else if (abs(bin_sum_est[b] - bin_sum_est[best]) <= 1e-12 &&\n                         bins[b].size() < bins[best].size()) best = b;\n            }\n            assign[id] = best;\n            bins[best].push_back(id);\n            bin_sum_est[best] += w_est[id];\n        }\n    }\n\n    void init_snake(const vector<int>& order) {\n        assign.assign(N, -1);\n        bins.assign(D, {});\n        bin_sum_est.assign(D, 0.0);\n\n        int per = max(1, 2 * D - 2);\n        for (int i = 0; i < N; ++i) {\n            int t = i % per;\n            int b = (t < D ? t : per - t);\n\n            int id = order[i];\n            assign[id] = b;\n            bins[b].push_back(id);\n            bin_sum_est[b] += w_est[id];\n        }\n    }\n\n    void move_item_g(int item, int to) {\n        int from = assign[item];\n        if (from == to) return;\n\n        auto& vf = bins[from];\n        for (int i = 0; i < (int)vf.size(); ++i) {\n            if (vf[i] == item) {\n                vf[i] = vf.back();\n                vf.pop_back();\n                break;\n            }\n        }\n\n        bins[to].push_back(item);\n        assign[item] = to;\n\n        bin_sum_est[from] -= w_est[item];\n        bin_sum_est[to] += w_est[item];\n    }\n\n    void swap_item_g(int i, int j) {\n        int a = assign[i], b = assign[j];\n        if (a == b) return;\n\n        auto& va = bins[a];\n        auto& vb = bins[b];\n\n        for (int& x : va) if (x == i) { x = j; break; }\n        for (int& x : vb) if (x == j) { x = i; break; }\n\n        assign[i] = b;\n        assign[j] = a;\n\n        double wi = w_est[i], wj = w_est[j];\n        bin_sum_est[a] += wj - wi;\n        bin_sum_est[b] += wi - wj;\n    }\n\n    inline double sq(double x) const { return x * x; }\n\n    double obj_sse() const {\n        double mean = total_est / D;\n        double s = 0.0;\n        for (int b = 0; b < D; ++b) s += sq(bin_sum_est[b] - mean);\n        return s;\n    }\n\n    void local_search_est(int iter_limit, bool allow_swap) {\n        double mean = total_est / D;\n\n        for (int iter = 0; iter < iter_limit; ++iter) {\n            double best_delta = -1e-12;\n            int type = 0;\n            int bi = -1, bj = -1, bt = -1;\n\n            // move\n            for (int i = 0; i < N; ++i) {\n                int a = assign[i];\n                if ((int)bins[a].size() <= 1) continue;\n                double wi = w_est[i];\n\n                for (int b = 0; b < D; ++b) {\n                    if (b == a) continue;\n                    double delta =\n                        sq(bin_sum_est[a] - wi - mean) +\n                        sq(bin_sum_est[b] + wi - mean) -\n                        sq(bin_sum_est[a] - mean) -\n                        sq(bin_sum_est[b] - mean);\n\n                    if (delta < best_delta) {\n                        best_delta = delta;\n                        type = 1;\n                        bi = i;\n                        bt = b;\n                    }\n                }\n            }\n\n            // swap\n            if (allow_swap) {\n                for (int i = 0; i < N; ++i) {\n                    for (int j = i + 1; j < N; ++j) {\n                        int a = assign[i], b = assign[j];\n                        if (a == b) continue;\n\n                        double wi = w_est[i], wj = w_est[j];\n                        double delta =\n                            sq(bin_sum_est[a] - wi + wj - mean) +\n                            sq(bin_sum_est[b] - wj + wi - mean) -\n                            sq(bin_sum_est[a] - mean) -\n                            sq(bin_sum_est[b] - mean);\n\n                        if (delta < best_delta) {\n                            best_delta = delta;\n                            type = 2;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n            }\n\n            if (type == 0) break;\n            if (type == 1) move_item_g(bi, bt);\n            else swap_item_g(bi, bj);\n        }\n    }\n\n    State capture() const {\n        return State{assign, bins, bin_sum_est};\n    }\n\n    void restore(const State& st) {\n        assign = st.assign;\n        bins = st.bins;\n        bin_sum_est = st.sum;\n    }\n\n    char cmp_bins(int a, int b) {\n        return ask_set(bins[a], bins[b]);\n    }\n\n    char cmp_after_move(int h, int l, int x) {\n        vector<int> L;\n        L.reserve((int)bins[h].size() - 1);\n        for (int v : bins[h]) if (v != x) L.push_back(v);\n\n        vector<int> R = bins[l];\n        R.push_back(x);\n\n        return ask_set(L, R);\n    }\n\n    void reinsert_bin(vector<int>& ord, int b) {\n        int lo = 0, hi = (int)ord.size();\n        while (lo < hi && used < Q) {\n            int mid = (lo + hi) / 2;\n            char c = cmp_bins(b, ord[mid]);\n            if (c == '>') hi = mid;   // b heavier\n            else lo = mid + 1;\n        }\n        ord.insert(ord.begin() + lo, b);\n    }\n\n    void refine_high() {\n        int rem = Q - used;\n        int need = insertion_cost(D) + 8;\n        if (rem < need) return;\n\n        vector<int> ord;\n        ord.reserve(D);\n        for (int b = 0; b < D; ++b) {\n            if (used >= Q) return;\n            reinsert_bin(ord, b);\n        }\n\n        int guard = 0;\n        while (used < Q && guard < 10000) {\n            ++guard;\n\n            int h = -1;\n            for (int id : ord) {\n                if ((int)bins[id].size() > 1) {\n                    h = id;\n                    break;\n                }\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int i = (int)ord.size() - 1; i >= 0; --i) {\n                if (ord[i] != h) { l = ord[i]; break; }\n            }\n            if (l == -1) break;\n\n            char base = cmp_bins(h, l);\n            if (base == '=') break;\n            if (base == '<') swap(h, l);\n\n            if ((int)bins[h].size() <= 1) break;\n\n            vector<int> cand = bins[h];\n            // light -> heavy for binary search\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (rank_pos[a] != rank_pos[b]) return rank_pos[a] > rank_pos[b];\n                return a < b;\n            });\n\n            int m = (int)cand.size();\n            int lo = -1, hi = m; // lo: too light ('>'), hi: heavy enough ('<'/'=')\n\n            while (hi - lo > 1 && used < Q) {\n                int mid = (lo + hi) / 2;\n                int x = cand[mid];\n                char c = cmp_after_move(h, l, x);\n                if (c == '>') lo = mid;\n                else hi = mid;\n            }\n\n            if (lo == -1 && hi == m) break;\n\n            int chosen;\n            if (lo == -1) chosen = cand[hi];\n            else if (hi == m) chosen = cand[lo];\n            else {\n                double diff = bin_sum_est[h] - bin_sum_est[l];\n                double e1 = fabs(diff - 2.0 * w_est[cand[lo]]);\n                double e2 = fabs(diff - 2.0 * w_est[cand[hi]]);\n                chosen = (e1 <= e2 ? cand[lo] : cand[hi]);\n            }\n\n            move_item_g(chosen, l);\n\n            auto it = find(ord.begin(), ord.end(), h);\n            if (it != ord.end()) ord.erase(it);\n            it = find(ord.begin(), ord.end(), l);\n            if (it != ord.end()) ord.erase(it);\n\n            if (used >= Q) break;\n            reinsert_bin(ord, h);\n            if (used >= Q) break;\n            reinsert_bin(ord, l);\n        }\n    }\n\n    void refine_simple(int max_steps) {\n        int stall = 0;\n        int last_item = -1, last_from = -1, last_to = -1;\n\n        for (int step = 0; step < max_steps && used < Q && stall < 2 * D + 6; ++step) {\n            int h = -1;\n            for (int b = 0; b < D; ++b) {\n                if ((int)bins[b].size() <= 1) continue;\n                if (h == -1 || bin_sum_est[b] > bin_sum_est[h]) h = b;\n            }\n            if (h == -1) break;\n\n            int l = -1;\n            for (int b = 0; b < D; ++b) {\n                if (b == h) continue;\n                if (l == -1 || bin_sum_est[b] < bin_sum_est[l]) l = b;\n            }\n            if (l == -1) break;\n\n            char c = cmp_bins(h, l);\n            if (c == '=') {\n                double avg = 0.5 * (bin_sum_est[h] + bin_sum_est[l]);\n                bin_sum_est[h] = avg;\n                bin_sum_est[l] = avg;\n                ++stall;\n                continue;\n            }\n            if (c == '<') {\n                swap(h, l);\n                if (bin_sum_est[h] < bin_sum_est[l]) {\n                    swap(bin_sum_est[h], bin_sum_est[l]);\n                }\n            }\n\n            if ((int)bins[h].size() <= 1) {\n                ++stall;\n                continue;\n            }\n\n            double diff = max(0.0, bin_sum_est[h] - bin_sum_est[l]);\n            int chosen = -1;\n            double best = 1e100;\n\n            for (int x : bins[h]) {\n                if (x == last_item && h == last_to && l == last_from) continue;\n                double v = fabs(diff - 2.0 * w_est[x]);\n                if (v < best) {\n                    best = v;\n                    chosen = x;\n                }\n            }\n            if (chosen == -1) {\n                for (int x : bins[h]) {\n                    if (chosen == -1 || w_est[x] < w_est[chosen]) chosen = x;\n                }\n            }\n            if (chosen == -1) {\n                ++stall;\n                continue;\n            }\n\n            move_item_g(chosen, l);\n            last_item = chosen;\n            last_from = h;\n            last_to = l;\n            stall = 0;\n        }\n    }\n\n    void fill_dummy() {\n        while (used < Q) {\n            ask_single_raw(0, 1);\n        }\n    }\n\n    void solve() {\n        if (!(cin >> N >> D >> Q)) return;\n\n        uint64_t seed = 0x9e3779b97f4a7c15ULL;\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)D * 9176ULL;\n        seed ^= (uint64_t)Q * 1315423911ULL;\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n\n        cmp_cache.assign(N, vector<int8_t>(N, 2));\n        for (int i = 0; i < N; ++i) cmp_cache[i][i] = 0;\n        score_item.assign(N, 0);\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        int full_cost = insertion_cost(N);\n        int rank_start = used;\n\n        vector<int> order;\n        if (Q >= full_cost) {\n            order = full_sort_items();\n        } else {\n            int reserve = min(max(4, D / 2), max(0, Q - (int)(1.7 * N)));\n            reserve = min(reserve, Q / 6);\n            int budget_end = Q - reserve;\n            if (budget_end < used) budget_end = used;\n\n            order = partial_rank_focus(budget_end);\n        }\n\n        int rank_used = used - rank_start;\n\n        // sanitize permutation\n        {\n            vector<int> seen(N, 0), clean;\n            clean.reserve(N);\n            for (int x : order) {\n                if (0 <= x && x < N && !seen[x]) {\n                    seen[x] = 1;\n                    clean.push_back(x);\n                }\n            }\n            for (int i = 0; i < N; ++i) if (!seen[i]) clean.push_back(i);\n            order.swap(clean);\n        }\n\n        build_est_from_order(order);\n        double conf = min(1.0, (double)rank_used / max(1, full_cost));\n\n        // Multi-start init: LPT vs snake\n        int iter = 170 + (int)(90.0 * conf);\n        bool allow_swap = true;\n\n        State best_state;\n        double best_obj = 1e100;\n\n        init_lpt(order);\n        local_search_est(iter, allow_swap);\n        best_state = capture();\n        best_obj = obj_sse();\n\n        init_snake(order);\n        local_search_est(iter, allow_swap);\n        double obj2 = obj_sse();\n        if (obj2 < best_obj) {\n            best_obj = obj2;\n            best_state = capture();\n        }\n\n        restore(best_state);\n\n        int rem = Q - used;\n        if (rem > 0) {\n            if (rem >= insertion_cost(D) + 10 && conf > 0.82) {\n                refine_high();\n                if (used < Q) refine_simple(min(D, Q - used));\n            } else {\n                refine_simple(min(Q - used, 3 * D + 10));\n            }\n        }\n\n        fill_dummy();\n\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << assign[i];\n        }\n        cout << '\\n';\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 200;\nconstexpr int MAXM = 10;\nconstexpr long long INF64 = (1LL << 60);\n\nint N, M;\n\nstruct Params {\n    int w_cross;\n    int w_near;\n    int near_th;\n    int w_height;\n    int w_top;\n    int w_empty;\n    int w_boundary;\n\n    bool operator==(const Params& o) const {\n        return w_cross == o.w_cross &&\n               w_near == o.w_near &&\n               near_th == o.near_th &&\n               w_height == o.w_height &&\n               w_top == o.w_top &&\n               w_empty == o.w_empty &&\n               w_boundary == o.w_boundary;\n    }\n};\n\nstruct State {\n    int len[MAXM];\n    int box[MAXM][MAXN]; // bottom -> top\n    int stk[MAXN + 1];   // box value -> stack id, -1 if removed\n    int pos[MAXN + 1];   // index in stack\n};\n\nstruct SegInfo {\n    int total;\n    int bottom;\n    int pref[MAXN + 1]; // # in segment <= v\n};\n\nstruct Result {\n    long long energy = INF64;\n    vector<pair<int, int>> ops;\n    Params param{};\n};\n\nstruct Trial {\n    long long e;\n    Params p;\n};\n\ninline void move_suffix(State& st, int src, int start, int dst) {\n    int k = st.len[src] - start;\n    int base = st.len[dst];\n    for (int i = 0; i < k; ++i) {\n        int v = st.box[src][start + i];\n        st.box[dst][base + i] = v;\n        st.stk[v] = dst;\n        st.pos[v] = base + i;\n    }\n    st.len[dst] += k;\n    st.len[src] = start;\n}\n\ninline void remove_target(State& st, int x) {\n    int s = st.stk[x];\n    st.len[s]--;\n    st.stk[x] = -1;\n    st.pos[x] = -1;\n}\n\ninline SegInfo build_seg_info(const State& st, int src, int start) {\n    SegInfo sg{};\n    sg.total = st.len[src] - start;\n    sg.bottom = st.box[src][start];\n\n    int freq[MAXN + 1];\n    memset(freq, 0, sizeof(freq));\n    for (int i = start; i < st.len[src]; ++i) {\n        ++freq[st.box[src][i]];\n    }\n\n    sg.pref[0] = 0;\n    for (int v = 1; v <= N; ++v) {\n        sg.pref[v] = sg.pref[v - 1] + freq[v];\n    }\n    return sg;\n}\n\ninline long long score_dest(\n    const State& st, int dst, int x, const Params& p, const SegInfo& sg\n) {\n    long long cross = 0;\n    long long nearv = 0;\n\n    for (int j = 0; j < st.len[dst]; ++j) {\n        int z = st.box[dst][j];\n        int cnt = sg.total - sg.pref[z]; // # moved boxes > z\n        if (cnt <= 0) continue;\n        cross += cnt;\n\n        int dz = z - x;\n        if (dz <= p.near_th) {\n            nearv += 1LL * cnt * (p.near_th + 1 - dz);\n        }\n    }\n\n    long long sc = 0;\n    sc += 1LL * p.w_cross * cross;\n    sc += 1LL * p.w_near * nearv;\n    sc += 1LL * p.w_height * st.len[dst];\n\n    if (st.len[dst] == 0) {\n        sc -= p.w_empty;\n    } else {\n        int top = st.box[dst][st.len[dst] - 1];\n        sc -= 1LL * p.w_top * top;\n        if (sg.bottom > top) {\n            sc += 1LL * p.w_boundary * (sg.bottom - top);\n        }\n    }\n    return sc;\n}\n\ninline int choose_best_dest(\n    const State& st, int src, int start, int x, const Params& p\n) {\n    SegInfo sg = build_seg_info(st, src, start);\n\n    long long bestSc = INF64;\n    int bestD = -1;\n\n    for (int d = 0; d < M; ++d) {\n        if (d == src) continue;\n        long long sc = score_dest(st, d, x, p, sg);\n\n        if (sc < bestSc ||\n            (sc == bestSc && (bestD == -1 ||\n                              st.len[d] < st.len[bestD] ||\n                              (st.len[d] == st.len[bestD] && d < bestD)))) {\n            bestSc = sc;\n            bestD = d;\n        }\n    }\n    return bestD;\n}\n\ninline int rank_destinations(\n    const State& st, int src, int start, int x, const Params& p,\n    array<pair<long long, int>, MAXM>& cand\n) {\n    SegInfo sg = build_seg_info(st, src, start);\n    int cnt = 0;\n    for (int d = 0; d < M; ++d) {\n        if (d == src) continue;\n        cand[cnt++] = {score_dest(st, d, x, p, sg), d};\n    }\n\n    sort(cand.begin(), cand.begin() + cnt,\n         [&](const auto& a, const auto& b) {\n             if (a.first != b.first) return a.first < b.first;\n             if (st.len[a.second] != st.len[b.second]) {\n                 return st.len[a.second] < st.len[b.second];\n             }\n             return a.second < b.second;\n         });\n    return cnt;\n}\n\nlong long simulate_base(State& st, int nextX, const Params& p, long long cutoff) {\n    long long energy = 0;\n    for (int x = nextX; x <= N; ++x) {\n        int s = st.stk[x];\n        int pos = st.pos[x];\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int d = choose_best_dest(st, s, start, x, p);\n            move_suffix(st, s, start, d);\n            energy += k + 1;\n            if (energy > cutoff) return energy;\n        }\n        remove_target(st, x);\n    }\n    return energy;\n}\n\nlong long solve_run(\n    const State& init, const Params& p, int candK,\n    vector<pair<int, int>>* outOps\n) {\n    State st = init;\n    long long energy = 0;\n\n    if (outOps) {\n        outOps->clear();\n        outOps->reserve(700);\n    }\n\n    array<pair<long long, int>, MAXM> cand{};\n\n    for (int x = 1; x <= N; ++x) {\n        int s = st.stk[x];\n        int pos = st.pos[x];\n\n        if (pos + 1 < st.len[s]) {\n            int start = pos + 1;\n            int k = st.len[s] - start;\n            int chosenD = -1;\n\n            if (candK <= 1) {\n                chosenD = choose_best_dest(st, s, start, x, p);\n            } else {\n                int cnt = rank_destinations(st, s, start, x, p, cand);\n                int K = min(candK, cnt);\n\n                long long bestEst = INF64;\n                long long bestCheap = INF64;\n                int bestD = cand[0].second;\n\n                for (int ci = 0; ci < K; ++ci) {\n                    int d = cand[ci].second;\n                    long long cheap = cand[ci].first;\n\n                    State tmp = st;\n                    move_suffix(tmp, s, start, d);\n                    remove_target(tmp, x);\n\n                    long long cutoff = (bestEst >= INF64 / 4) ? INF64 : (bestEst - (k + 1));\n                    if (cutoff < 0) cutoff = 0;\n\n                    long long fut = simulate_base(tmp, x + 1, p, cutoff);\n                    long long est = (k + 1) + fut;\n\n                    if (est < bestEst ||\n                        (est == bestEst && cheap < bestCheap) ||\n                        (est == bestEst && cheap == bestCheap && d < bestD)) {\n                        bestEst = est;\n                        bestCheap = cheap;\n                        bestD = d;\n                    }\n                }\n                chosenD = bestD;\n            }\n\n            int vmove = st.box[s][start];\n            move_suffix(st, s, start, chosenD);\n            energy += k + 1;\n            if (outOps) outOps->push_back({vmove, chosenD + 1});\n        }\n\n        remove_target(st, x);\n        if (outOps) outOps->push_back({x, 0});\n    }\n\n    return energy;\n}\n\nvoid add_pool(vector<Trial>& pool, long long e, const Params& p, int lim) {\n    bool found = false;\n    for (auto& t : pool) {\n        if (t.p == p) {\n            if (e < t.e) t.e = e;\n            found = true;\n            break;\n        }\n    }\n    if (!found) pool.push_back({e, p});\n\n    sort(pool.begin(), pool.end(),\n         [](const Trial& a, const Trial& b) { return a.e < b.e; });\n\n    if ((int)pool.size() > lim) pool.resize(lim);\n}\n\nParams random_param(mt19937& rng) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n    Params p{};\n    p.w_cross = rnd(600, 1800);\n    p.w_near = rnd(0, 100);\n    p.near_th = rnd(8, 65);\n    p.w_height = rnd(-5, 12);\n    p.w_top = rnd(0, 12);\n    p.w_empty = rnd(0, 3800);\n    p.w_boundary = rnd(0, 80);\n    return p;\n}\n\nParams mutate_param(const Params& base, mt19937& rng, int strength) {\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    if (rnd(0, 99) < 10) return random_param(rng);\n\n    int s = max(1, strength);\n    Params p = base;\n    p.w_cross = clamp(base.w_cross + rnd(-130 * s, 130 * s), 450, 2200);\n    p.w_near = clamp(base.w_near + rnd(-10 * s, 10 * s), 0, 130);\n    p.near_th = clamp(base.near_th + rnd(-4 * s, 4 * s), 5, 75);\n    p.w_height = clamp(base.w_height + rnd(-2 * s, 2 * s), -8, 16);\n    p.w_top = clamp(base.w_top + rnd(-2 * s, 2 * s), 0, 16);\n    p.w_empty = clamp(base.w_empty + rnd(-220 * s, 220 * s), 0, 5000);\n    p.w_boundary = clamp(base.w_boundary + rnd(-6 * s, 6 * s), 0, 100);\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    State init{};\n\n    for (int i = 0; i < MAXM; ++i) init.len[i] = 0;\n    for (int v = 1; v <= MAXN; ++v) {\n        init.stk[v] = -1;\n        init.pos[v] = -1;\n    }\n\n    int h = N / M;\n    uint64_t seed = 1469598103934665603ULL;\n\n    for (int i = 0; i < M; ++i) {\n        init.len[i] = h;\n        for (int j = 0; j < h; ++j) {\n            int v;\n            cin >> v;\n            init.box[i][j] = v;\n            init.stk[v] = i;\n            init.pos[v] = j;\n\n            seed ^= (uint64_t)v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    uint64_t clk = (uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count();\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32) ^ clk));\n    auto rnd = [&](int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    };\n\n    vector<Params> presets = {\n        {1000, 10, 20, 1, 1,  800, 10},\n        {1000, 20, 24, 2, 1, 1200, 15},\n        {1050, 30, 28, 2, 2, 1500, 20},\n        {1100, 35, 32, 3, 2, 1700, 25},\n        { 900, 45, 20, 1, 3, 1300, 15},\n        {1200, 25, 40, 4, 1, 2000, 30},\n        { 950, 15, 18, 1, 2,  900,  8},\n        {1300, 20, 45, 5, 1, 2200, 35},\n    };\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    // Time plan\n    const double HARD = 1.80;\n    const double T1 = 0.55;\n    const double T2 = 1.35;\n\n    const int K_FAST = 1;\n    const int K_MID = 4;\n    const int K_FINAL = 7;\n    const int POOL_SZ = 24;\n\n    vector<Trial> pool;\n    Params bestFastP = presets[0];\n    long long bestFastE = INF64;\n\n    // Stage 1: fast coarse search (greedy base)\n    for (const auto& p : presets) {\n        if (elapsed() + 0.01 > T1) break;\n        long long e = solve_run(init, p, K_FAST, nullptr);\n        if (e < bestFastE) {\n            bestFastE = e;\n            bestFastP = p;\n        }\n        add_pool(pool, e, p, POOL_SZ);\n    }\n\n    if (pool.empty()) {\n        long long e = solve_run(init, bestFastP, K_FAST, nullptr);\n        add_pool(pool, e, bestFastP, POOL_SZ);\n    }\n\n    while (elapsed() + 0.01 < T1) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 55) {\n            base = bestFastP;\n        } else if (r < 90 && !pool.empty()) {\n            int idx = rnd(0, min((int)pool.size() - 1, 7));\n            base = pool[idx].p;\n        } else {\n            base = presets[rnd(0, (int)presets.size() - 1)];\n        }\n\n        Params cand = mutate_param(base, rng, 2);\n        long long e = solve_run(init, cand, K_FAST, nullptr);\n        if (e < bestFastE) {\n            bestFastE = e;\n            bestFastP = cand;\n        }\n        add_pool(pool, e, cand, POOL_SZ);\n    }\n\n    Result bestRes;\n    bestRes.energy = INF64;\n\n    auto run_record = [&](const Params& p, int k) {\n        vector<pair<int, int>> ops;\n        long long e = solve_run(init, p, k, &ops);\n        if (e < bestRes.energy ||\n            (e == bestRes.energy && (bestRes.ops.empty() || ops.size() < bestRes.ops.size()))) {\n            bestRes.energy = e;\n            bestRes.ops = move(ops);\n            bestRes.param = p;\n        }\n    };\n\n    // Stage 2 init: evaluate top coarse candidates with medium rollout\n    int initTry = min((int)pool.size(), 8);\n    for (int i = 0; i < initTry && elapsed() + 0.06 < T2; ++i) {\n        run_record(pool[i].p, K_MID);\n    }\n    for (const auto& p : presets) {\n        if (elapsed() + 0.06 > T2) break;\n        run_record(p, K_MID);\n    }\n\n    if (bestRes.energy >= INF64 / 2) {\n        run_record(bestFastP, K_FAST);\n    }\n\n    auto eval_and_update = [&](const Params& p, int k, double est, bool addToPool) {\n        if (elapsed() + est * 1.5 > HARD) return;\n        long long e = solve_run(init, p, k, nullptr);\n        if (addToPool) add_pool(pool, e, p, POOL_SZ);\n        if (e < bestRes.energy && elapsed() + est < HARD) {\n            run_record(p, k);\n        }\n    };\n\n    // Stage 2: medium refinement\n    while (elapsed() + 0.06 * 1.5 < T2) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 60) {\n            base = bestRes.param;\n        } else if (r < 90 && !pool.empty()) {\n            int idx = rnd(0, min((int)pool.size() - 1, 9));\n            base = pool[idx].p;\n        } else {\n            base = presets[rnd(0, (int)presets.size() - 1)];\n        }\n\n        Params cand = mutate_param(base, rng, 1);\n        eval_and_update(cand, K_MID, 0.06, true);\n    }\n\n    // Stage 3: stronger rollout polish\n    eval_and_update(bestRes.param, K_FINAL, 0.10, false);\n    eval_and_update(bestRes.param, 9, 0.13, false);\n\n    for (int i = 0; i < min((int)pool.size(), 6) && elapsed() + 0.10 * 1.5 < HARD; ++i) {\n        eval_and_update(pool[i].p, K_FINAL, 0.10, false);\n    }\n\n    while (elapsed() + 0.10 * 1.5 < HARD) {\n        Params base;\n        int r = rnd(0, 99);\n        if (r < 75 || pool.empty()) {\n            base = bestRes.param;\n        } else {\n            int idx = rnd(0, min((int)pool.size() - 1, 9));\n            base = pool[idx].p;\n        }\n        Params cand = mutate_param(base, rng, 1);\n        eval_and_update(cand, K_FINAL, 0.10, false);\n    }\n\n    if (bestRes.ops.empty()) {\n        run_record(bestFastP, K_FAST);\n    }\n\n    for (auto [v, i] : bestRes.ops) {\n        cout << v << ' ' << i << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Metric {\n    long long total = 0;\n    int L = 0;\n    bool valid = false;\n};\n\nclass Solver {\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void read_input() {\n        cin >> N;\n        hWall.resize(N - 1);\n        for (int i = 0; i < N - 1; i++) cin >> hWall[i];\n        vWall.resize(N);\n        for (int i = 0; i < N; i++) cin >> vWall[i];\n\n        V = N * N;\n        dirt.resize(V);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                cin >> dirt[i * N + j];\n            }\n        }\n    }\n\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        build_graph();\n        precompute_apsp();\n\n        logd.resize(V);\n        for (int i = 0; i < V; i++) logd[i] = log(1.0 + (double)dirt[i]);\n\n        firstVisit.assign(V, -1);\n        prevVisit.assign(V, -1);\n        tri.assign(V, 0LL);\n\n        string dfsRoute = build_dfs_route();\n        Metric dfsM = evaluate(dfsRoute);\n\n        string bestRoute = dfsRoute;\n        Metric bestM = dfsM;\n\n        const double T_INIT = 0.30;\n        const double T_GAP  = 1.00;\n        const double T_RAND = 1.75;\n        const double T_END  = 1.88;\n\n        // Initial multi-start\n        int trial = 0;\n        while (elapsed() < T_INIT) {\n            string r;\n            if (trial % 3 == 0) {\n                double a = 0.2 + rnd01() * 1.8;\n                double b = 0.4 + rnd01() * 1.8;\n                double g = rnd01() * 0.6;\n                r = build_random_route(a, b, g);\n            } else {\n                double wD = rnd01() * 2.0;\n                double wR = rnd01() * 1.0;\n                double nz = 0.2 + rnd01() * 1.2;\n                r = build_weighted_dfs(wD, wR, nz);\n            }\n\n            if (!r.empty()) {\n                Metric m = evaluate(r);\n                if (better(m, bestM)) {\n                    bestM = m;\n                    bestRoute = std::move(r);\n                }\n            }\n            trial++;\n        }\n\n        string curRoute = bestRoute;\n        Metric curM = bestM;\n\n        long long sumd = 0;\n        int maxd = 0;\n        for (int x : dirt) {\n            sumd += x;\n            maxd = max(maxd, x);\n        }\n        double avgd = (double)sumd / max(1, V);\n        double skew = maxd / max(1.0, avgd);\n\n        int maxLen = 32000;\n        if (skew > 4.0) maxLen = 42000;\n        if (skew > 7.0) maxLen = 52000;\n        if (V < 900) maxLen += 6000;\n        maxLen = min(maxLen, 90000);\n\n        // Deterministic improve\n        while (elapsed() < T_GAP) {\n            bool improved = false;\n            if (improve_gap_best(curRoute, curM, T_GAP, maxLen)) improved = true;\n            if (elapsed() < T_GAP && improve_shorten_batch(curRoute, curM, T_GAP)) improved = true;\n\n            if (improved && better(curM, bestM)) {\n                bestM = curM;\n                bestRoute = curRoute;\n            }\n            if (!improved) break;\n        }\n\n        // High-d candidates and near lists\n        vector<int> highIds(V);\n        iota(highIds.begin(), highIds.end(), 0);\n        sort(highIds.begin(), highIds.end(), [&](int a, int b) {\n            if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n            return a < b;\n        });\n        if ((int)highIds.size() > 500) highIds.resize(500);\n\n        vector<vector<int>> nearTargets(V);\n        const int NEAR_DIST = 10;\n        for (int a = 0; a < V; a++) {\n            for (int x : highIds) {\n                int dd = (int)distMat[a][x];\n                if (dd > 0 && dd <= NEAR_DIST) nearTargets[a].push_back(x);\n            }\n        }\n\n        vector<int> pos = decode_positions(curRoute);\n        if (pos.empty()) {\n            curRoute = bestRoute;\n            curM = bestM;\n            pos = decode_positions(curRoute);\n        }\n        if (pos.empty()) {\n            curRoute = dfsRoute;\n            curM = dfsM;\n            pos = decode_positions(curRoute);\n        }\n        vector<int> cnt = build_counts(pos);\n\n        // Random hill-climb (improvement only)\n        int fail = 0;\n        while (elapsed() < T_RAND) {\n            string cand;\n            bool ok = false;\n\n            int op = (int)(rng() % 100);\n            if (op < 45) {\n                ok = make_random_loop_insert(curRoute, pos, nearTargets, highIds, cand, maxLen);\n            } else if (op < 65) {\n                ok = make_random_edge_insert(curRoute, pos, highIds, cand, maxLen);\n            } else if (op < 83) {\n                ok = make_random_shortcut(curRoute, pos, cnt, cand);\n            } else {\n                ok = make_random_loop_remove(curRoute, pos, cnt, cand);\n            }\n\n            if (!ok) {\n                fail++;\n                continue;\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, curM)) {\n                curRoute.swap(cand);\n                curM = m;\n                if (better(curM, bestM)) {\n                    bestM = curM;\n                    bestRoute = curRoute;\n                }\n                pos = decode_positions(curRoute);\n                if (pos.empty()) break;\n                cnt = build_counts(pos);\n                fail = 0;\n            } else {\n                fail++;\n            }\n\n            if (fail > 220 && elapsed() < T_RAND) {\n                bool improved = false;\n                if (improve_gap_best(curRoute, curM, T_RAND, maxLen)) improved = true;\n                if (elapsed() < T_RAND && improve_shorten_batch(curRoute, curM, T_RAND)) improved = true;\n\n                if (improved) {\n                    if (better(curM, bestM)) {\n                        bestM = curM;\n                        bestRoute = curRoute;\n                    }\n                    pos = decode_positions(curRoute);\n                    if (pos.empty()) break;\n                    cnt = build_counts(pos);\n                }\n                fail = 0;\n            }\n        }\n\n        // Final polish\n        curRoute = bestRoute;\n        curM = bestM;\n        while (elapsed() < T_END) {\n            bool improved = false;\n            if (improve_shorten_batch(curRoute, curM, T_END)) improved = true;\n            if (elapsed() < T_END && improve_gap_best(curRoute, curM, T_END, maxLen)) improved = true;\n\n            if (improved) {\n                if (better(curM, bestM)) {\n                    bestM = curM;\n                    bestRoute = curRoute;\n                }\n            } else {\n                break;\n            }\n        }\n\n        Metric fin = evaluate(bestRoute);\n        if (!fin.valid || (int)bestRoute.size() > 100000) {\n            bestRoute = dfsRoute; // guaranteed fallback\n        }\n        cout << bestRoute << '\\n';\n    }\n\nprivate:\n    int N = 0, V = 0;\n    vector<string> hWall, vWall;\n    vector<int> dirt;\n    vector<double> logd;\n\n    vector<int> row, col;\n    vector<vector<int>> adj;\n    vector<array<int, 4>> nxtMove; // U D L R\n\n    vector<vector<int16_t>> distMat, nextHop;\n    vector<int> dist0;\n\n    vector<int> firstVisit, prevVisit;\n    vector<long long> tri;\n\n    int dirMap[256]{};\n\n    mt19937_64 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    double rnd01() {\n        return (rng() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    void build_graph() {\n        fill(begin(dirMap), end(dirMap), -1);\n        dirMap[(unsigned char)'U'] = 0;\n        dirMap[(unsigned char)'D'] = 1;\n        dirMap[(unsigned char)'L'] = 2;\n        dirMap[(unsigned char)'R'] = 3;\n\n        row.resize(V);\n        col.resize(V);\n        adj.assign(V, {});\n        nxtMove.assign(V, array<int, 4>{-1, -1, -1, -1});\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                row[id] = i;\n                col[id] = j;\n\n                if (i > 0 && hWall[i - 1][j] == '0') {\n                    int to = (i - 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][0] = to;\n                }\n                if (i + 1 < N && hWall[i][j] == '0') {\n                    int to = (i + 1) * N + j;\n                    adj[id].push_back(to);\n                    nxtMove[id][1] = to;\n                }\n                if (j > 0 && vWall[i][j - 1] == '0') {\n                    int to = i * N + (j - 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][2] = to;\n                }\n                if (j + 1 < N && vWall[i][j] == '0') {\n                    int to = i * N + (j + 1);\n                    adj[id].push_back(to);\n                    nxtMove[id][3] = to;\n                }\n            }\n        }\n    }\n\n    void precompute_apsp() {\n        const int16_t INF = 30000;\n        distMat.assign(V, vector<int16_t>(V, INF));\n        nextHop.assign(V, vector<int16_t>(V, -1));\n\n        vector<int> q(V);\n\n        for (int s = 0; s < V; s++) {\n            auto &ds = distMat[s];\n            auto &ns = nextHop[s];\n            fill(ds.begin(), ds.end(), INF);\n            fill(ns.begin(), ns.end(), -1);\n\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            ds[s] = 0;\n            ns[s] = s;\n\n            while (head < tail) {\n                int u = q[head++];\n                for (int v : adj[u]) {\n                    if (ds[v] != INF) continue;\n                    ds[v] = ds[u] + 1;\n                    ns[v] = (u == s ? v : ns[u]);\n                    q[tail++] = v;\n                }\n            }\n        }\n\n        dist0.resize(V);\n        for (int i = 0; i < V; i++) dist0[i] = (int)distMat[0][i];\n    }\n\n    char dir_between(int u, int v) const {\n        if (row[v] == row[u] - 1) return 'U';\n        if (row[v] == row[u] + 1) return 'D';\n        if (col[v] == col[u] - 1) return 'L';\n        return 'R';\n    }\n\n    char opposite(char c) const {\n        if (c == 'U') return 'D';\n        if (c == 'D') return 'U';\n        if (c == 'L') return 'R';\n        return 'L';\n    }\n\n    Metric evaluate(const string &route) {\n        int L = (int)route.size();\n        if (L <= 0 || L > 100000) return Metric{0, L, false};\n\n        fill(firstVisit.begin(), firstVisit.end(), -1);\n        fill(prevVisit.begin(), prevVisit.end(), -1);\n        fill(tri.begin(), tri.end(), 0LL);\n\n        int cur = 0;\n        for (int t = 1; t <= L; t++) {\n            int d = dirMap[(unsigned char)route[t - 1]];\n            if (d < 0) return Metric{0, L, false};\n\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return Metric{0, L, false};\n\n            cur = nx;\n            if (prevVisit[cur] != -1) {\n                long long delta = t - prevVisit[cur];\n                tri[cur] += delta * (delta - 1) / 2;\n            } else {\n                firstVisit[cur] = t;\n            }\n            prevVisit[cur] = t;\n        }\n\n        if (cur != 0) return Metric{0, L, false};\n\n        long long total = 0;\n        for (int v = 0; v < V; v++) {\n            if (prevVisit[v] == -1) return Metric{0, L, false};\n            long long delta = (long long)firstVisit[v] + L - prevVisit[v];\n            tri[v] += delta * (delta - 1) / 2;\n            total += tri[v] * (long long)dirt[v];\n        }\n\n        return Metric{total, L, true};\n    }\n\n    bool better(const Metric &a, const Metric &b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        __int128 lhs = (__int128)a.total * b.L;\n        __int128 rhs = (__int128)b.total * a.L;\n        if (lhs != rhs) return lhs < rhs;\n        return a.L < b.L;\n    }\n\n    vector<int> decode_positions(const string &route) const {\n        int L = (int)route.size();\n        vector<int> pos(L + 1);\n        int cur = 0;\n        pos[0] = 0;\n\n        for (int i = 0; i < L; i++) {\n            int d = dirMap[(unsigned char)route[i]];\n            if (d < 0) return {};\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return {};\n            cur = nx;\n            pos[i + 1] = cur;\n        }\n        return pos;\n    }\n\n    vector<int> build_counts(const vector<int> &pos) const {\n        vector<int> cnt(V, 0);\n        for (int t = 1; t < (int)pos.size(); t++) cnt[pos[t]]++;\n        return cnt;\n    }\n\n    string path_between(int a, int b) const {\n        if (a == b) return \"\";\n        string p;\n        int u = a;\n        int guard = 0;\n        while (u != b) {\n            int v = (int)nextHop[u][b];\n            if (v < 0 || v == u) return \"\";\n            p.push_back(dir_between(u, v));\n            u = v;\n            if (++guard > 500000) return \"\";\n        }\n        return p;\n    }\n\n    string roundtrip_detour(int a, int target) const {\n        if (a == target) return \"\";\n        string fwd = path_between(a, target);\n        if (fwd.empty()) return \"\";\n        string det = fwd;\n        for (int i = (int)fwd.size() - 1; i >= 0; i--) det.push_back(opposite(fwd[i]));\n        return det;\n    }\n\n    string insert_detour(const string &route, int t, const string &det) const {\n        string out;\n        out.reserve(route.size() + det.size());\n        out.append(route, 0, t);\n        out += det;\n        out.append(route, t, route.size() - t);\n        return out;\n    }\n\n    string remove_segment(const string &route, int l, int len) const {\n        string out;\n        out.reserve(route.size() - len);\n        out.append(route, 0, l);\n        out.append(route, l + len, route.size() - (l + len));\n        return out;\n    }\n\n    string replace_segment(const string &route, int l, int r, const string &rep) const {\n        string out;\n        out.reserve(route.size() - (r - l) + rep.size());\n        out.append(route, 0, l);\n        out += rep;\n        out.append(route, r, route.size() - r);\n        return out;\n    }\n\n    string build_dfs_route() {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            vector<int> nbs = adj[u];\n            sort(nbs.begin(), nbs.end(), [&](int a, int b) {\n                if (dirt[a] != dirt[b]) return dirt[a] > dirt[b];\n                return a < b;\n            });\n\n            for (int v : nbs) {\n                if (vis[v]) continue;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_weighted_dfs(double wD, double wR, double noise) {\n        vector<char> vis(V, 0);\n        string route;\n        route.reserve(2 * V + 8);\n\n        function<void(int)> dfs = [&](int u) {\n            vis[u] = 1;\n            vector<pair<double, int>> cand;\n            cand.reserve(adj[u].size());\n\n            for (int v : adj[u]) {\n                if (vis[v]) continue;\n                double s = wD * logd[v] - wR * dist0[v] + noise * rnd01();\n                cand.push_back({s, v});\n            }\n\n            sort(cand.begin(), cand.end(), [](const auto &x, const auto &y) {\n                return x.first > y.first;\n            });\n\n            for (auto &kv : cand) {\n                int v = kv.second;\n                route.push_back(dir_between(u, v));\n                dfs(v);\n                route.push_back(dir_between(v, u));\n            }\n        };\n\n        dfs(0);\n        return route;\n    }\n\n    string build_random_route(double alpha, double beta, double gamma) {\n        vector<char> vis(V, 0);\n        vis[0] = 1;\n        int rem = V - 1;\n\n        int cur = 0;\n        string route;\n        route.reserve(V * 3);\n\n        while (rem > 0) {\n            if ((int)route.size() > 90000) return \"\";\n\n            int bestN = -1;\n            double bestS = -1e100;\n\n            for (int nb : adj[cur]) {\n                if (vis[nb]) continue;\n                int onward = 0;\n                for (int z : adj[nb]) if (!vis[z]) onward++;\n                double s = alpha * logd[nb] - beta * onward + rnd01() * 0.02;\n                if (s > bestS) {\n                    bestS = s;\n                    bestN = nb;\n                }\n            }\n\n            if (bestN != -1) {\n                route.push_back(dir_between(cur, bestN));\n                cur = bestN;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                continue;\n            }\n\n            int target = -1;\n            double bestV = 1e100;\n            for (int v = 0; v < V; v++) {\n                if (vis[v]) continue;\n                int dd = (int)distMat[cur][v];\n                double val = (double)dd - gamma * logd[v] + rnd01() * 0.02;\n                if (val < bestV) {\n                    bestV = val;\n                    target = v;\n                }\n            }\n            if (target < 0) return \"\";\n\n            while (cur != target) {\n                int nx = (int)nextHop[cur][target];\n                if (nx < 0 || nx == cur) return \"\";\n                route.push_back(dir_between(cur, nx));\n                cur = nx;\n                if (!vis[cur]) {\n                    vis[cur] = 1;\n                    rem--;\n                }\n                if ((int)route.size() > 90000) return \"\";\n            }\n        }\n\n        while (cur != 0) {\n            int nx = (int)nextHop[cur][0];\n            if (nx < 0 || nx == cur) return \"\";\n            route.push_back(dir_between(cur, nx));\n            cur = nx;\n            if ((int)route.size() > 90000) return \"\";\n        }\n\n        return route;\n    }\n\n    struct Cand {\n        double est;\n        int type; // 0: loop insert, 1: edge via target\n        int t;\n        int v;\n    };\n\n    bool improve_gap_best(string &route, Metric &curM, double timeLimit, int maxLen) {\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n\n        int L = (int)route.size();\n        if (L <= 0) return false;\n\n        vector<int> first(V, -1), last(V, -1), maxGap(V, 0), gapStart(V, 0);\n\n        for (int t = 1; t <= L; t++) {\n            int v = pos[t];\n            if (first[v] == -1) {\n                first[v] = last[v] = t;\n            } else {\n                int g = t - last[v];\n                if (g > maxGap[v]) {\n                    maxGap[v] = g;\n                    gapStart[v] = last[v];\n                }\n                last[v] = t;\n            }\n        }\n        for (int v = 0; v < V; v++) {\n            int g = first[v] + L - last[v];\n            if (g > maxGap[v]) {\n                maxGap[v] = g;\n                gapStart[v] = last[v];\n            }\n        }\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(V);\n        for (int v = 0; v < V; v++) {\n            if (maxGap[v] <= 2) continue;\n            long long g = maxGap[v];\n            long long pot = 1LL * dirt[v] * g * g;\n            ord.push_back({pot, v});\n        }\n        if (ord.empty()) return false;\n\n        sort(ord.begin(), ord.end(), greater<pair<long long, int>>());\n        int K = min((int)ord.size(), 220);\n\n        vector<Cand> cands;\n        cands.reserve(K * 14);\n\n        static const int frac[7] = {1, 2, 3, 4, 5, 6, 7};\n\n        for (int i = 0; i < K; i++) {\n            int v = ord[i].second;\n            long long pot = ord[i].first;\n            int g = maxGap[v];\n            int s = gapStart[v];\n\n            int maxExtra = max(8, min(80, g / 2 + 4));\n\n            for (int z = 0; z < 7; z++) {\n                int t = (int)((s + (long long)g * frac[z] / 8) % L);\n                int u = pos[t];\n\n                int d1 = (int)distMat[u][v];\n                if (d1 > 0) {\n                    int add = 2 * d1;\n                    if (add <= maxExtra && L + add <= maxLen) {\n                        double est = (double)pot / (add + 1.0);\n                        cands.push_back({est, 0, t, v});\n                    }\n                }\n\n                int w = pos[t + 1];\n                int d2 = (int)distMat[u][v];\n                int d3 = (int)distMat[v][w];\n                int via = d2 + d3;\n                int add = via - 1;\n                if (add > 0 && add <= maxExtra && L + add <= maxLen) {\n                    double est = 1.15 * (double)pot / (add + 1.0);\n                    cands.push_back({est, 1, t, v});\n                }\n            }\n        }\n\n        if (cands.empty()) return false;\n        sort(cands.begin(), cands.end(), [](const Cand &a, const Cand &b) {\n            return a.est > b.est;\n        });\n        if ((int)cands.size() > 70) cands.resize(70);\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (const auto &c : cands) {\n            if (elapsed() >= timeLimit) break;\n\n            string cand;\n            if (c.type == 0) {\n                string det = roundtrip_detour(pos[c.t], c.v);\n                if (det.empty()) continue;\n                cand = insert_detour(route, c.t, det);\n            } else {\n                int u = pos[c.t];\n                int w = pos[c.t + 1];\n                string p1 = path_between(u, c.v);\n                string p2 = path_between(c.v, w);\n                if ((int)distMat[u][c.v] > 0 && p1.empty()) continue;\n                if ((int)distMat[c.v][w] > 0 && p2.empty()) continue;\n                string rep = p1 + p2;\n                if ((int)rep.size() <= 1) continue;\n                cand = replace_segment(route, c.t, c.t + 1, rep);\n            }\n\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\n    }\n\n    static void add_delta_small(vector<int> &ids, vector<int> &delta, int v, int add) {\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (ids[i] == v) {\n                delta[i] += add;\n                return;\n            }\n        }\n        ids.push_back(v);\n        delta.push_back(add);\n    }\n\n    bool can_remove_closed(const vector<int> &pos, const vector<int> &cnt, int l, int r) const {\n        vector<int> ids, delta;\n        ids.reserve(r - l + 2);\n        delta.reserve(r - l + 2);\n\n        for (int t = l + 1; t <= r; t++) {\n            add_delta_small(ids, delta, pos[t], -1);\n        }\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    bool can_replace_segment(\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        int l, int r,\n        const string &rep\n    ) const {\n        vector<int> ids, delta;\n        ids.reserve((r - l) + (int)rep.size() + 4);\n        delta.reserve((r - l) + (int)rep.size() + 4);\n\n        for (int t = l + 1; t <= r; t++) add_delta_small(ids, delta, pos[t], -1);\n\n        int cur = pos[l];\n        for (char c : rep) {\n            int d = dirMap[(unsigned char)c];\n            if (d < 0) return false;\n            int nx = nxtMove[cur][d];\n            if (nx < 0) return false;\n            cur = nx;\n            add_delta_small(ids, delta, cur, +1);\n        }\n        if (cur != pos[r]) return false;\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            if (cnt[ids[i]] + delta[i] <= 0) return false;\n        }\n        return true;\n    }\n\n    int pick_target_near_anchor(int anchor, const vector<int> &highIds, int maxDist) {\n        int H = (int)highIds.size();\n        if (H == 0) return -1;\n\n        int best = -1;\n        double bestScore = -1e100;\n\n        for (int it = 0; it < 26; it++) {\n            int x;\n            if ((rng() % 100) < 85) {\n                x = highIds[(int)(rng() % H)];\n            } else {\n                x = (int)(rng() % V);\n            }\n            int dd = (int)distMat[anchor][x];\n            if (dd <= 0 || dd > maxDist) continue;\n            double sc = (double)dirt[x] / dd + rnd01() * 0.05;\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = x;\n            }\n        }\n        return best;\n    }\n\n    bool make_random_loop_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<vector<int>> &nearTargets,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L >= maxLen) return false;\n\n        int t = (int)(rng() % (L + 1));\n        int a = pos[t];\n\n        int chosen = -1;\n        double bestVal = -1e100;\n\n        const auto &lst = nearTargets[a];\n        if (!lst.empty()) {\n            int sample = min(10, (int)lst.size());\n            for (int s = 0; s < sample; s++) {\n                int x = lst[(int)(rng() % lst.size())];\n                int dd = (int)distMat[a][x];\n                if (dd <= 0) continue;\n                if (L + 2 * dd > maxLen) continue;\n                double v = (double)dirt[x] / dd + rnd01() * 0.03;\n                if (v > bestVal) {\n                    bestVal = v;\n                    chosen = x;\n                }\n            }\n        }\n\n        if (chosen < 0) {\n            int maxDist = 6 + (int)(rng() % 17); // 6..22\n            chosen = pick_target_near_anchor(a, highIds, maxDist);\n            if (chosen < 0) return false;\n            int dd = (int)distMat[a][chosen];\n            if (dd <= 0 || L + 2 * dd > maxLen) return false;\n        }\n\n        string det = roundtrip_detour(a, chosen);\n        if (det.empty()) return false;\n\n        cand = insert_detour(route, t, det);\n        return true;\n    }\n\n    bool make_random_edge_insert(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &highIds,\n        string &cand,\n        int maxLen\n    ) {\n        int L = (int)route.size();\n        if (L <= 0 || L >= maxLen) return false;\n\n        int t = (int)(rng() % L);\n        int u = pos[t];\n        int w = pos[t + 1];\n\n        int H = (int)highIds.size();\n        if (H == 0) return false;\n\n        int bestX = -1;\n        double bestVal = -1e100;\n\n        int maxVia = 10 + (int)(rng() % 18); // 10..27\n        for (int it = 0; it < 30; it++) {\n            int x;\n            if ((rng() % 100) < 90) {\n                x = highIds[(int)(rng() % H)];\n            } else {\n                x = (int)(rng() % V);\n            }\n\n            int d1 = (int)distMat[u][x];\n            int d2 = (int)distMat[x][w];\n            int via = d1 + d2;\n            int add = via - 1;\n            if (add <= 0) continue;\n            if (via > maxVia) continue;\n            if (L + add > maxLen) continue;\n\n            double val = (double)dirt[x] / add + rnd01() * 0.03;\n            if (val > bestVal) {\n                bestVal = val;\n                bestX = x;\n            }\n        }\n\n        if (bestX < 0) return false;\n\n        string p1 = (u == bestX ? \"\" : path_between(u, bestX));\n        string p2 = (bestX == w ? \"\" : path_between(bestX, w));\n        if ((int)distMat[u][bestX] > 0 && p1.empty()) return false;\n        if ((int)distMat[bestX][w] > 0 && p2.empty()) return false;\n\n        string rep = p1 + p2;\n        if ((int)rep.size() <= 1) return false;\n\n        cand = replace_segment(route, t, t + 1, rep);\n        return true;\n    }\n\n    bool make_random_loop_remove(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        if (L < 4) return false;\n\n        int maxSeg = min(120, L);\n        int len = 2 + (int)(rng() % (maxSeg - 1)); // 2..maxSeg\n        int l = (int)(rng() % (L - len + 1));\n        int r = l + len;\n\n        if (pos[l] != pos[r]) return false;\n        if (!can_remove_closed(pos, cnt, l, r)) return false;\n\n        cand = remove_segment(route, l, len);\n        return true;\n    }\n\n    bool make_random_shortcut(\n        const string &route,\n        const vector<int> &pos,\n        const vector<int> &cnt,\n        string &cand\n    ) {\n        int L = (int)route.size();\n        if (L < 6) return false;\n\n        int maxSpan = min(100, L);\n        int span = 3 + (int)(rng() % (maxSpan - 2)); // 3..maxSpan\n        int l = (int)(rng() % (L - span + 1));\n        int r = l + span;\n\n        int u = pos[l];\n        int v = pos[r];\n        int p = (int)distMat[u][v];\n        if (p <= 0 || p >= span) return false;\n\n        string rep = path_between(u, v);\n        if ((int)rep.size() != p) return false;\n\n        if (!can_replace_segment(pos, cnt, l, r, rep)) return false;\n        cand = replace_segment(route, l, r, rep);\n        return true;\n    }\n\n    bool improve_shorten_batch(string &route, Metric &curM, double timeLimit) {\n        vector<int> pos = decode_positions(route);\n        if (pos.empty()) return false;\n        vector<int> cnt = build_counts(pos);\n\n        int L = (int)route.size();\n        int attempts = (L < 8000 ? 120 : (L < 20000 ? 80 : 50));\n\n        Metric bestLocal = curM;\n        string bestRoute;\n\n        for (int it = 0; it < attempts && elapsed() < timeLimit; it++) {\n            string cand;\n            bool ok;\n            if ((rng() & 1ULL) == 0) {\n                ok = make_random_loop_remove(route, pos, cnt, cand);\n            } else {\n                ok = make_random_shortcut(route, pos, cnt, cand);\n            }\n            if (!ok) continue;\n\n            Metric m = evaluate(cand);\n            if (better(m, bestLocal)) {\n                bestLocal = m;\n                bestRoute = std::move(cand);\n            }\n        }\n\n        if (better(bestLocal, curM)) {\n            route = std::move(bestRoute);\n            curM = bestLocal;\n            return true;\n        }\n        return false;\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}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return int(next() % (uint64_t)n); }\n    double nextDouble() { return (next() >> 11) * (1.0 / 9007199254740992.0); } // [0,1)\n};\n\nstruct Solver {\n    static constexpr int INF = 1e9;\n\n    int N{}, M{}, V{};\n    int si{}, sj{}, startId{};\n    vector<string> board;\n    vector<string> words;\n\n    array<vector<int>, 26> occ{};\n    int distMat[225][225]{};\n\n    vector<vector<int>> ov; // overlap [0..4]\n\n    vector<int> lastChar, nEnd;\n\n    // exact evaluator\n    vector<vector<uint16_t>> firstEndCost; // first word from start -> end states\n    vector<size_t> transOffset;            // pair matrix offsets\n    vector<uint16_t> transData;            // flattened [nEnd[a] x nEnd[b]]\n\n    // approx guidance\n    vector<int> startApprox;\n    vector<vector<int>> edgeApprox; // min-based\n    vector<vector<int>> edgeGuide;  // average-best-rows for better guidance\n\n    // candidate lists\n    vector<vector<int>> candNext, candPrev;\n\n    chrono::steady_clock::time_point t0;\n    XorShift64 rng{};\n\n    struct MoveInfo {\n        uint8_t type; // 0 swap, 1 relocate\n        int i, j;\n        long long dA;\n    };\n\n    struct CandMove {\n        uint8_t type;\n        uint16_t i, j;\n        int dA;\n    };\n\n    struct Elite {\n        int e;\n        long long a;\n        vector<int> p;\n        uint64_t h;\n    };\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n        words.resize(M);\n        for (int i = 0; i < M; i++) cin >> words[i];\n        V = N * N;\n        startId = si * N + sj;\n    }\n\n    uint64_t makeSeed() const {\n        uint64_t h = 1469598103934665603ull;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (const auto& r : board) for (char c : r) mix((uint64_t)c);\n        for (const auto& w : words) for (char c : w) mix((uint64_t)c);\n        return h;\n    }\n\n    void computeOccAndDist() {\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 a = 0; a < V; a++) {\n            int ra = a / N, ca = a % N;\n            for (int b = 0; b < V; b++) {\n                int rb = b / N, cb = b % N;\n                distMat[a][b] = abs(ra - rb) + abs(ca - cb);\n            }\n        }\n    }\n\n    void computeOverlap() {\n        ov.assign(M, vector<int>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int best = 0;\n                for (int k = 4; k >= 0; k--) {\n                    bool ok = true;\n                    for (int x = 0; x < k; x++) {\n                        if (words[i][5 - k + x] != words[j][x]) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (ok) {\n                        best = k;\n                        break;\n                    }\n                }\n                ov[i][j] = best;\n            }\n        }\n    }\n\n    // Type words[w][begin..4] from one startCell.\n    // out size = nEnd[w], in order occ[lastChar[w]]\n    void endCostsSingleStartRaw(int startCell, int w, int begin, uint16_t* out) const {\n        int prevId[225], nextId[225];\n        int prevCost[225], nextCost[225];\n\n        int ps = 1;\n        prevId[0] = startCell;\n        prevCost[0] = 0;\n\n        for (int pos = begin; pos < 5; pos++) {\n            const auto& cells = occ[words[w][pos] - 'A'];\n            int ns = (int)cells.size();\n\n            for (int ni = 0; ni < ns; ni++) {\n                int q = cells[ni];\n                int best = INF;\n                for (int pi = 0; pi < ps; pi++) {\n                    int p = prevId[pi];\n                    int cand = prevCost[pi] + distMat[p][q] + 1;\n                    if (cand < best) best = cand;\n                }\n                nextId[ni] = q;\n                nextCost[ni] = best;\n            }\n\n            ps = ns;\n            for (int i = 0; i < ps; i++) {\n                prevId[i] = nextId[i];\n                prevCost[i] = nextCost[i];\n            }\n        }\n\n        for (int i = 0; i < ps; i++) out[i] = (uint16_t)prevCost[i];\n    }\n\n    void preprocessTransitionsAndApprox() {\n        lastChar.resize(M);\n        nEnd.resize(M);\n        for (int w = 0; w < M; w++) {\n            lastChar[w] = words[w][4] - 'A';\n            nEnd[w] = (int)occ[lastChar[w]].size();\n        }\n\n        firstEndCost.assign(M, {});\n        startApprox.assign(M, INF);\n        edgeApprox.assign(M, vector<int>(M, INF));\n        edgeGuide.assign(M, vector<int>(M, INF));\n\n        // first-word from initial finger\n        for (int w = 0; w < M; w++) {\n            firstEndCost[w].resize(nEnd[w]);\n            endCostsSingleStartRaw(startId, w, 0, firstEndCost[w].data());\n            int mn = INF;\n            for (uint16_t v : firstEndCost[w]) mn = min(mn, (int)v);\n            startApprox[w] = mn;\n        }\n\n        transOffset.assign((size_t)M * M + 1, 0);\n        size_t total = 0;\n        for (int a = 0; a < M; a++) {\n            for (int b = 0; b < M; b++) {\n                size_t id = (size_t)a * M + b;\n                total += (size_t)nEnd[a] * nEnd[b];\n                transOffset[id + 1] = total;\n            }\n        }\n        transData.assign(total, 0);\n\n        uint16_t row[225];\n\n        for (int a = 0; a < M; a++) {\n            const auto& starts = occ[lastChar[a]];\n            int na = nEnd[a];\n\n            for (int b = 0; b < M; b++) {\n                int nb = nEnd[b];\n                size_t id = (size_t)a * M + b;\n                size_t off = transOffset[id];\n                int begin = ov[a][b];\n\n                int mn = INF;\n                int best1 = INF, best2 = INF, best3 = INF;\n\n                for (int si = 0; si < na; si++) {\n                    endCostsSingleStartRaw(starts[si], b, begin, row);\n                    size_t base = off + (size_t)si * nb;\n\n                    int rmin = INF;\n                    for (int tj = 0; tj < nb; tj++) {\n                        int v = (int)row[tj];\n                        transData[base + tj] = row[tj];\n                        if (v < rmin) rmin = v;\n                    }\n\n                    mn = min(mn, rmin);\n\n                    if (rmin < best1) {\n                        best3 = best2;\n                        best2 = best1;\n                        best1 = rmin;\n                    } else if (rmin < best2) {\n                        best3 = best2;\n                        best2 = rmin;\n                    } else if (rmin < best3) {\n                        best3 = rmin;\n                    }\n                }\n\n                edgeApprox[a][b] = mn;\n                int cnt = min(na, 3);\n                int sum = 0;\n                if (cnt >= 1) sum += best1;\n                if (cnt >= 2) sum += best2;\n                if (cnt >= 3) sum += best3;\n                edgeGuide[a][b] = sum / cnt;\n            }\n        }\n    }\n\n    void buildCandidateLists(int C = 12) {\n        candNext.assign(M, {});\n        candPrev.assign(M, {});\n\n        for (int a = 0; a < M; a++) {\n            vector<pair<int,int>> v;\n            v.reserve(M - 1);\n            for (int b = 0; b < M; b++) if (b != a) v.emplace_back(edgeGuide[a][b], b);\n            sort(v.begin(), v.end());\n            int take = min(C, (int)v.size());\n            candNext[a].reserve(take);\n            for (int i = 0; i < take; i++) candNext[a].push_back(v[i].second);\n        }\n\n        for (int b = 0; b < M; b++) {\n            vector<pair<int,int>> v;\n            v.reserve(M - 1);\n            for (int a = 0; a < M; a++) if (a != b) v.emplace_back(edgeGuide[a][b], a);\n            sort(v.begin(), v.end());\n            int take = min(C, (int)v.size());\n            candPrev[b].reserve(take);\n            for (int i = 0; i < take; i++) candPrev[b].push_back(v[i].second);\n        }\n    }\n\n    void preprocess() {\n        computeOccAndDist();\n        computeOverlap();\n        preprocessTransitionsAndApprox();\n        buildCandidateLists(12);\n    }\n\n    inline long long edgeContrib(int from, int to) const {\n        if (to < 0) return 0;\n        if (from < 0) return startApprox[to];\n        return edgeApprox[from][to];\n    }\n\n    long long approxCost(const vector<int>& perm) const {\n        long long c = startApprox[perm[0]];\n        for (int i = 1; i < M; i++) c += edgeApprox[perm[i - 1]][perm[i]];\n        return c;\n    }\n\n    long long deltaSwapApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int cand[4] = {i, i + 1, j, j + 1};\n        int pos[4], npos = 0;\n        for (int z = 0; z < 4; z++) {\n            int t = cand[z];\n            if (t < 0 || t >= M) continue;\n            bool ex = false;\n            for (int k = 0; k < npos; k++) if (pos[k] == t) { ex = true; break; }\n            if (!ex) pos[npos++] = t;\n        }\n\n        auto getNew = [&](int idx) -> int {\n            if (idx == i) return p[j];\n            if (idx == j) return p[i];\n            return p[idx];\n        };\n\n        long long oldc = 0, newc = 0;\n        for (int z = 0; z < npos; z++) {\n            int t = pos[z];\n            int toOld = p[t];\n            int fromOld = (t == 0 ? -1 : p[t - 1]);\n            oldc += edgeContrib(fromOld, toOld);\n\n            int toNew = getNew(t);\n            int fromNew = (t == 0 ? -1 : getNew(t - 1));\n            newc += edgeContrib(fromNew, toNew);\n        }\n        return newc - oldc;\n    }\n\n    long long deltaRelocateApprox(const vector<int>& p, int i, int j) const {\n        if (i == j) return 0;\n        int x = p[i];\n\n        if (i < j) {\n            int a = (i > 0 ? p[i - 1] : -1);\n            int b = p[i + 1];\n            int c = p[j];\n            int d = (j + 1 < M ? p[j + 1] : -1);\n\n            long long oldc = edgeContrib(a, x) + edgeContrib(x, b) + edgeContrib(c, d);\n            long long newc = edgeContrib(a, b) + edgeContrib(c, x) + edgeContrib(x, d);\n            return newc - oldc;\n        } else {\n            int a = p[i - 1];\n            int b = (i + 1 < M ? p[i + 1] : -1);\n            int c = (j > 0 ? p[j - 1] : -1);\n            int d = p[j];\n\n            long long oldc = edgeContrib(c, d) + edgeContrib(a, x) + edgeContrib(x, b);\n            long long newc = edgeContrib(c, x) + edgeContrib(x, d) + edgeContrib(a, b);\n            return newc - oldc;\n        }\n    }\n\n    static void relocateMove(vector<int>& p, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) p[k] = p[k + 1];\n            p[j] = v;\n        } else {\n            for (int k = i; k > j; k--) p[k] = p[k - 1];\n            p[j] = v;\n        }\n    }\n\n    static void swapWithPos(vector<int>& p, vector<int>& pos, int i, int j) {\n        int a = p[i], b = p[j];\n        swap(p[i], p[j]);\n        pos[a] = j;\n        pos[b] = i;\n    }\n\n    static void relocateWithPos(vector<int>& p, vector<int>& pos, int i, int j) {\n        if (i == j) return;\n        int v = p[i];\n        if (i < j) {\n            for (int k = i; k < j; k++) {\n                p[k] = p[k + 1];\n                pos[p[k]] = k;\n            }\n            p[j] = v;\n            pos[v] = j;\n        } else {\n            for (int k = i; k > j; k--) {\n                p[k] = p[k - 1];\n                pos[p[k]] = k;\n            }\n            p[j] = v;\n            pos[v] = j;\n        }\n    }\n\n    MoveInfo proposeMove(const vector<int>& cur, const vector<int>& pos) {\n        MoveInfo mv{1, 0, 0, 0};\n        int mode = rng.nextInt(100);\n\n        if (mode < 34) {\n            mv.type = 0;\n            mv.i = rng.nextInt(M);\n            mv.j = rng.nextInt(M - 1);\n            if (mv.j >= mv.i) mv.j++;\n        } else if (mode < 68) {\n            mv.type = 1;\n            mv.i = rng.nextInt(M);\n            mv.j = rng.nextInt(M - 1);\n            if (mv.j >= mv.i) mv.j++;\n        } else if (mode < 84) {\n            bool found = false;\n            for (int tr = 0; tr < 5 && !found; tr++) {\n                int pa = rng.nextInt(M);\n                int a = cur[pa];\n                const auto& cn = candNext[a];\n                if (cn.empty()) continue;\n                int take = min((int)cn.size(), 6);\n                int b = cn[rng.nextInt(take)];\n                int pb = pos[b];\n                if (pb == pa + 1) continue;\n\n                mv.type = 1;\n                mv.i = pb;\n                mv.j = (pb < pa ? pa : pa + 1);\n                if (mv.j >= M) mv.j = M - 1;\n                if (mv.i == mv.j) continue;\n                found = true;\n            }\n            if (!found) {\n                mv.type = 1;\n                mv.i = rng.nextInt(M);\n                mv.j = rng.nextInt(M - 1);\n                if (mv.j >= mv.i) mv.j++;\n            }\n        } else {\n            bool found = false;\n            for (int tr = 0; tr < 5 && !found; tr++) {\n                int pa = rng.nextInt(M);\n                int a = cur[pa];\n                const auto& cp = candPrev[a];\n                if (cp.empty()) continue;\n                int take = min((int)cp.size(), 6);\n                int b = cp[rng.nextInt(take)];\n                int pb = pos[b];\n                if (pb == pa - 1) continue;\n\n                mv.type = 1;\n                mv.i = pb;\n                mv.j = (pb < pa ? pa - 1 : pa);\n                if (mv.j < 0) mv.j = 0;\n                if (mv.i == mv.j) continue;\n                found = true;\n            }\n            if (!found) {\n                mv.type = 1;\n                mv.i = rng.nextInt(M);\n                mv.j = rng.nextInt(M - 1);\n                if (mv.j >= mv.i) mv.j++;\n            }\n        }\n\n        mv.dA = (mv.type == 0) ? deltaSwapApprox(cur, mv.i, mv.j)\n                               : deltaRelocateApprox(cur, mv.i, mv.j);\n        return mv;\n    }\n\n    vector<int> nearestAllStarts() const {\n        vector<int> bestPerm;\n        long long best = (1LL << 60);\n\n        vector<char> used(M);\n        vector<int> perm(M);\n\n        for (int s = 0; s < M; s++) {\n            fill(used.begin(), used.end(), 0);\n            perm[0] = s;\n            used[s] = 1;\n            long long c = startApprox[s];\n\n            for (int pos = 1; pos < M; pos++) {\n                int cur = perm[pos - 1];\n                int bj = -1, bv = INF;\n                for (int j = 0; j < M; j++) if (!used[j]) {\n                    int v = edgeApprox[cur][j];\n                    if (v < bv) {\n                        bv = v;\n                        bj = j;\n                    }\n                }\n                perm[pos] = bj;\n                used[bj] = 1;\n                c += bv;\n            }\n\n            if (c < best) {\n                best = c;\n                bestPerm = perm;\n            }\n        }\n        return bestPerm;\n    }\n\n    vector<int> cheapestInsertion(int seed) const {\n        vector<int> path;\n        path.reserve(M);\n        vector<char> used(M, 0);\n\n        path.push_back(seed);\n        used[seed] = 1;\n\n        for (int step = 1; step < M; step++) {\n            long long bestDelta = (1LL << 60);\n            int bestWord = -1, bestPos = -1;\n            int len = (int)path.size();\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                long long dFront = (long long)startApprox[x] + edgeApprox[x][path[0]] - startApprox[path[0]];\n                if (dFront < bestDelta) {\n                    bestDelta = dFront;\n                    bestWord = x;\n                    bestPos = 0;\n                }\n\n                for (int pos = 1; pos < len; pos++) {\n                    int u = path[pos - 1], v = path[pos];\n                    long long d = (long long)edgeApprox[u][x] + edgeApprox[x][v] - edgeApprox[u][v];\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestWord = x;\n                        bestPos = pos;\n                    }\n                }\n\n                long long dEnd = edgeApprox[path[len - 1]][x];\n                if (dEnd < bestDelta) {\n                    bestDelta = dEnd;\n                    bestWord = x;\n                    bestPos = len;\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestWord);\n            used[bestWord] = 1;\n        }\n\n        return path;\n    }\n\n    vector<int> randomGreedy(int seed, int rcl) {\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> used(M, 0);\n\n        perm.push_back(seed);\n        used[seed] = 1;\n\n        while ((int)perm.size() < M) {\n            int cur = perm.back();\n            vector<pair<int,int>> cands;\n            cands.reserve(M);\n            for (int j = 0; j < M; j++) if (!used[j]) cands.emplace_back(edgeApprox[cur][j], j);\n\n            sort(cands.begin(), cands.end());\n            int take = min(rcl, (int)cands.size());\n            int pick = cands[rng.nextInt(take)].second;\n            perm.push_back(pick);\n            used[pick] = 1;\n        }\n\n        return perm;\n    }\n\n    int appendExactMin(const vector<int>& vec, int a, int b) const {\n        int na = nEnd[a], nb = nEnd[b];\n        int col[225];\n        for (int j = 0; j < nb; j++) col[j] = INF;\n\n        size_t id = (size_t)a * M + b;\n        const uint16_t* mat = transData.data() + transOffset[id];\n\n        for (int i = 0; i < na; i++) {\n            int base = vec[i];\n            const uint16_t* row = mat + (size_t)i * nb;\n            for (int j = 0; j < nb; j++) {\n                int cand = base + (int)row[j];\n                if (cand < col[j]) col[j] = cand;\n            }\n        }\n\n        int best = INF;\n        for (int j = 0; j < nb; j++) best = min(best, col[j]);\n        return best;\n    }\n\n    void appendTransform(const vector<int>& vec, int a, int b, vector<int>& out) const {\n        int na = nEnd[a], nb = nEnd[b];\n        out.assign(nb, INF);\n\n        size_t id = (size_t)a * M + b;\n        const uint16_t* mat = transData.data() + transOffset[id];\n\n        for (int i = 0; i < na; i++) {\n            int base = vec[i];\n            const uint16_t* row = mat + (size_t)i * nb;\n            for (int j = 0; j < nb; j++) {\n                int cand = base + (int)row[j];\n                if (cand < out[j]) out[j] = cand;\n            }\n        }\n    }\n\n    vector<int> exactGreedy(int start, int rcl) {\n        vector<char> used(M, 0);\n        vector<int> perm;\n        perm.reserve(M);\n\n        int cur = start;\n        used[cur] = 1;\n        perm.push_back(cur);\n\n        vector<int> vec(nEnd[cur]);\n        for (int i = 0; i < nEnd[cur]; i++) vec[i] = (int)firstEndCost[cur][i];\n        vector<int> nvec;\n        nvec.reserve(225);\n\n        for (int step = 1; step < M; step++) {\n            vector<pair<int,int>> top;\n            top.reserve(rcl);\n\n            for (int b = 0; b < M; b++) if (!used[b]) {\n                int v = appendExactMin(vec, cur, b);\n\n                int p = 0;\n                while (p < (int)top.size() && top[p].first <= v) p++;\n                if (p < rcl) {\n                    top.insert(top.begin() + p, {v, b});\n                    if ((int)top.size() > rcl) top.pop_back();\n                }\n            }\n\n            int pick = top[(rcl <= 1 ? 0 : rng.nextInt((int)top.size()))].second;\n            appendTransform(vec, cur, pick, nvec);\n            vec.swap(nvec);\n\n            cur = pick;\n            used[cur] = 1;\n            perm.push_back(cur);\n        }\n\n        return perm;\n    }\n\n    vector<int> pathRelinkCandidate(vector<int> cur, const vector<int>& target) const {\n        vector<int> pos(M);\n        for (int i = 0; i < M; i++) pos[cur[i]] = i;\n\n        long long c = approxCost(cur);\n        long long best = c;\n        vector<int> bestP = cur;\n\n        for (int i = 0; i < M; i++) {\n            int want = target[i];\n            int j = pos[want];\n            if (j == i) continue;\n\n            long long d = deltaSwapApprox(cur, i, j);\n            int a = cur[i], b = cur[j];\n            swap(cur[i], cur[j]);\n            pos[a] = j;\n            pos[b] = i;\n            c += d;\n\n            if (c < best) {\n                best = c;\n                bestP = cur;\n            }\n        }\n        return bestP;\n    }\n\n    uint64_t hashPerm(const vector<int>& p) const {\n        uint64_t h = 1469598103934665603ull;\n        for (int x : p) {\n            h ^= (uint64_t)(x + 1);\n            h *= 1099511628211ull;\n        }\n        return h;\n    }\n\n    void SAApprox(vector<int>& perm, long long& curCost, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm, best = perm;\n        vector<int> pos(M);\n        for (int i = 0; i < M; i++) pos[cur[i]] = i;\n\n        long long cC = curCost, bC = cC;\n        const double T0 = 22.0, T1 = 0.05;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        const int SAMPLE = 3;\n        array<MoveInfo, SAMPLE> sample{};\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            for (int s = 0; s < SAMPLE; s++) sample[s] = proposeMove(cur, pos);\n            int bestIdx = 0;\n            for (int s = 1; s < SAMPLE; s++) if (sample[s].dA < sample[bestIdx].dA) bestIdx = s;\n\n            int pick = (rng.nextInt(100) < 80 ? bestIdx : rng.nextInt(SAMPLE));\n            MoveInfo mv = sample[pick];\n\n            bool accept = (mv.dA <= 0) || (rng.nextDouble() < exp(-double(mv.dA) / temp));\n            if (!accept) continue;\n\n            if (mv.type == 0) swapWithPos(cur, pos, mv.i, mv.j);\n            else relocateWithPos(cur, pos, mv.i, mv.j);\n\n            cC += mv.dA;\n            if (cC < bC) {\n                bC = cC;\n                best = cur;\n            }\n        }\n\n        perm = best;\n        curCost = bC;\n    }\n\n    int exactCost(const vector<int>& perm) const {\n        int dpA[225], dpB[225];\n\n        int w0 = perm[0];\n        int sz = nEnd[w0];\n        for (int i = 0; i < sz; i++) dpA[i] = (int)firstEndCost[w0][i];\n\n        for (int idx = 1; idx < M; idx++) {\n            int a = perm[idx - 1], b = perm[idx];\n            int na = nEnd[a], nb = nEnd[b];\n\n            for (int j = 0; j < nb; j++) dpB[j] = INF;\n\n            size_t id = (size_t)a * M + b;\n            const uint16_t* mat = transData.data() + transOffset[id];\n\n            for (int i = 0; i < na; i++) {\n                int base = dpA[i];\n                const uint16_t* row = mat + (size_t)i * nb;\n                for (int j = 0; j < nb; j++) {\n                    int cand = base + (int)row[j];\n                    if (cand < dpB[j]) dpB[j] = cand;\n                }\n            }\n\n            for (int j = 0; j < nb; j++) dpA[j] = dpB[j];\n            sz = nb;\n        }\n\n        int ans = INF;\n        for (int i = 0; i < sz; i++) ans = min(ans, dpA[i]);\n        return ans;\n    }\n\n    void perturb(vector<int>& p, int moves) {\n        for (int t = 0; t < moves; t++) {\n            if (rng.nextInt(100) < 50) {\n                int i = rng.nextInt(M);\n                int j = rng.nextInt(M - 1);\n                if (j >= i) j++;\n                swap(p[i], p[j]);\n            } else {\n                int i = rng.nextInt(M);\n                int j = rng.nextInt(M - 1);\n                if (j >= i) j++;\n                relocateMove(p, i, j);\n            }\n        }\n    }\n\n    void SAExact(vector<int>& perm, long long& curA, int& curE, double endTime) {\n        double begin = elapsed();\n        if (begin >= endTime) return;\n\n        vector<int> cur = perm, best = perm;\n        vector<int> pos(M);\n        for (int i = 0; i < M; i++) pos[cur[i]] = i;\n\n        long long cA = curA, bA = curA;\n        int cE = curE, bE = curE;\n\n        const double T0 = 10.8, T1 = 0.02;\n        double temp = T0;\n        double span = max(1e-9, endTime - begin);\n\n        int stagn = 0;\n        const int SAMPLE = 4;\n        array<MoveInfo, SAMPLE> sample{};\n\n        for (long long iter = 0;; iter++) {\n            if ((iter & 255) == 0) {\n                double now = elapsed();\n                if (now >= endTime) break;\n                double r = (now - begin) / span;\n                temp = T0 * pow(T1 / T0, r);\n            }\n\n            for (int s = 0; s < SAMPLE; s++) sample[s] = proposeMove(cur, pos);\n            int bestIdx = 0;\n            for (int s = 1; s < SAMPLE; s++) if (sample[s].dA < sample[bestIdx].dA) bestIdx = s;\n\n            int pick = (rng.nextInt(100) < 82 ? bestIdx : rng.nextInt(SAMPLE));\n            MoveInfo mv = sample[pick];\n\n            if (mv.dA > 240 && rng.nextInt(100) < 96) continue;\n            if (mv.dA > 130 && rng.nextInt(100) < 65) continue;\n\n            if (mv.type == 0) swapWithPos(cur, pos, mv.i, mv.j);\n            else relocateWithPos(cur, pos, mv.i, mv.j);\n\n            int ne = exactCost(cur);\n            int dE = ne - cE;\n\n            bool accept = false;\n            if (dE < 0) accept = true;\n            else if (dE == 0) {\n                if (mv.dA < 0) accept = true;\n                else accept = (rng.nextInt(100) < 8);\n            } else {\n                accept = (rng.nextDouble() < exp(-double(dE) / temp));\n            }\n\n            if (accept) {\n                cE = ne;\n                cA += mv.dA;\n                if (cE < bE || (cE == bE && cA < bA)) {\n                    bE = cE;\n                    bA = cA;\n                    best = cur;\n                    stagn = 0;\n                } else {\n                    stagn++;\n                }\n            } else {\n                if (mv.type == 0) swapWithPos(cur, pos, mv.i, mv.j);\n                else relocateWithPos(cur, pos, mv.j, mv.i); // inverse\n                stagn++;\n            }\n\n            if (stagn > 6000 && elapsed() < endTime - 0.02) {\n                cur = best;\n                for (int t = 0; t < 2; t++) {\n                    if (rng.nextInt(100) < 50) {\n                        int a = rng.nextInt(M);\n                        int b = rng.nextInt(M - 1);\n                        if (b >= a) b++;\n                        swap(cur[a], cur[b]);\n                    } else {\n                        int a = rng.nextInt(M);\n                        int b = rng.nextInt(M - 1);\n                        if (b >= a) b++;\n                        relocateMove(cur, a, b);\n                    }\n                }\n                for (int k = 0; k < M; k++) pos[cur[k]] = k;\n                cA = approxCost(cur);\n                cE = exactCost(cur);\n                stagn = 0;\n            }\n        }\n\n        perm = best;\n        curA = approxCost(best);\n        curE = bE;\n    }\n\n    void exactCandidateDescent(vector<int>& perm, long long& curA, int& curE, double endTime) {\n        vector<int> pos(M), tmp;\n        tmp.reserve(M);\n\n        vector<CandMove> moves;\n        moves.reserve(M * 12 + 160);\n\n        auto cmpMove = [](const CandMove& a, const CandMove& b) { return a.dA < b.dA; };\n\n        while (elapsed() < endTime) {\n            for (int i = 0; i < M; i++) pos[perm[i]] = i;\n            moves.clear();\n\n            for (int pa = 0; pa < M; pa++) {\n                int a = perm[pa];\n\n                const auto& cn = candNext[a];\n                int limN = min((int)cn.size(), 4);\n                for (int z = 0; z < limN; z++) {\n                    int b = cn[z];\n                    int pb = pos[b];\n                    if (pb == pa + 1) continue;\n                    int j = (pb < pa ? pa : pa + 1);\n                    if (j >= M) j = M - 1;\n                    if (pb == j) continue;\n                    int dA = (int)deltaRelocateApprox(perm, pb, j);\n                    moves.push_back(CandMove{1, (uint16_t)pb, (uint16_t)j, dA});\n                }\n\n                const auto& cp = candPrev[a];\n                int limP = min((int)cp.size(), 4);\n                for (int z = 0; z < limP; z++) {\n                    int b = cp[z];\n                    int pb = pos[b];\n                    if (pb == pa - 1) continue;\n                    int j = (pb < pa ? pa - 1 : pa);\n                    if (j < 0) j = 0;\n                    if (pb == j) continue;\n                    int dA = (int)deltaRelocateApprox(perm, pb, j);\n                    moves.push_back(CandMove{1, (uint16_t)pb, (uint16_t)j, dA});\n                }\n            }\n\n            for (int t = 0; t < 80; t++) {\n                if (rng.nextInt(100) < 55) {\n                    int i = rng.nextInt(M);\n                    int j = rng.nextInt(M - 1);\n                    if (j >= i) j++;\n                    int dA = (int)deltaSwapApprox(perm, i, j);\n                    moves.push_back(CandMove{0, (uint16_t)i, (uint16_t)j, dA});\n                } else {\n                    int i = rng.nextInt(M);\n                    int j = rng.nextInt(M - 1);\n                    if (j >= i) j++;\n                    int dA = (int)deltaRelocateApprox(perm, i, j);\n                    moves.push_back(CandMove{1, (uint16_t)i, (uint16_t)j, dA});\n                }\n            }\n\n            if (moves.empty()) break;\n            sort(moves.begin(), moves.end(), cmpMove);\n\n            int K = min((int)moves.size(), 140);\n\n            int bestIdx = -1;\n            int bestE = curE;\n            int bestDA = 0;\n\n            for (int idx = 0; idx < K; idx++) {\n                if ((idx & 15) == 0 && elapsed() >= endTime) break;\n\n                const auto& mv = moves[idx];\n                tmp = perm;\n                if (mv.type == 0) swap(tmp[mv.i], tmp[mv.j]);\n                else relocateMove(tmp, mv.i, mv.j);\n\n                int ne = exactCost(tmp);\n                if (ne < bestE || (ne == bestE && mv.dA < bestDA)) {\n                    bestE = ne;\n                    bestDA = mv.dA;\n                    bestIdx = idx;\n                }\n            }\n\n            if (bestIdx < 0) break;\n\n            const auto& bm = moves[bestIdx];\n            if (bm.type == 0) swap(perm[bm.i], perm[bm.j]);\n            else relocateMove(perm, bm.i, bm.j);\n\n            curE = bestE;\n            curA += bestDA;\n        }\n    }\n\n    void exactFocusedRelocateSwapDescent(vector<int>& perm, long long& curA, int& curE, double endTime) {\n        vector<int> tmp;\n        tmp.reserve(M);\n\n        auto insertTop = [&](vector<pair<int,int>>& top, int d, int j, int K) {\n            if ((int)top.size() < K) {\n                top.emplace_back(d, j);\n                int p = (int)top.size() - 1;\n                while (p > 0 && top[p].first < top[p - 1].first) {\n                    swap(top[p], top[p - 1]);\n                    p--;\n                }\n            } else if (d < top.back().first) {\n                top.back() = {d, j};\n                int p = K - 1;\n                while (p > 0 && top[p].first < top[p - 1].first) {\n                    swap(top[p], top[p - 1]);\n                    p--;\n                }\n            }\n        };\n\n        while (elapsed() < endTime) {\n            vector<pair<int,int>> edges;\n            edges.reserve(M);\n            for (int i = 0; i < M; i++) {\n                int c = (i == 0 ? startApprox[perm[0]] : edgeApprox[perm[i - 1]][perm[i]]);\n                edges.emplace_back(c, i);\n            }\n\n            int B = min(M, 22);\n            nth_element(edges.begin(), edges.begin() + B, edges.end(),\n                        [](const auto& x, const auto& y) { return x.first > y.first; });\n\n            vector<char> mark(M, 0);\n            for (int t = 0; t < B; t++) {\n                int idx = edges[t].second;\n                mark[idx] = 1;\n                if (idx > 0) mark[idx - 1] = 1;\n                if (idx + 1 < M) mark[idx + 1] = 1;\n            }\n            for (int r = 0; r < 12; r++) mark[rng.nextInt(M)] = 1;\n\n            vector<int> candPos;\n            candPos.reserve(M);\n            for (int i = 0; i < M; i++) if (mark[i]) candPos.push_back(i);\n\n            int bestType = -1, bestI = -1, bestJ = -1;\n            int bestE = curE;\n            int bestDA = 0;\n\n            for (int ix = 0; ix < (int)candPos.size(); ix++) {\n                if ((ix & 3) == 0 && elapsed() >= endTime) break;\n                int i = candPos[ix];\n\n                vector<pair<int,int>> topRel, topSw;\n                topRel.reserve(3);\n                topSw.reserve(1);\n\n                for (int j = 0; j < M; j++) if (j != i) {\n                    int dR = (int)deltaRelocateApprox(perm, i, j);\n                    insertTop(topRel, dR, j, 3);\n\n                    int dS = (int)deltaSwapApprox(perm, i, j);\n                    insertTop(topSw, dS, j, 1);\n                }\n\n                for (auto [d, j] : topRel) {\n                    tmp = perm;\n                    relocateMove(tmp, i, j);\n                    int ne = exactCost(tmp);\n                    if (ne < bestE || (ne == bestE && d < bestDA)) {\n                        bestE = ne;\n                        bestDA = d;\n                        bestType = 1;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n\n                for (auto [d, j] : topSw) {\n                    tmp = perm;\n                    swap(tmp[i], tmp[j]);\n                    int ne = exactCost(tmp);\n                    if (ne < bestE || (ne == bestE && d < bestDA)) {\n                        bestE = ne;\n                        bestDA = d;\n                        bestType = 0;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestType < 0) break;\n\n            if (bestType == 0) swap(perm[bestI], perm[bestJ]);\n            else relocateMove(perm, bestI, bestJ);\n\n            curE = bestE;\n            curA += bestDA;\n        }\n    }\n\n    void buildString(const vector<int>& perm, string& out) const {\n        out.clear();\n        out.reserve(5 * M);\n        out += words[perm[0]];\n        for (int i = 1; i < M; i++) {\n            int a = perm[i - 1], b = perm[i];\n            int k = ov[a][b];\n            for (int p = k; p < 5; p++) out.push_back(words[b][p]);\n        }\n    }\n\n    vector<int> bestPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<short>> parent(L, vector<short>(V, -1));\n\n        vector<int> prev(V, INF), cur(V, INF);\n        vector<int> prevCells = occ[s[0] - 'A'];\n\n        for (int q : prevCells) prev[q] = distMat[startId][q] + 1;\n\n        for (int idx = 1; idx < L; idx++) {\n            const auto& nextCells = occ[s[idx] - 'A'];\n\n            for (int q : nextCells) {\n                int best = INF;\n                short bp = -1;\n                for (int p : prevCells) {\n                    int cand = prev[p] + distMat[p][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bp = (short)p;\n                    }\n                }\n                cur[q] = best;\n                parent[idx][q] = bp;\n            }\n\n            for (int p : prevCells) prev[p] = INF;\n            prevCells = nextCells;\n            for (int q : prevCells) {\n                prev[q] = cur[q];\n                cur[q] = INF;\n            }\n        }\n\n        int endCell = -1, best = INF;\n        for (int p : prevCells) {\n            if (prev[p] < best) {\n                best = prev[p];\n                endCell = p;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = endCell;\n        for (int i = L - 1; i >= 1; i--) path[i - 1] = parent[i][path[i]];\n        return path;\n    }\n\n    void solve() {\n        readInput();\n        rng = XorShift64(makeSeed());\n        t0 = chrono::steady_clock::now();\n\n        preprocess();\n\n        const double APPROX_END = 0.50;\n        const double MAIN_END   = 1.82;\n        const double DESC_END   = 1.88;\n        const double FOCUS_END  = 1.91;\n        const double FINAL_END  = 1.94;\n\n        vector<vector<int>> cands;\n        vector<long long> aCost;\n        unordered_set<uint64_t> seen;\n        seen.reserve(512);\n\n        auto addCand = [&](vector<int> p) {\n            uint64_t h = hashPerm(p);\n            if (seen.insert(h).second) {\n                aCost.push_back(approxCost(p));\n                cands.push_back(move(p));\n            }\n        };\n\n        // seed generation\n        addCand(nearestAllStarts());\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 (startApprox[a] != startApprox[b]) return startApprox[a] < startApprox[b];\n            return a < b;\n        });\n\n        for (int i = 0; i < min(M, 6); i++) addCand(cheapestInsertion(ord[i]));\n        for (int t = 0; t < 3; t++) addCand(cheapestInsertion(rng.nextInt(M)));\n\n        for (int i = 0; i < min(M, 4); i++) addCand(randomGreedy(ord[i], 4));\n        for (int t = 0; t < 6; t++) addCand(randomGreedy(rng.nextInt(M), 3 + rng.nextInt(4)));\n\n        for (int i = 0; i < min(M, 8); i++) addCand(exactGreedy(ord[i], 1));\n        for (int i = 0; i < min(M, 5); i++) addCand(exactGreedy(ord[i], 3));\n        for (int t = 0; t < 6; t++) addCand(exactGreedy(rng.nextInt(M), 3 + rng.nextInt(3)));\n\n        // path relinking on best approx seeds\n        {\n            vector<int> idx((int)cands.size());\n            iota(idx.begin(), idx.end(), 0);\n            sort(idx.begin(), idx.end(), [&](int x, int y) { return aCost[x] < aCost[y]; });\n\n            int K = min(5, (int)idx.size());\n            for (int i = 0; i < K; i++) {\n                for (int j = i + 1; j < K; j++) {\n                    addCand(pathRelinkCandidate(cands[idx[i]], cands[idx[j]]));\n                    addCand(pathRelinkCandidate(cands[idx[j]], cands[idx[i]]));\n                }\n            }\n        }\n\n        // short approx SA\n        if (elapsed() < APPROX_END) {\n            vector<int> idx((int)cands.size());\n            iota(idx.begin(), idx.end(), 0);\n            sort(idx.begin(), idx.end(), [&](int x, int y) { return aCost[x] < aCost[y]; });\n\n            int use = min(2, (int)idx.size());\n            for (int z = 0; z < use && elapsed() < APPROX_END; z++) {\n                int id = idx[z];\n                double rem = APPROX_END - elapsed();\n                double slice = rem / (use - z);\n                SAApprox(cands[id], aCost[id], elapsed() + slice);\n            }\n        }\n\n        int C = (int)cands.size();\n        vector<int> eCost(C, INF);\n\n        int bestIdx = 0;\n        int bestE = INF;\n        long long bestA = (1LL << 60);\n\n        for (int i = 0; i < C; i++) {\n            eCost[i] = exactCost(cands[i]);\n            if (eCost[i] < bestE || (eCost[i] == bestE && aCost[i] < bestA)) {\n                bestE = eCost[i];\n                bestA = aCost[i];\n                bestIdx = i;\n            }\n        }\n\n        vector<int> bestPerm = cands[bestIdx];\n\n        vector<int> seedOrder(C);\n        iota(seedOrder.begin(), seedOrder.end(), 0);\n        sort(seedOrder.begin(), seedOrder.end(), [&](int x, int y) {\n            if (eCost[x] != eCost[y]) return eCost[x] < eCost[y];\n            return aCost[x] < aCost[y];\n        });\n\n        vector<Elite> elite;\n        elite.reserve(10);\n\n        auto addElite = [&](const vector<int>& p, long long a, int e) {\n            uint64_t h = hashPerm(p);\n            for (auto& el : elite) {\n                if (el.h == h) {\n                    if (e < el.e || (e == el.e && a < el.a)) {\n                        el.e = e;\n                        el.a = a;\n                        el.p = p;\n                    }\n                    sort(elite.begin(), elite.end(), [](const Elite& x, const Elite& y) {\n                        if (x.e != y.e) return x.e < y.e;\n                        return x.a < y.a;\n                    });\n                    if ((int)elite.size() > 8) elite.resize(8);\n                    return;\n                }\n            }\n            elite.push_back(Elite{e, a, p, h});\n            sort(elite.begin(), elite.end(), [](const Elite& x, const Elite& y) {\n                if (x.e != y.e) return x.e < y.e;\n                return x.a < y.a;\n            });\n            if ((int)elite.size() > 8) elite.resize(8);\n        };\n\n        for (int t = 0; t < min(C, 8); t++) {\n            int id = seedOrder[t];\n            addElite(cands[id], aCost[id], eCost[id]);\n        }\n        addElite(bestPerm, bestA, bestE);\n\n        int round = 0;\n        int seedUse = min(C, 12);\n\n        while (elapsed() < MAIN_END) {\n            vector<int> cur;\n            long long curA;\n            int curE;\n\n            if (round < seedUse) {\n                int id = seedOrder[round];\n                cur = cands[id];\n                curA = aCost[id];\n                curE = eCost[id];\n            } else {\n                if (!elite.empty() && rng.nextInt(100) < 75) {\n                    int k = min(4, (int)elite.size());\n                    cur = elite[rng.nextInt(k)].p;\n                } else {\n                    cur = bestPerm;\n                }\n                int pm = 1 + (round % 6);\n                if (rng.nextInt(100) < 20) pm = max(0, pm - 1);\n                perturb(cur, pm);\n                curA = approxCost(cur);\n                curE = exactCost(cur);\n            }\n\n            double rem = MAIN_END - elapsed();\n            if (rem <= 0.03) break;\n            double slice = min(0.18, max(0.05, rem * 0.33));\n\n            SAExact(cur, curA, curE, elapsed() + slice);\n\n            if (curE < bestE || (curE == bestE && curA < bestA)) {\n                bestE = curE;\n                bestA = curA;\n                bestPerm = cur;\n            }\n            addElite(cur, curA, curE);\n\n            round++;\n        }\n\n        if (elapsed() < DESC_END) {\n            exactCandidateDescent(bestPerm, bestA, bestE, DESC_END);\n            bestA = approxCost(bestPerm);\n            addElite(bestPerm, bestA, bestE);\n        }\n\n        if (elapsed() < FOCUS_END) {\n            exactFocusedRelocateSwapDescent(bestPerm, bestA, bestE, FOCUS_END);\n            bestA = approxCost(bestPerm);\n            addElite(bestPerm, bestA, bestE);\n        }\n\n        if (elapsed() < FINAL_END) {\n            SAExact(bestPerm, bestA, bestE, FINAL_END);\n        }\n\n        string finalS;\n        buildString(bestPerm, finalS);\n\n        vector<int> path = bestPathForString(finalS);\n        for (int id : path) {\n            cout << (id / N) << ' ' << (id % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Mask {\n    static constexpr int W = 7; // 448 bits >= 400 cells\n    array<uint64_t, W> w{};\n    Mask() { w.fill(0ULL); }\n    inline void set(int idx) { w[idx >> 6] |= (1ULL << (idx & 63)); }\n    inline bool test(int idx) const { return (w[idx >> 6] >> (idx & 63)) & 1ULL; }\n};\n\nstruct Placement {\n    vector<int> cells;      // covered cell indices\n    Mask mask;\n    vector<uint8_t> qcov;   // for each drilled query id: 0/1 cover\n};\n\nclass OilSolver {\n    struct ArrHash {\n        size_t operator()(array<uint64_t, Mask::W> const& a) const noexcept {\n            uint64_t h = 0x9e3779b97f4a7c15ULL;\n            for (uint64_t x : a) {\n                x ^= (x >> 30);\n                x *= 0xbf58476d1ce4e5b9ULL;\n                x ^= (x >> 27);\n                x *= 0x94d049bb133111ebULL;\n                x ^= (x >> 31);\n                h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n            }\n            return (size_t)h;\n        }\n    };\n\n    struct UnionCand {\n        array<uint64_t, Mask::W> m{};\n        int cnt = 0;\n    };\n\n    int N = 0, M = 0, n2 = 0;\n    double eps = 0.0;\n\n    vector<vector<pair<int,int>>> shapes;\n    vector<vector<Placement>> fieldPls; // [field][placement]\n\n    vector<int> drilledVal;   // -1 unknown, else exact v(cell)\n    vector<int> qidOfCell;    // cell -> query id if drilled\n    vector<int> queryVals;    // drilled exact values\n    vector<int> queryCells;\n    vector<int> positiveDrilled;\n\n    vector<int> priorOrder;\n    int priorPtr = 0;\n\n    vector<array<uint64_t, Mask::W>> forbiddenMasks;\n\n    mt19937 rng;\n    int ops = 0;\n    int wrongGuesses = 0;\n\n    chrono::steady_clock::time_point startTime;\n\n    static constexpr double HARD_LIMIT_MS = 2850.0;\n    static constexpr double EMERGENCY_MS  = 2620.0;\n    static constexpr int MAX_WRONG_GUESSES = 18;\n\npublic:\n    OilSolver() : rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    double elapsed_ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        n2 = N * N;\n        shapes.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            shapes[k].resize(d);\n            for (int i = 0; i < d; i++) {\n                int r, c;\n                cin >> r >> c;\n                shapes[k][i] = {r, c};\n            }\n        }\n        drilledVal.assign(n2, -1);\n        qidOfCell.assign(n2, -1);\n    }\n\n    void build_placements() {\n        fieldPls.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            int maxr = 0, maxc = 0;\n            for (auto [r, c] : shapes[k]) {\n                maxr = max(maxr, r);\n                maxc = max(maxc, c);\n            }\n\n            for (int di = 0; di + maxr < N; di++) {\n                for (int dj = 0; dj + maxc < N; dj++) {\n                    Placement pl;\n                    pl.cells.reserve(shapes[k].size());\n                    pl.qcov.reserve(n2);\n                    for (auto [r, c] : shapes[k]) {\n                        int idx = (di + r) * N + (dj + c);\n                        pl.cells.push_back(idx);\n                        pl.mask.set(idx);\n                    }\n                    fieldPls[k].push_back(move(pl));\n                }\n            }\n        }\n    }\n\n    void build_prior_order() {\n        vector<vector<int>> coverCnt(M, vector<int>(n2, 0));\n        for (int k = 0; k < M; k++) {\n            for (auto const& pl : fieldPls[k]) {\n                for (int idx : pl.cells) coverCnt[k][idx]++;\n            }\n        }\n\n        vector<double> score(n2, 0.0);\n        for (int idx = 0; idx < n2; idx++) {\n            double p0 = 1.0;\n            for (int k = 0; k < M; k++) {\n                double pk = (double)coverCnt[k][idx] / (double)fieldPls[k].size();\n                p0 *= (1.0 - pk);\n            }\n            double p = 1.0 - p0;\n            score[idx] = p * (1.0 - p);\n        }\n\n        priorOrder.resize(n2);\n        iota(priorOrder.begin(), priorOrder.end(), 0);\n        sort(priorOrder.begin(), priorOrder.end(), [&](int a, int b) {\n            if (score[a] != score[b]) return score[a] > score[b];\n            return a < b;\n        });\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << \" \" << (idx % N) << '\\n' << flush;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    int ask_answer(const vector<int>& cells) {\n        cout << \"a \" << cells.size();\n        for (int idx : cells) cout << \" \" << (idx / N) << \" \" << (idx % N);\n        cout << '\\n' << flush;\n        int res;\n        if (!(cin >> res)) exit(0);\n        return res;\n    }\n\n    void add_drill(int idx, int val) {\n        if (drilledVal[idx] != -1) return;\n\n        drilledVal[idx] = val;\n        int qid = (int)queryVals.size();\n        qidOfCell[idx] = qid;\n        queryVals.push_back(val);\n        queryCells.push_back(idx);\n        if (val > 0) positiveDrilled.push_back(idx);\n\n        // append one qcov bit for every placement\n        for (int k = 0; k < M; k++) {\n            for (auto& pl : fieldPls[k]) {\n                pl.qcov.push_back(pl.mask.test(idx) ? 1 : 0);\n            }\n        }\n    }\n\n    int pick_prior_cell() {\n        while (priorPtr < (int)priorOrder.size() && drilledVal[priorOrder[priorPtr]] != -1) priorPtr++;\n        if (priorPtr < (int)priorOrder.size()) return priorOrder[priorPtr++];\n        return -1;\n    }\n\n    int first_unknown_cell() const {\n        for (int idx = 0; idx < n2; idx++) if (drilledVal[idx] == -1) return idx;\n        return -1;\n    }\n\n    int pick_frontier_cell() const {\n        static const int di[4] = {-1, 1, 0, 0};\n        static const int dj[4] = {0, 0, -1, 1};\n\n        int best = -1, bestScore = -1;\n        for (int idx : positiveDrilled) {\n            int i = idx / N, j = idx % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nid = ni * N + nj;\n                if (drilledVal[nid] != -1) continue;\n\n                int sc = 0;\n                for (int d2 = 0; d2 < 4; d2++) {\n                    int xi = ni + di[d2], xj = nj + dj[d2];\n                    if (xi < 0 || xi >= N || xj < 0 || xj >= N) continue;\n                    int xid = xi * N + xj;\n                    if (drilledVal[xid] > 0) sc++;\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = nid;\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<int> exact_from_drilled() const {\n        vector<int> ans;\n        ans.reserve(n2);\n        for (int idx = 0; idx < n2; idx++) if (drilledVal[idx] > 0) ans.push_back(idx);\n        return ans;\n    }\n\n    static inline void set_bit(array<uint64_t, Mask::W>& m, int idx) {\n        m[idx >> 6] |= (1ULL << (idx & 63));\n    }\n\n    bool is_forbidden(const array<uint64_t, Mask::W>& m) const {\n        for (auto const& x : forbiddenMasks) if (x == m) return true;\n        return false;\n    }\n\n    void add_forbidden(const array<uint64_t, Mask::W>& m) {\n        if (!is_forbidden(m)) forbiddenMasks.push_back(m);\n    }\n\n    void normalize_mask(array<uint64_t, Mask::W>& m) const {\n        for (int idx : positiveDrilled) set_bit(m, idx);\n    }\n\n    array<uint64_t, Mask::W> build_union_mask(const vector<int>& asg) const {\n        array<uint64_t, Mask::W> m{};\n        m.fill(0ULL);\n        for (int k = 0; k < M; k++) {\n            int p = asg[k];\n            if (p < 0) continue;\n            for (int wi = 0; wi < Mask::W; wi++) m[wi] |= fieldPls[k][p].mask.w[wi];\n        }\n        return m;\n    }\n\n    vector<int> mask_to_cells(const array<uint64_t, Mask::W>& m) const {\n        vector<int> cells;\n        cells.reserve(n2);\n        for (int wi = 0; wi < Mask::W; wi++) {\n            uint64_t bits = m[wi];\n            while (bits) {\n                int b = __builtin_ctzll(bits);\n                int idx = wi * 64 + b;\n                if (idx < n2) cells.push_back(idx);\n                bits &= bits - 1;\n            }\n        }\n        return cells;\n    }\n\n    bool can_afford_guess(int safety = 2) const {\n        int maxOps = 2 * n2;\n        int unknown = n2 - (int)queryVals.size();\n        return (maxOps - ops) > (unknown + safety);\n    }\n\n    int submit_guess_mask(array<uint64_t, Mask::W> m) {\n        normalize_mask(m);\n        if (is_forbidden(m)) return -1;\n\n        vector<int> cells = mask_to_cells(m);\n        int res = ask_answer(cells);\n        ops++;\n\n        if (res == 1) return 1;\n        wrongGuesses++;\n        add_forbidden(m);\n        return 0;\n    }\n\n    void fill_all_domains(vector<vector<int>>& domains) const {\n        domains.assign(M, {});\n        for (int k = 0; k < M; k++) {\n            domains[k].resize(fieldPls[k].size());\n            iota(domains[k].begin(), domains[k].end(), 0);\n        }\n    }\n\n    bool verify_assignment_full(const vector<int>& asg) const {\n        vector<int> rem = queryVals;\n        for (int k = 0; k < M; k++) {\n            int p = asg[k];\n            if (p < 0) return false;\n            for (int idx : fieldPls[k][p].cells) {\n                int qid = qidOfCell[idx];\n                if (qid != -1) rem[qid]--;\n            }\n        }\n        for (int v : rem) if (v != 0) return false;\n        return true;\n    }\n\n    bool propagate_domains(vector<vector<int>>& domains) {\n        domains.assign(M, {});\n        int q = (int)queryVals.size();\n\n        if (q == 0) {\n            fill_all_domains(domains);\n            return true;\n        }\n\n        vector<vector<uint8_t>> active(M);\n        for (int k = 0; k < M; k++) active[k].assign(fieldPls[k].size(), 1);\n\n        int maxIt = 10;\n        if (q > 80)  maxIt = 7;\n        if (q > 160) maxIt = 5;\n        if (q > 260) maxIt = 3;\n        if (elapsed_ms() > 2300.0) maxIt = min(maxIt, 2);\n\n        for (int it = 0; it < maxIt; it++) {\n            if (elapsed_ms() > HARD_LIMIT_MS - 140.0) break;\n\n            vector<int> domSize(M, 0);\n            vector<vector<int>> cnt1(M, vector<int>(q, 0));\n\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    domSize[k]++;\n                    const auto& qc = pls[p].qcov;\n                    for (int r = 0; r < q; r++) cnt1[k][r] += qc[r];\n                }\n            }\n\n            for (int k = 0; k < M; k++) if (domSize[k] == 0) return false;\n\n            vector<vector<int8_t>> minv(M, vector<int8_t>(q, 0));\n            vector<vector<int8_t>> maxv(M, vector<int8_t>(q, 0));\n            vector<int> totalMin(q, 0), totalMax(q, 0);\n\n            for (int r = 0; r < q; r++) {\n                int tmin = 0, tmax = 0;\n                for (int k = 0; k < M; k++) {\n                    bool has1 = cnt1[k][r] > 0;\n                    bool has0 = (domSize[k] - cnt1[k][r]) > 0;\n                    int mn = has0 ? 0 : 1;\n                    int mx = has1 ? 1 : 0;\n                    minv[k][r] = (int8_t)mn;\n                    maxv[k][r] = (int8_t)mx;\n                    tmin += mn;\n                    tmax += mx;\n                }\n                totalMin[r] = tmin;\n                totalMax[r] = tmax;\n                int y = queryVals[r];\n                if (y < tmin || y > tmax) return false;\n            }\n\n            bool changed = false;\n            for (int k = 0; k < M; k++) {\n                const auto& pls = fieldPls[k];\n                for (int p = 0; p < (int)pls.size(); p++) if (active[k][p]) {\n                    const auto& qc = pls[p].qcov;\n                    bool ok = true;\n                    for (int r = 0; r < q; r++) {\n                        int need = queryVals[r] - (int)qc[r];\n                        int lo = totalMin[r] - (int)minv[k][r];\n                        int hi = totalMax[r] - (int)maxv[k][r];\n                        if (need < lo || need > hi) {\n                            ok = false;\n                            break;\n                        }\n                    }\n                    if (!ok) {\n                        active[k][p] = 0;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        for (int k = 0; k < M; k++) {\n            for (int p = 0; p < (int)fieldPls[k].size(); p++) if (active[k][p]) domains[k].push_back(p);\n            if (domains[k].empty()) return false;\n        }\n        return true;\n    }\n\n    vector<int> choose_used_constraints(int maxUsed) {\n        int q = (int)queryVals.size();\n        vector<int> used;\n        if (q <= maxUsed) {\n            used.resize(q);\n            iota(used.begin(), used.end(), 0);\n            return used;\n        }\n\n        vector<int> pos, zero;\n        pos.reserve(q);\n        zero.reserve(q);\n\n        for (int r = 0; r < q; r++) {\n            if (queryVals[r] > 0) pos.push_back(r);\n            else zero.push_back(r);\n        }\n\n        shuffle(pos.begin(), pos.end(), rng);\n        shuffle(zero.begin(), zero.end(), rng);\n\n        // prioritize positive cells (usually informative)\n        int keepPos = min((int)pos.size(), maxUsed * 3 / 4);\n        for (int i = 0; i < keepPos; i++) used.push_back(pos[i]);\n\n        int rem = maxUsed - (int)used.size();\n        int takeZero = min(rem, (int)zero.size());\n        for (int i = 0; i < takeZero; i++) used.push_back(zero[i]);\n        rem = maxUsed - (int)used.size();\n\n        int pidx = keepPos;\n        while (rem > 0 && pidx < (int)pos.size()) {\n            used.push_back(pos[pidx++]);\n            rem--;\n        }\n\n        int zidx = takeZero;\n        while (rem > 0 && zidx < (int)zero.size()) {\n            used.push_back(zero[zidx++]);\n            rem--;\n        }\n\n        return used;\n    }\n\n    vector<vector<int>> sample_solutions(const vector<vector<int>>& domains, int maxSol, long long nodeLimit, int baseTimeMs) {\n        vector<vector<int>> sols;\n        if (maxSol <= 0) return sols;\n\n        int qFull = (int)queryVals.size();\n        if (elapsed_ms() > HARD_LIMIT_MS - 120.0) return sols;\n\n        double remGlobal = HARD_LIMIT_MS - elapsed_ms();\n        if (remGlobal < 18.0) return sols;\n        int timeMs = min(baseTimeMs, (int)max(6.0, remGlobal - 10.0));\n        auto deadline = chrono::steady_clock::now() + chrono::milliseconds(timeMs);\n\n        if (qFull == 0) {\n            int trials = maxSol * 5;\n            for (int t = 0; t < trials && (int)sols.size() < maxSol; t++) {\n                vector<int> asg(M, -1);\n                for (int k = 0; k < M; k++) {\n                    const auto& d = domains[k];\n                    asg[k] = d[rng() % d.size()];\n                }\n                auto m = build_union_mask(asg);\n                normalize_mask(m);\n                if (is_forbidden(m)) continue;\n                sols.push_back(move(asg));\n            }\n            return sols;\n        }\n\n        const int Q_USED_MAX = 140;\n        vector<int> used = choose_used_constraints(min(qFull, Q_USED_MAX));\n        int q = (int)used.size();\n\n        vector<vector<int8_t>> varMin(M, vector<int8_t>(q, 0));\n        vector<vector<int8_t>> varMax(M, vector<int8_t>(q, 0));\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            vector<int> c1(q, 0);\n\n            for (int p : domains[k]) {\n                const auto& qc = fieldPls[k][p].qcov;\n                for (int r = 0; r < q; r++) c1[r] += qc[used[r]];\n            }\n\n            for (int r = 0; r < q; r++) {\n                bool has1 = c1[r] > 0;\n                bool has0 = (ds - c1[r]) > 0;\n                varMin[k][r] = has0 ? 0 : 1;\n                varMax[k][r] = has1 ? 1 : 0;\n            }\n        }\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (domains[a].size() != domains[b].size()) return domains[a].size() < domains[b].size();\n            return a < b;\n        });\n\n        vector<vector<int>> sufMin(M + 1, vector<int>(q, 0));\n        vector<vector<int>> sufMax(M + 1, vector<int>(q, 0));\n        for (int d = M - 1; d >= 0; d--) {\n            int k = order[d];\n            for (int r = 0; r < q; r++) {\n                sufMin[d][r] = sufMin[d + 1][r] + (int)varMin[k][r];\n                sufMax[d][r] = sufMax[d + 1][r] + (int)varMax[k][r];\n            }\n        }\n\n        vector<int> target(q, 0);\n        for (int r = 0; r < q; r++) target[r] = queryVals[used[r]];\n\n        for (int r = 0; r < q; r++) {\n            if (target[r] < sufMin[0][r] || target[r] > sufMax[0][r]) return sols;\n        }\n\n        vector<vector<int>> domOrd = domains;\n        vector<int> assign(M, -1);\n\n        long long nodes = 0;\n        bool stop = false;\n\n        auto over = [&]() -> bool {\n            if (nodes > nodeLimit) return true;\n            if (chrono::steady_clock::now() >= deadline) return true;\n            if (elapsed_ms() > HARD_LIMIT_MS - 35.0) return true;\n            return false;\n        };\n\n        function<void(int)> dfs = [&](int depth) {\n            if (stop || (int)sols.size() >= maxSol) return;\n\n            if (depth == M) {\n                for (int r = 0; r < q; r++) if (target[r] != 0) return;\n                if (!verify_assignment_full(assign)) return;\n                auto m = build_union_mask(assign);\n                normalize_mask(m);\n                if (!is_forbidden(m)) sols.push_back(assign);\n                return;\n            }\n\n            int k = order[depth];\n            auto& plist = domOrd[k];\n\n            for (int p : plist) {\n                nodes++;\n                if ((nodes & 1023LL) == 0 && over()) {\n                    stop = true;\n                    return;\n                }\n\n                const auto& qc = fieldPls[k][p].qcov;\n                bool ok = true;\n                for (int r = 0; r < q; r++) {\n                    int nt = target[r] - (int)qc[used[r]];\n                    if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (!ok) continue;\n\n                assign[k] = p;\n                for (int r = 0; r < q; r++) target[r] -= (int)qc[used[r]];\n                dfs(depth + 1);\n                for (int r = 0; r < q; r++) target[r] += (int)qc[used[r]];\n\n                if (stop || (int)sols.size() >= maxSol) return;\n            }\n\n            assign[k] = -1;\n        };\n\n        int restarts = 0;\n        while (!stop && (int)sols.size() < maxSol && restarts < 4) {\n            for (int k = 0; k < M; k++) {\n                if (domOrd[k].size() > 1) shuffle(domOrd[k].begin(), domOrd[k].end(), rng);\n            }\n            fill(assign.begin(), assign.end(), -1);\n            for (int r = 0; r < q; r++) target[r] = queryVals[used[r]];\n            dfs(0);\n            restarts++;\n        }\n\n        // randomized constructive fallback\n        if ((int)sols.size() < max(4, maxSol / 4) && chrono::steady_clock::now() < deadline) {\n            int attempts = 100;\n            for (int at = 0; at < attempts && (int)sols.size() < maxSol; at++) {\n                if (chrono::steady_clock::now() >= deadline) break;\n\n                vector<int> t(q, 0);\n                for (int r = 0; r < q; r++) t[r] = queryVals[used[r]];\n                vector<int> asg(M, -1);\n                bool fail = false;\n\n                for (int depth = 0; depth < M; depth++) {\n                    int k = order[depth];\n                    int chosen = -1;\n                    int feasCnt = 0;\n\n                    for (int p : domOrd[k]) {\n                        const auto& qc = fieldPls[k][p].qcov;\n                        bool ok = true;\n                        for (int r = 0; r < q; r++) {\n                            int nt = t[r] - (int)qc[used[r]];\n                            if (nt < sufMin[depth + 1][r] || nt > sufMax[depth + 1][r]) {\n                                ok = false;\n                                break;\n                            }\n                        }\n                        if (!ok) continue;\n                        feasCnt++;\n                        if ((int)(rng() % feasCnt) == 0) chosen = p;\n                    }\n\n                    if (chosen == -1) {\n                        fail = true;\n                        break;\n                    }\n\n                    asg[k] = chosen;\n                    const auto& qc = fieldPls[k][chosen].qcov;\n                    for (int r = 0; r < q; r++) t[r] -= (int)qc[used[r]];\n                }\n\n                if (fail) continue;\n                bool exactSub = true;\n                for (int r = 0; r < q; r++) if (t[r] != 0) { exactSub = false; break; }\n                if (!exactSub) continue;\n\n                if (!verify_assignment_full(asg)) continue;\n\n                auto m = build_union_mask(asg);\n                normalize_mask(m);\n                if (is_forbidden(m)) continue;\n                sols.push_back(move(asg));\n            }\n        }\n\n        return sols;\n    }\n\n    vector<UnionCand> build_union_candidates(const vector<vector<int>>& sols, vector<int>& freq, int& totalCnt) {\n        unordered_map<array<uint64_t, Mask::W>, int, ArrHash> mp;\n        mp.reserve(sols.size() * 2 + 1);\n\n        vector<UnionCand> cands;\n        for (auto const& asg : sols) {\n            auto m = build_union_mask(asg);\n            normalize_mask(m);\n            if (is_forbidden(m)) continue;\n\n            auto it = mp.find(m);\n            if (it == mp.end()) {\n                int id = (int)cands.size();\n                mp.emplace(m, id);\n                UnionCand uc;\n                uc.m = m;\n                uc.cnt = 1;\n                cands.push_back(move(uc));\n            } else {\n                cands[it->second].cnt++;\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [&](const UnionCand& a, const UnionCand& b) {\n            return a.cnt > b.cnt;\n        });\n\n        totalCnt = 0;\n        for (auto& c : cands) totalCnt += c.cnt;\n\n        freq.assign(n2, 0);\n        if (totalCnt == 0) return cands;\n\n        for (auto const& c : cands) {\n            int add = c.cnt;\n            for (int wi = 0; wi < Mask::W; wi++) {\n                uint64_t bits = c.m[wi];\n                while (bits) {\n                    int b = __builtin_ctzll(bits);\n                    int idx = wi * 64 + b;\n                    if (idx < n2) freq[idx] += add;\n                    bits &= bits - 1;\n                }\n            }\n        }\n\n        return cands;\n    }\n\n    int choose_uncertain_cell(const vector<int>& freq, int total) const {\n        if (total <= 0) return -1;\n        int best = -1;\n        double bestScore = -1.0;\n\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            int f = freq[idx];\n            if (f == 0 || f == total) continue;\n            double p = (double)f / (double)total;\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    int choose_entropy_cell(const vector<vector<int>>& domains) const {\n        vector<double> p0(n2, 1.0);\n        vector<int> cnt(n2, 0);\n\n        for (int k = 0; k < M; k++) {\n            int ds = (int)domains[k].size();\n            if (ds <= 0) continue;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            for (int p : domains[k]) {\n                for (int idx : fieldPls[k][p].cells) cnt[idx]++;\n            }\n\n            double inv = 1.0 / (double)ds;\n            for (int idx = 0; idx < n2; idx++) {\n                if (drilledVal[idx] != -1) continue;\n                if (cnt[idx] == 0) continue;\n                double pk = cnt[idx] * inv;\n                p0[idx] *= (1.0 - pk);\n            }\n        }\n\n        int best = -1;\n        double bestScore = -1.0;\n        for (int idx = 0; idx < n2; idx++) {\n            if (drilledVal[idx] != -1) continue;\n            double p = 1.0 - p0[idx];\n            double sc = p * (1.0 - p);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = idx;\n            }\n        }\n        return best;\n    }\n\n    int infer_interval(int drilled) const {\n        if (drilled < 60)  return 1;\n        if (drilled < 140) return 2;\n        if (drilled < 220) return 4;\n        if (drilled < 300) return 6;\n        return 9;\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        const int maxOps = 2 * n2;\n        int turn = 0;\n\n        while (ops < maxOps) {\n            turn++;\n            int drilledCnt = (int)queryVals.size();\n            int unknown = n2 - drilledCnt;\n\n            if (unknown == 0) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    (void)res;\n                }\n                return;\n            }\n\n            double now = elapsed_ms();\n            bool emergency = (now > EMERGENCY_MS || now > HARD_LIMIT_MS - 70.0);\n\n            int next = -1;\n\n            if (!emergency) {\n                int interval = infer_interval(drilledCnt);\n                bool doInference = (drilledCnt < 20) || (turn % interval == 0);\n\n                if (doInference) {\n                    vector<vector<int>> domains;\n                    bool feasible = propagate_domains(domains);\n\n                    if (!feasible) {\n                        next = first_unknown_cell();\n                    } else {\n                        // unique placement per field => direct guess candidate\n                        bool unique = true;\n                        vector<int> uniqAsg(M, -1);\n                        for (int k = 0; k < M; k++) {\n                            if (domains[k].size() != 1) {\n                                unique = false;\n                                break;\n                            }\n                            uniqAsg[k] = domains[k][0];\n                        }\n                        if (unique && can_afford_guess(2) && wrongGuesses < MAX_WRONG_GUESSES) {\n                            int r = submit_guess_mask(build_union_mask(uniqAsg));\n                            if (r == 1) return;\n                            if (r == 0) continue;\n                        }\n\n                        next = choose_entropy_cell(domains);\n\n                        // sampling\n                        if (drilledCnt >= 4 && elapsed_ms() < 2500.0) {\n                            double rem = HARD_LIMIT_MS - elapsed_ms();\n                            if (rem > 18.0) {\n                                int maxSol = 40, tMs = 12;\n                                long long nodeLim = 240000;\n\n                                if (drilledCnt < 40) {\n                                    maxSol = 40; nodeLim = 250000; tMs = 14;\n                                } else if (drilledCnt < 120) {\n                                    maxSol = 60; nodeLim = 500000; tMs = 20;\n                                } else if (drilledCnt < 220) {\n                                    maxSol = 55; nodeLim = 450000; tMs = 16;\n                                } else {\n                                    maxSol = 40; nodeLim = 260000; tMs = 10;\n                                }\n\n                                tMs = min(tMs, (int)max(6.0, rem * 0.18));\n\n                                auto sols = sample_solutions(domains, maxSol, nodeLim, tMs);\n\n                                if (!sols.empty()) {\n                                    vector<int> freq;\n                                    int total = 0;\n                                    auto cands = build_union_candidates(sols, freq, total);\n\n                                    if (total > 0) {\n                                        double p0 = (double)cands[0].cnt / (double)total;\n                                        bool madeGuess = false;\n\n                                        if (can_afford_guess(2) && wrongGuesses < MAX_WRONG_GUESSES) {\n                                            bool g1 = false;\n                                            if ((int)cands.size() == 1 && total >= 3) g1 = true;\n                                            else if (p0 >= 0.88 && total >= 8) g1 = true;\n                                            else if (p0 >= 0.78 && total >= 12 && drilledCnt >= 10) g1 = true;\n                                            else if (p0 >= 0.66 && total >= 20 && drilledCnt >= 24) g1 = true;\n\n                                            if (g1) {\n                                                int r = submit_guess_mask(cands[0].m);\n                                                if (r == 1) return;\n                                                if (r == 0) madeGuess = true;\n                                            }\n\n                                            // late aggressive burst: try top-2 if candidate set small\n                                            if (!madeGuess && drilledCnt >= 140 && unknown >= 80 && (int)cands.size() <= 3) {\n                                                int tries = min(2, (int)cands.size());\n                                                for (int ci = 0; ci < tries; ci++) {\n                                                    double pp = (double)cands[ci].cnt / (double)total;\n                                                    if (pp < 0.20) break;\n                                                    if (!can_afford_guess(2) || wrongGuesses >= MAX_WRONG_GUESSES) break;\n                                                    int r = submit_guess_mask(cands[ci].m);\n                                                    if (r == 1) return;\n                                                    if (r == 0) madeGuess = true;\n                                                }\n                                            }\n                                        }\n\n                                        if (madeGuess) continue;\n\n                                        int u = choose_uncertain_cell(freq, total);\n                                        if (u != -1) next = u;\n                                        else if (next == -1) next = choose_entropy_cell(domains);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (next == -1) {\n                int f = pick_frontier_cell();\n                if (f != -1) next = f;\n            }\n\n            if (next == -1) {\n                if (drilledCnt < min(8, N)) next = pick_prior_cell();\n                if (next == -1) next = pick_prior_cell();\n            }\n\n            if (next == -1) next = first_unknown_cell();\n\n            if (next == -1) {\n                vector<int> ans = exact_from_drilled();\n                if (ops < maxOps) {\n                    int res = ask_answer(ans);\n                    ops++;\n                    if (res == 1) return;\n                }\n                return;\n            }\n\n            int v = ask_drill(next);\n            ops++;\n            add_drill(next, v);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    OilSolver solver;\n    solver.read_input();\n    solver.build_placements();\n    solver.build_prior_order();\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\nusing ll = long long;\n\nstruct Iseg {\n    int c, l, r; // coordinate c, interval [l,r)\n    bool operator==(const Iseg& o) const { return c == o.c && l == o.l && r == o.r; }\n};\n\nstruct Candidate {\n    vector<array<int, 4>> rects; // by request rank k\n    vector<Iseg> hsegs;          // y=c, x in [l,r)\n    vector<Iseg> vsegs;          // x=c, y in [l,r)\n    vector<int> areas;           // sorted cell areas\n    ll shortage = 0;             // day-dependent\n    int boundaryLen = 0;         // shape-dependent\n    uint64_t hash = 0;           // shape hash\n    unsigned char src = 0;       // 1: local, 2: global proto, 4: path proto\n};\n\n// ---------- Forward declarations (compile-order safety) ----------\nstatic bool generate_guillotine_candidate(\n    int W, const vector<int>& dayA, const vector<int>& ord, Candidate& outCand,\n    uint64_t seed, int mode, unsigned char src);\n\nstatic vector<Candidate> generate_shelf_one_order(\n    int W, const vector<int>& dayA, const vector<int>& ord,\n    int capRows, const vector<int>& widthModes);\n\nstatic vector<Candidate> generate_fixed_height_templates(\n    int W, const vector<int>& dayA, const vector<int>& ord,\n    const vector<vector<int>>& templates, const vector<int>& widthModes,\n    unsigned char src);\n\n// ---------- Utilities ----------\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 shape_hash(const vector<Iseg>& H, const vector<Iseg>& V) {\n    uint64_t h = 0x123456789abcdefULL;\n    auto add = [&](uint64_t v) {\n        h ^= splitmix64(v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));\n    };\n    add((uint64_t)H.size() + 0x11111111ULL);\n    for (auto& s : H) {\n        uint64_t p = ((uint64_t)s.c << 22) ^ ((uint64_t)s.l << 11) ^ (uint64_t)s.r;\n        add((p << 1) | 1ULL);\n    }\n    add(0xfedcba987654321ULL);\n    add((uint64_t)V.size() + 0x22222222ULL);\n    for (auto& s : V) {\n        uint64_t p = ((uint64_t)s.c << 22) ^ ((uint64_t)s.l << 11) ^ (uint64_t)s.r;\n        add((p << 1) | 0ULL);\n    }\n    return h;\n}\n\nstatic vector<Iseg> merge_segments(vector<Iseg> segs) {\n    sort(segs.begin(), segs.end(), [](const Iseg& a, const Iseg& b) {\n        if (a.c != b.c) return a.c < b.c;\n        if (a.l != b.l) return a.l < b.l;\n        return a.r < b.r;\n    });\n    vector<Iseg> out;\n    out.reserve(segs.size());\n    for (auto& s : segs) {\n        if (s.l >= s.r) continue;\n        if (out.empty() || out.back().c != s.c || s.l > out.back().r) out.push_back(s);\n        else out.back().r = max(out.back().r, s.r);\n    }\n    return out;\n}\n\nstatic inline ll rect_area(const array<int, 4>& r) {\n    return 1LL * (r[2] - r[0]) * (r[3] - r[1]);\n}\n\nstatic ll calc_shortage(const vector<int>& dayA, const vector<int>& areasSorted) {\n    ll sh = 0;\n    int N = (int)dayA.size();\n    for (int k = 0; k < N; k++) if (areasSorted[k] < dayA[k]) sh += 100LL * (dayA[k] - areasSorted[k]);\n    return sh;\n}\n\nstatic Candidate build_candidate_from_cells(\n    int W,\n    const vector<int>& dayA,\n    const vector<array<int, 4>>& cells,\n    unsigned char src = 1\n) {\n    int N = (int)dayA.size();\n    Candidate c;\n    c.src = src;\n    c.rects.resize(N);\n    c.areas.resize(N);\n\n    vector<pair<ll, int>> ord;\n    ord.reserve(N);\n    for (int i = 0; i < N; i++) ord.push_back({rect_area(cells[i]), i});\n    sort(ord.begin(), ord.end(), [](auto& a, auto& b) {\n        if (a.first != b.first) return a.first < b.first;\n        return a.second < b.second;\n    });\n\n    for (int k = 0; k < N; k++) {\n        c.rects[k] = cells[ord[k].second];\n        c.areas[k] = (int)ord[k].first;\n    }\n    c.shortage = calc_shortage(dayA, c.areas);\n\n    vector<Iseg> rawH, rawV;\n    rawH.reserve(2 * N);\n    rawV.reserve(2 * N);\n\n    for (auto& rc : cells) {\n        int y0 = rc[0], x0 = rc[1], y1 = rc[2], x1 = rc[3];\n        if (y0 > 0) rawH.push_back({y0, x0, x1});\n        if (y1 < W) rawH.push_back({y1, x0, x1});\n        if (x0 > 0) rawV.push_back({x0, y0, y1});\n        if (x1 < W) rawV.push_back({x1, y0, y1});\n    }\n\n    c.hsegs = merge_segments(move(rawH));\n    c.vsegs = merge_segments(move(rawV));\n\n    ll bl = 0;\n    for (auto& s : c.hsegs) bl += (s.r - s.l);\n    for (auto& s : c.vsegs) bl += (s.r - s.l);\n    c.boundaryLen = (int)bl;\n    c.hash = shape_hash(c.hsegs, c.vsegs);\n    return c;\n}\n\nstatic Candidate clone_for_day(const Candidate& proto, const vector<int>& dayA, unsigned char srcOverride = 0) {\n    Candidate c = proto;\n    c.shortage = calc_shortage(dayA, c.areas);\n    if (srcOverride) c.src = srcOverride;\n    return c;\n}\n\nstatic Candidate transpose_candidate(const Candidate& base, int W, const vector<int>& dayA, unsigned char srcOverride = 0) {\n    (void)W;\n    vector<array<int, 4>> cells = base.rects;\n    for (auto& r : cells) {\n        swap(r[0], r[1]);\n        swap(r[2], r[3]);\n    }\n    return build_candidate_from_cells(W, dayA, cells, srcOverride ? srcOverride : base.src);\n}\n\nstatic bool same_shape(const Candidate& a, const Candidate& b) {\n    if (a.hash != b.hash) return false;\n    return a.hsegs == b.hsegs && a.vsegs == b.vsegs;\n}\n\nstatic ll symdiff_len(const vector<Iseg>& A, const vector<Iseg>& B) {\n    ll cost = 0;\n    int i = 0, j = 0;\n    while (i < (int)A.size() || j < (int)B.size()) {\n        int c;\n        if (j == (int)B.size() || (i < (int)A.size() && A[i].c < B[j].c)) c = A[i].c;\n        else c = B[j].c;\n\n        int i0 = i, j0 = j;\n        while (i < (int)A.size() && A[i].c == c) i++;\n        while (j < (int)B.size() && B[j].c == c) j++;\n\n        ll lenA = 0, lenB = 0;\n        for (int p = i0; p < i; p++) lenA += (A[p].r - A[p].l);\n        for (int q = j0; q < j; q++) lenB += (B[q].r - B[q].l);\n\n        ll inter = 0;\n        int p = i0, q = j0;\n        while (p < i && q < j) {\n            int L = max(A[p].l, B[q].l);\n            int R = min(A[p].r, B[q].r);\n            if (R > L) inter += (R - L);\n            if (A[p].r < B[q].r) p++;\n            else q++;\n        }\n        cost += lenA + lenB - 2LL * inter;\n    }\n    return cost;\n}\n\nstatic inline ll transition_cost(const Candidate& A, const Candidate& B) {\n    return symdiff_len(A.hsegs, B.hsegs) + symdiff_len(A.vsegs, B.vsegs);\n}\n\nstatic void add_order_unique(vector<vector<int>>& orders, const vector<int>& ord) {\n    for (auto& v : orders) if (v == ord) return;\n    orders.push_back(ord);\n}\n\nstatic void add_template_unique(vector<vector<int>>& templates, const vector<int>& h) {\n    if (h.empty()) return;\n    for (auto& t : templates) if (t == h) return;\n    templates.push_back(h);\n}\n\nstatic int min_height_segment(const vector<int>& arr, int l, int r, int W) {\n    auto ok = [&](int h) -> bool {\n        ll sw = 0;\n        for (int i = l; i < r; i++) {\n            sw += (arr[i] + h - 1) / h;\n            if (sw > W) return false;\n        }\n        return true;\n    };\n    if (!ok(W)) return W + 1;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) >> 1;\n        if (ok(mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nstatic int closest_feasible(const vector<int>& feasible, int t) {\n    auto it = lower_bound(feasible.begin(), feasible.end(), t);\n    if (it == feasible.begin()) return *it;\n    if (it == feasible.end()) return feasible.back();\n    int a = *it, b = *prev(it);\n    return (abs(a - t) < abs(b - t)) ? a : b;\n}\n\nstatic vector<int> sample_rows(const vector<int>& feasible, int cap) {\n    if (feasible.empty()) return {};\n    if ((int)feasible.size() <= cap) return feasible;\n    cap = max(cap, 1);\n\n    set<int> S;\n    auto add_target = [&](int t) { S.insert(closest_feasible(feasible, t)); };\n\n    add_target(1); add_target(2); add_target(3); add_target(4); add_target(5); add_target(8);\n    add_target(feasible.back());\n\n    int m = (int)feasible.size();\n    for (int i = 0; i < cap; i++) {\n        int idx = (int)(1LL * i * (m - 1) / max(1, cap - 1));\n        S.insert(feasible[idx]);\n    }\n\n    vector<int> ret(S.begin(), S.end());\n    if ((int)ret.size() > cap) {\n        vector<int> tmp;\n        for (int i = 0; i < cap; i++) {\n            int idx = (int)(1LL * i * ((int)ret.size() - 1) / max(1, cap - 1));\n            tmp.push_back(ret[idx]);\n        }\n        sort(tmp.begin(), tmp.end());\n        tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());\n        ret.swap(tmp);\n    }\n    return ret;\n}\n\nstatic void add_var_unique(vector<vector<int>>& vars, const vector<int>& v) {\n    if (v.empty()) return;\n    for (auto& u : vars) if (u == v) return;\n    vars.push_back(v);\n}\n\nstatic void add_split_unique(vector<vector<int>>& splits, const vector<int>& sp) {\n    for (auto& u : splits) if (u == sp) return;\n    splits.push_back(sp);\n}\n\nstatic vector<int> snapped_variant(const vector<int>& hmin, int slack, int W, int Q, int mode) {\n    int rr = (int)hmin.size();\n    vector<int> pref(rr + 1, 0);\n    for (int i = 0; i < rr; i++) pref[i + 1] = pref[i] + hmin[i];\n\n    vector<int> inc(rr + 1, 0);\n    inc[0] = 0;\n    inc[rr] = slack;\n\n    int prev = 0;\n    for (int t = 1; t < rr; t++) {\n        int p = pref[t];\n        int targetY;\n        if (mode == 0) {\n            targetY = ((p + Q - 1) / Q) * Q;\n        } else {\n            int ideal = (int)llround((double)W * t / rr);\n            int dn = (ideal / Q) * Q;\n            int up = ((ideal + Q - 1) / Q) * Q;\n            targetY = (abs(ideal - dn) <= abs(up - ideal) ? dn : up);\n            if (targetY < p) targetY = ((p + Q - 1) / Q) * Q;\n        }\n        int des = targetY - p;\n        des = max(des, prev);\n        des = min(des, slack);\n        inc[t] = des;\n        prev = des;\n    }\n\n    for (int t = rr - 1; t >= 1; t--) inc[t] = min(inc[t], inc[t + 1]);\n    for (int t = 1; t <= rr; t++) inc[t] = max(inc[t], inc[t - 1]);\n    inc[rr] = slack;\n\n    vector<int> h(rr);\n    for (int g = 0; g < rr; g++) h[g] = hmin[g] + (inc[g + 1] - inc[g]);\n    return h;\n}\n\nstatic vector<int> random_variant(const vector<int>& hmin, int slack, uint64_t seed) {\n    int rr = (int)hmin.size();\n    mt19937_64 rng(seed);\n\n    vector<int> cuts(rr + 1, 0);\n    cuts[0] = 0;\n    cuts[rr] = slack;\n    uniform_int_distribution<int> dist(0, slack);\n    for (int i = 1; i < rr; i++) cuts[i] = dist(rng);\n    sort(cuts.begin(), cuts.end());\n\n    vector<int> h(rr);\n    for (int g = 0; g < rr; g++) h[g] = hmin[g] + (cuts[g + 1] - cuts[g]);\n    return h;\n}\n\nstatic void apply_width_mode(vector<int>& w, int slack, int mode) {\n    int m = (int)w.size();\n    if (m == 0 || slack <= 0) return;\n    if (m == 1) {\n        w[0] += slack;\n        return;\n    }\n\n    if (mode == 0) {\n        w[m - 1] += slack;\n    } else if (mode == 1) {\n        w[0] += slack;\n    } else if (mode == 2) {\n        int q = slack / m, rem = slack % m;\n        for (int i = 0; i < m; i++) w[i] += q + (i < rem ? 1 : 0);\n    } else { // proportional\n        ll sumw = 0;\n        for (int x : w) sumw += x;\n        if (sumw <= 0) {\n            w[m - 1] += slack;\n            return;\n        }\n        vector<pair<ll, int>> frac;\n        frac.reserve(m);\n        int used = 0;\n        for (int i = 0; i < m; i++) {\n            ll num = 1LL * slack * w[i];\n            int add = (int)(num / sumw);\n            ll fr = num % sumw;\n            w[i] += add;\n            used += add;\n            frac.push_back({fr, i});\n        }\n        int rem = slack - used;\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        for (int t = 0; t < rem; t++) w[frac[t % m].second]++;\n    }\n}\n\nstatic bool build_cells_from_split_heights(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    const vector<int>& split,\n    const vector<int>& heights,\n    int widthMode,\n    vector<array<int, 4>>& cells\n) {\n    int rr = (int)heights.size();\n    int N = (int)dayA.size();\n    if ((int)split.size() != rr + 1 || split[0] != 0 || split[rr] != N) return false;\n\n    int sumH = 0;\n    for (int h : heights) {\n        if (h <= 0) return false;\n        sumH += h;\n    }\n    if (sumH != W) return false;\n\n    cells.clear();\n    cells.reserve(N);\n\n    int y = 0;\n    for (int g = 0; g < rr; g++) {\n        int l = split[g], r = split[g + 1];\n        if (!(l < r)) return false;\n        int h = heights[g];\n\n        vector<int> minw;\n        minw.reserve(r - l);\n        int sumMin = 0;\n        for (int t = l; t < r; t++) {\n            int req = dayA[ord[t]];\n            int mw = (req + h - 1) / h;\n            if (mw <= 0) return false;\n            minw.push_back(mw);\n            sumMin += mw;\n            if (sumMin > W) return false;\n        }\n\n        int slack = W - sumMin;\n        vector<int> widths = minw;\n        apply_width_mode(widths, slack, widthMode);\n\n        int x = 0;\n        for (int ww : widths) {\n            if (ww <= 0) return false;\n            cells.push_back({y, x, y + h, x + ww});\n            x += ww;\n        }\n        if (x != W) return false;\n        y += h;\n    }\n    if (y != W) return false;\n    return (int)cells.size() == N;\n}\n\nstatic vector<int> make_snap_template(int W, int r, int Q) {\n    vector<int> b(r + 1);\n    b[0] = 0;\n    b[r] = W;\n    int prev = 0;\n    for (int i = 1; i < r; i++) {\n        double ideal = 1.0 * W * i / r;\n        int y = (int)llround(ideal / Q) * Q;\n        y = max(y, prev + 1);\n        y = min(y, W - (r - i));\n        b[i] = y;\n        prev = y;\n    }\n    vector<int> h(r);\n    for (int i = 0; i < r; i++) h[i] = b[i + 1] - b[i];\n    return h;\n}\n\nstatic vector<vector<int>> make_fixed_templates(int W, int N, bool smallScale) {\n    vector<int> rset;\n    if (smallScale) rset = {1,2,3,4,5,6,8,10,12,16};\n    else rset = {1,2,3,4,5,6,8,10,12};\n\n    vector<vector<int>> templates;\n    for (int r : rset) {\n        if (r <= 0 || r > N) continue;\n\n        vector<int> h1(r, W / r);\n        int rem = W % r;\n        for (int i = 0; i < rem; i++) h1[i]++;\n        add_template_unique(templates, h1);\n\n        if (rem > 0) {\n            vector<int> h2(r, W / r);\n            for (int i = 0; i < rem; i++) h2[r - 1 - i]++;\n            add_template_unique(templates, h2);\n        }\n\n        if (r <= 12) add_template_unique(templates, make_snap_template(W, r, 50));\n    }\n    return templates;\n}\n\n// ---------- Dedup / trim ----------\nstatic vector<Candidate> dedup_shape_only(vector<Candidate> pool) {\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n    unordered_map<uint64_t, vector<int>> mp;\n    mp.reserve(pool.size() * 2 + 1);\n\n    for (auto& c : pool) {\n        auto& vec = mp[c.hash];\n        bool merged = false;\n        for (int id : vec) {\n            if (same_shape(c, uniq[id])) {\n                unsigned char srcU = (unsigned char)(uniq[id].src | c.src);\n                bool better = false;\n                if (c.boundaryLen < uniq[id].boundaryLen) better = true;\n                else if (c.boundaryLen == uniq[id].boundaryLen && c.shortage < uniq[id].shortage) better = true;\n                if (better) {\n                    Candidate t = c;\n                    t.src = srcU;\n                    uniq[id] = move(t);\n                } else {\n                    uniq[id].src = srcU;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) {\n            vec.push_back((int)uniq.size());\n            uniq.push_back(move(c));\n        }\n    }\n    return uniq;\n}\n\nstatic void dedup_and_trim(vector<Candidate>& pool, int maxCand, int freeArea) {\n    if (pool.empty()) return;\n    maxCand = max(maxCand, 1);\n\n    vector<Candidate> uniq;\n    uniq.reserve(pool.size());\n    unordered_map<uint64_t, vector<int>> mp;\n    mp.reserve(pool.size() * 2 + 1);\n\n    for (auto& c : pool) {\n        auto& vec = mp[c.hash];\n        bool merged = false;\n        for (int id : vec) {\n            if (same_shape(c, uniq[id])) {\n                unsigned char srcU = (unsigned char)(uniq[id].src | c.src);\n                bool better = false;\n                if (c.shortage < uniq[id].shortage) better = true;\n                else if (c.shortage == uniq[id].shortage && c.boundaryLen < uniq[id].boundaryLen) better = true;\n                if (better) {\n                    Candidate t = c;\n                    t.src = srcU;\n                    uniq[id] = move(t);\n                } else {\n                    uniq[id].src = srcU;\n                }\n                merged = true;\n                break;\n            }\n        }\n        if (!merged) {\n            vec.push_back((int)uniq.size());\n            uniq.push_back(move(c));\n        }\n    }\n\n    if ((int)uniq.size() <= maxCand) {\n        pool.swap(uniq);\n        return;\n    }\n\n    int M = (int)uniq.size();\n    vector<int> ids(M);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byShort = ids;\n    sort(byShort.begin(), byShort.end(), [&](int i, int j) {\n        if (uniq[i].shortage != uniq[j].shortage) return uniq[i].shortage < uniq[j].shortage;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    vector<int> byBound = ids;\n    sort(byBound.begin(), byBound.end(), [&](int i, int j) {\n        if (uniq[i].boundaryLen != uniq[j].boundaryLen) return uniq[i].boundaryLen < uniq[j].boundaryLen;\n        return uniq[i].shortage < uniq[j].shortage;\n    });\n\n    vector<int> byMix = ids;\n    sort(byMix.begin(), byMix.end(), [&](int i, int j) {\n        ll si = uniq[i].shortage + 16LL * uniq[i].boundaryLen;\n        ll sj = uniq[j].shortage + 16LL * uniq[j].boundaryLen;\n        if (si != sj) return si < sj;\n        if (uniq[i].shortage != uniq[j].shortage) return uniq[i].shortage < uniq[j].shortage;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    vector<int> proto = ids;\n    proto.erase(remove_if(proto.begin(), proto.end(), [&](int id) {\n        return !(uniq[id].src & (2 | 4));\n    }), proto.end());\n    sort(proto.begin(), proto.end(), [&](int i, int j) {\n        ll si = uniq[i].shortage + 10LL * uniq[i].boundaryLen;\n        ll sj = uniq[j].shortage + 10LL * uniq[j].boundaryLen;\n        if (si != sj) return si < sj;\n        return uniq[i].boundaryLen < uniq[j].boundaryLen;\n    });\n\n    double t = (freeArea - 5000.0) / 250000.0;\n    t = max(0.0, min(1.0, t));\n\n    ll bestS = uniq[byShort[0]].shortage;\n    ll margin = (ll)llround(50000.0 + 170000.0 * t);\n\n    vector<int> near;\n    near.reserve(M);\n    for (int id : ids) if (uniq[id].shortage <= bestS + margin) near.push_back(id);\n    sort(near.begin(), near.end(), [&](int i, int j) {\n        if (uniq[i].boundaryLen != uniq[j].boundaryLen) return uniq[i].boundaryLen < uniq[j].boundaryLen;\n        return uniq[i].shortage < uniq[j].shortage;\n    });\n\n    int qShort = (int)llround(maxCand * (0.70 - 0.30 * t));\n    int qProto = (int)llround(maxCand * (0.15 + 0.20 * t));\n    int qNear  = (int)llround(maxCand * (0.10 + 0.05 * t));\n    qShort = max(qShort, 1);\n    qProto = max(qProto, 0);\n    qNear  = max(qNear, 0);\n\n    int minProtoKeep;\n    if (bestS > 0) minProtoKeep = min((int)proto.size(), (freeArea > 120000 ? 6 : 2));\n    else minProtoKeep = min((int)proto.size(), (freeArea > 120000 ? 8 : 4));\n    qProto = max(qProto, minProtoKeep);\n\n    while (qShort + qProto + qNear > maxCand) {\n        if (qNear > 0) qNear--;\n        else if (qShort > 1) qShort--;\n        else if (qProto > minProtoKeep) qProto--;\n        else if (qProto > 0) qProto--;\n        else break;\n    }\n    int qMix = max(0, maxCand - qShort - qProto - qNear);\n\n    vector<char> used(M, 0);\n    vector<int> sel;\n    sel.reserve(maxCand);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxCand || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    pick(byShort, qShort);\n    pick(proto, qProto);\n    pick(near, qNear);\n    pick(byMix, qMix);\n    pick(byBound, maxCand);\n    pick(byShort, maxCand);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) out.push_back(move(uniq[id]));\n    pool.swap(out);\n}\n\n// ---------- Shelf / fixed templates ----------\nstatic vector<Candidate> generate_shelf_one_order(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    int capRows,\n    const vector<int>& widthModes\n) {\n    int N = (int)dayA.size();\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    vector<vector<int>> htab(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            htab[l][r] = min_height_segment(arr, l, r, W);\n        }\n    }\n\n    const int INF = 1e9;\n    vector<vector<int>> dp(N + 1, vector<int>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int rr = 1; rr <= N; rr++) {\n        for (int i = 1; i <= N; i++) {\n            int best = INF, bestj = -1;\n            for (int j = 0; j < i; j++) {\n                if (dp[rr - 1][j] == INF) continue;\n                int h = htab[j][i];\n                if (h > W) continue;\n                int v = dp[rr - 1][j] + h;\n                if (v < best || (v == best && j > bestj)) {\n                    best = v;\n                    bestj = j;\n                }\n            }\n            dp[rr][i] = best;\n            par[rr][i] = bestj;\n        }\n    }\n\n    vector<int> feasibleRows;\n    for (int rr = 1; rr <= N; rr++) if (dp[rr][N] <= W) feasibleRows.push_back(rr);\n    vector<int> selRows = sample_rows(feasibleRows, capRows);\n\n    vector<Candidate> out;\n    out.reserve(selRows.size() * 24);\n\n    for (int rr : selRows) {\n        vector<int> split(rr + 1, 0);\n        split[rr] = N;\n        int cur = N;\n        bool ok = true;\n        for (int r = rr; r >= 1; r--) {\n            int j = par[r][cur];\n            if (j < 0) { ok = false; break; }\n            split[r - 1] = j;\n            cur = j;\n        }\n        if (!ok || split[0] != 0) continue;\n\n        vector<int> hmin(rr);\n        int sumMin = 0;\n        for (int g = 0; g < rr; g++) {\n            int l = split[g], r = split[g + 1];\n            hmin[g] = htab[l][r];\n            sumMin += hmin[g];\n        }\n        if (sumMin > W) continue;\n        int slack = W - sumMin;\n\n        vector<vector<int>> hvars;\n        {\n            vector<int> v = hmin;\n            v.back() += slack;\n            add_var_unique(hvars, v);\n        }\n        if (rr >= 2) {\n            vector<int> v = hmin;\n            v[0] += slack;\n            add_var_unique(hvars, v);\n        }\n        if (rr >= 2) {\n            vector<int> v = hmin;\n            int q = slack / rr, rem = slack % rr;\n            for (int g = 0; g < rr; g++) v[g] += q + (g < rem ? 1 : 0);\n            add_var_unique(hvars, v);\n        }\n        if (rr >= 3) {\n            vector<int> v = hmin;\n            v[rr / 2] += slack;\n            add_var_unique(hvars, v);\n        }\n\n        add_var_unique(hvars, snapped_variant(hmin, slack, W, 50, 0));\n        add_var_unique(hvars, snapped_variant(hmin, slack, W, 50, 1));\n        add_var_unique(hvars, snapped_variant(hmin, slack, W, 100, 1));\n\n        if (slack > 0 && rr >= 2) {\n            uint64_t seed = 1469598103934665603ULL ^ (uint64_t)rr;\n            for (int x : split) seed = splitmix64(seed ^ (uint64_t)(x + 0x9e37));\n            add_var_unique(hvars, random_variant(hmin, slack, seed ^ 1ULL));\n        }\n\n        vector<array<int, 4>> cells;\n        for (auto& hv : hvars) {\n            for (int wm : widthModes) {\n                if (build_cells_from_split_heights(W, dayA, ord, split, hv, wm, cells)) {\n                    out.push_back(build_candidate_from_cells(W, dayA, cells, 1));\n                }\n            }\n        }\n    }\n\n    return out;\n}\n\nstatic vector<Candidate> generate_fixed_height_templates(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    const vector<vector<int>>& templates,\n    const vector<int>& widthModes,\n    unsigned char src\n) {\n    int N = (int)dayA.size();\n    vector<int> arr(N);\n    for (int i = 0; i < N; i++) arr[i] = dayA[ord[i]];\n\n    const int INFINT = 1e9;\n    const ll INF64 = (1LL << 60);\n\n    vector<Candidate> out;\n    vector<array<int, 4>> cells;\n\n    for (auto& hvec : templates) {\n        int rr = (int)hvec.size();\n        if (rr <= 0 || rr > N) continue;\n\n        int sumH = 0;\n        bool bad = false;\n        for (int h : hvec) {\n            if (h <= 0) bad = true;\n            sumH += h;\n        }\n        if (bad || sumH != W) continue;\n\n        vector<vector<vector<int>>> slack(rr, vector<vector<int>>(N + 1, vector<int>(N + 1, INFINT)));\n\n        for (int g = 0; g < rr; g++) {\n            int h = hvec[g];\n            for (int l = 0; l < N; l++) {\n                int sumw = 0;\n                for (int i = l + 1; i <= N; i++) {\n                    sumw += (arr[i - 1] + h - 1) / h;\n                    if (sumw > W) break;\n                    slack[g][l][i] = W - sumw;\n                }\n            }\n        }\n\n        vector<vector<int>> splits;\n        for (int obj = 0; obj < 2; obj++) {\n            vector<vector<ll>> dp(rr + 1, vector<ll>(N + 1, INF64));\n            vector<vector<int>> par(rr + 1, vector<int>(N + 1, -1));\n            dp[0][0] = 0;\n\n            for (int g = 1; g <= rr; g++) {\n                for (int i = 1; i <= N; i++) {\n                    ll best = INF64;\n                    int bestj = -1;\n                    for (int j = 0; j < i; j++) {\n                        if (dp[g - 1][j] >= INF64 / 4) continue;\n                        int sl = slack[g - 1][j][i];\n                        if (sl >= INFINT) continue;\n                        ll add = (obj == 0 ? 1LL * sl * sl : 1LL * sl);\n                        ll val = dp[g - 1][j] + add;\n                        if (val < best || (val == best && j > bestj)) {\n                            best = val;\n                            bestj = j;\n                        }\n                    }\n                    dp[g][i] = best;\n                    par[g][i] = bestj;\n                }\n            }\n\n            if (dp[rr][N] >= INF64 / 4) continue;\n            vector<int> split(rr + 1, 0);\n            split[rr] = N;\n            int cur = N;\n            bool ok = true;\n            for (int g = rr; g >= 1; g--) {\n                int j = par[g][cur];\n                if (j < 0) { ok = false; break; }\n                split[g - 1] = j;\n                cur = j;\n            }\n            if (ok && split[0] == 0) add_split_unique(splits, split);\n        }\n\n        for (auto& split : splits) {\n            for (int wm : widthModes) {\n                if (build_cells_from_split_heights(W, dayA, ord, split, hvec, wm, cells)) {\n                    out.push_back(build_candidate_from_cells(W, dayA, cells, src));\n                }\n            }\n        }\n    }\n\n    return out;\n}\n\n// ---------- Guillotine ----------\nstatic bool generate_guillotine_candidate(\n    int W,\n    const vector<int>& dayA,\n    const vector<int>& ord,\n    Candidate& outCand,\n    uint64_t seed,\n    int mode,\n    unsigned char src\n) {\n    int N = (int)dayA.size();\n    vector<int> vals(N);\n    for (int i = 0; i < N; i++) vals[i] = dayA[ord[i]];\n\n    vector<ll> ps(N + 1, 0);\n    for (int i = 0; i < N; i++) ps[i + 1] = ps[i] + vals[i];\n\n    mt19937_64 rng(seed);\n\n    struct Opt {\n        int orient; // 0 vertical split, 1 horizontal split\n        int m, cut;\n        ll score;\n    };\n\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n\n    function<bool(int,int,int,int,int,int)> dfs = [&](int l, int r, int y0, int y1, int x0, int x1) -> bool {\n        if (r - l == 1) {\n            if (!(y0 < y1 && x0 < x1)) return false;\n            cells.push_back({y0, x0, y1, x1});\n            return true;\n        }\n\n        int h = y1 - y0, w = x1 - x0;\n        if (h <= 0 || w <= 0) return false;\n\n        ll S = ps[r] - ps[l];\n        if (S <= 0) return false;\n\n        int pref = (w >= h ? 0 : 1);\n        if (mode > 0 && (rng() & 1ULL)) pref ^= 1;\n\n        vector<Opt> opts;\n        opts.reserve((r - l - 1) * 4);\n\n        for (int pass = 0; pass < 2; pass++) {\n            int orient = (pass == 0 ? pref : (pref ^ 1));\n            for (int m = l + 1; m < r; m++) {\n                ll s1 = ps[m] - ps[l];\n                ll s2 = S - s1;\n\n                auto add_cut = [&](int cut, int orientFlag) {\n                    ll score;\n                    if (orientFlag == 0) {\n                        ll cap1 = 1LL * cut * h;\n                        ll cap2 = 1LL * (w - cut) * h;\n                        ll sl1 = cap1 - s1, sl2 = cap2 - s2;\n                        ll bal = llabs(2LL * (m - l) - (r - l));\n                        score = sl1 * sl1 + sl2 * sl2 + 4LL * bal;\n                    } else {\n                        ll cap1 = 1LL * cut * w;\n                        ll cap2 = 1LL * (h - cut) * w;\n                        ll sl1 = cap1 - s1, sl2 = cap2 - s2;\n                        ll bal = llabs(2LL * (m - l) - (r - l));\n                        score = sl1 * sl1 + sl2 * sl2 + 4LL * bal;\n                    }\n                    if (orientFlag != pref) score += 180;\n                    if (mode == 1) score += (ll)(rng() % 2500ULL);\n                    if (mode == 2) score += (ll)(rng() % 9000ULL);\n                    opts.push_back({orientFlag, m, cut, score});\n                };\n\n                if (orient == 0) {\n                    ll min1 = max(1LL, (s1 + h - 1) / h);\n                    ll min2 = max(1LL, (s2 + h - 1) / h);\n                    if (min1 + min2 > w) continue;\n                    int low = (int)min1, high = w - (int)min2;\n                    int c0 = (int)llround((double)w * (double)s1 / (double)S);\n                    c0 = max(low, min(high, c0));\n\n                    vector<int> cuts = {c0};\n                    if (mode >= 1) {\n                        int cm = (low + high) / 2;\n                        if (cm != c0) cuts.push_back(cm);\n                    }\n                    if (mode >= 2 && high - low >= 3) {\n                        int cr = low + (int)(rng() % (uint64_t)(high - low + 1));\n                        bool ex = false;\n                        for (int c : cuts) if (c == cr) ex = true;\n                        if (!ex) cuts.push_back(cr);\n                    }\n                    for (int cut : cuts) add_cut(cut, 0);\n\n                } else {\n                    ll min1 = max(1LL, (s1 + w - 1) / w);\n                    ll min2 = max(1LL, (s2 + w - 1) / w);\n                    if (min1 + min2 > h) continue;\n                    int low = (int)min1, high = h - (int)min2;\n                    int c0 = (int)llround((double)h * (double)s1 / (double)S);\n                    c0 = max(low, min(high, c0));\n\n                    vector<int> cuts = {c0};\n                    if (mode >= 1) {\n                        int cm = (low + high) / 2;\n                        if (cm != c0) cuts.push_back(cm);\n                    }\n                    if (mode >= 2 && high - low >= 3) {\n                        int cr = low + (int)(rng() % (uint64_t)(high - low + 1));\n                        bool ex = false;\n                        for (int c : cuts) if (c == cr) ex = true;\n                        if (!ex) cuts.push_back(cr);\n                    }\n                    for (int cut : cuts) add_cut(cut, 1);\n                }\n            }\n        }\n\n        if (opts.empty()) return false;\n        sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) { return a.score < b.score; });\n\n        int top = min<int>((mode == 0 ? 5 : 8), (int)opts.size());\n        vector<int> ordIdx(top);\n        iota(ordIdx.begin(), ordIdx.end(), 0);\n        if (mode > 0) shuffle(ordIdx.begin(), ordIdx.end(), rng);\n\n        int lim = min(top, 5);\n        for (int z = 0; z < lim; z++) {\n            const auto& op = opts[ordIdx[z]];\n            size_t old = cells.size();\n\n            bool ok = false;\n            if (op.orient == 0) {\n                int xm = x0 + op.cut;\n                ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                     dfs(op.m, r, y0, y1, xm, x1);\n            } else {\n                int ym = y0 + op.cut;\n                ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                     dfs(op.m, r, ym, y1, x0, x1);\n            }\n            if (ok) return true;\n            cells.resize(old);\n        }\n\n        if (mode > 0) {\n            int lim2 = min<int>(3, (int)opts.size());\n            for (int z = 0; z < lim2; z++) {\n                const auto& op = opts[z];\n                size_t old = cells.size();\n\n                bool ok = false;\n                if (op.orient == 0) {\n                    int xm = x0 + op.cut;\n                    ok = dfs(l, op.m, y0, y1, x0, xm) &&\n                         dfs(op.m, r, y0, y1, xm, x1);\n                } else {\n                    int ym = y0 + op.cut;\n                    ok = dfs(l, op.m, y0, ym, x0, x1) &&\n                         dfs(op.m, r, ym, y1, x0, x1);\n                }\n                if (ok) return true;\n                cells.resize(old);\n            }\n        }\n\n        return false;\n    };\n\n    bool ok = dfs(0, N, 0, W, 0, W);\n    if (!ok || (int)cells.size() != N) return false;\n    outCand = build_candidate_from_cells(W, dayA, cells, src);\n    return true;\n}\n\n// ---------- DP ----------\nstruct ThreePathResult {\n    ll cost0, cost1, cost2;\n    vector<int> path0, path1, path2;\n};\n\nstatic ThreePathResult solve_dp_three_paths(const vector<vector<Candidate>>& cands, int w1, int w2) {\n    int D = (int)cands.size();\n    const ll INF = (1LL << 62);\n\n    vector<vector<int>> par0(D), par1(D), par2(D);\n\n    vector<ll> dp0Prev(cands[0].size(), INF), dp1Prev(cands[0].size(), INF), dp2Prev(cands[0].size(), INF);\n    vector<ll> dp0Cur, dp1Cur, dp2Cur;\n\n    for (int i = 0; i < (int)cands[0].size(); i++) {\n        ll s = cands[0][i].shortage;\n        dp0Prev[i] = s;\n        dp1Prev[i] = s;\n        dp2Prev[i] = s;\n    }\n\n    for (int d = 1; d < D; d++) {\n        int P = (int)cands[d - 1].size();\n        int C = (int)cands[d].size();\n\n        dp0Cur.assign(C, INF);\n        dp1Cur.assign(C, INF);\n        dp2Cur.assign(C, INF);\n        par0[d].assign(C, -1);\n        par1[d].assign(C, -1);\n        par2[d].assign(C, -1);\n\n        for (int i = 0; i < C; i++) {\n            ll add = cands[d][i].shortage;\n            ll best0 = INF, best1 = INF, best2 = INF;\n            int b0 = 0, b1 = 0, b2 = 0;\n\n            for (int j = 0; j < P; j++) {\n                ll tr = transition_cost(cands[d - 1][j], cands[d][i]);\n\n                ll v0 = dp0Prev[j] + tr + add;\n                if (v0 < best0) { best0 = v0; b0 = j; }\n\n                ll v1 = dp1Prev[j] + (ll)w1 * tr + add;\n                if (v1 < best1) { best1 = v1; b1 = j; }\n\n                ll v2 = dp2Prev[j] + (ll)w2 * tr + add;\n                if (v2 < best2) { best2 = v2; b2 = j; }\n            }\n\n            dp0Cur[i] = best0;\n            dp1Cur[i] = best1;\n            dp2Cur[i] = best2;\n            par0[d][i] = b0;\n            par1[d][i] = b1;\n            par2[d][i] = b2;\n        }\n\n        dp0Prev.swap(dp0Cur);\n        dp1Prev.swap(dp1Cur);\n        dp2Prev.swap(dp2Cur);\n    }\n\n    int last0 = 0, last1 = 0, last2 = 0;\n    for (int i = 1; i < (int)dp0Prev.size(); i++) if (dp0Prev[i] < dp0Prev[last0]) last0 = i;\n    for (int i = 1; i < (int)dp1Prev.size(); i++) if (dp1Prev[i] < dp1Prev[last1]) last1 = i;\n    for (int i = 1; i < (int)dp2Prev.size(); i++) if (dp2Prev[i] < dp2Prev[last2]) last2 = i;\n\n    vector<int> path0(D), path1(D), path2(D);\n    path0[D - 1] = last0;\n    path1[D - 1] = last1;\n    path2[D - 1] = last2;\n    for (int d = D - 1; d >= 1; d--) {\n        path0[d - 1] = par0[d][path0[d]];\n        path1[d - 1] = par1[d][path1[d]];\n        path2[d - 1] = par2[d][path2[d]];\n    }\n\n    return {dp0Prev[last0], dp1Prev[last1], dp2Prev[last2], path0, path1, path2};\n}\n\nstatic pair<ll, vector<int>> solve_dp_prototypes(\n    const vector<Candidate>& protos,\n    const vector<vector<int>>& a\n) {\n    int P = (int)protos.size();\n    int D = (int)a.size();\n    const ll INF = (1LL << 62);\n    if (P == 0) return {INF, {}};\n\n    vector<vector<int>> tr(P, vector<int>(P, 0));\n    for (int i = 0; i < P; i++) {\n        for (int j = i + 1; j < P; j++) {\n            int v = (int)transition_cost(protos[i], protos[j]);\n            tr[i][j] = tr[j][i] = v;\n        }\n    }\n\n    vector<vector<ll>> sh(D, vector<ll>(P));\n    for (int d = 0; d < D; d++) for (int p = 0; p < P; p++) sh[d][p] = calc_shortage(a[d], protos[p].areas);\n\n    vector<vector<int>> par(D, vector<int>(P, -1));\n    vector<ll> dpPrev(P, INF), dpCur(P, INF);\n\n    for (int p = 0; p < P; p++) dpPrev[p] = sh[0][p];\n\n    for (int d = 1; d < D; d++) {\n        fill(dpCur.begin(), dpCur.end(), INF);\n        for (int i = 0; i < P; i++) {\n            ll add = sh[d][i];\n            ll best = INF;\n            int bestj = 0;\n            for (int j = 0; j < P; j++) {\n                ll v = dpPrev[j] + tr[j][i] + add;\n                if (v < best) {\n                    best = v;\n                    bestj = j;\n                }\n            }\n            dpCur[i] = best;\n            par[d][i] = bestj;\n        }\n        dpPrev.swap(dpCur);\n    }\n\n    int last = 0;\n    for (int p = 1; p < P; p++) if (dpPrev[p] < dpPrev[last]) last = p;\n\n    vector<int> path(D, 0);\n    path[D - 1] = last;\n    for (int d = D - 1; d >= 1; d--) path[d - 1] = par[d][path[d]];\n    return {dpPrev[last], path};\n}\n\n// ---------- Proto helpers ----------\nstatic vector<Candidate> trim_prototypes(vector<Candidate> protos, const vector<vector<int>>& a, int maxK, int avgFree) {\n    protos = dedup_shape_only(move(protos));\n    if ((int)protos.size() <= maxK) return protos;\n\n    int P = (int)protos.size();\n    int D = (int)a.size();\n    double t = avgFree / 250000.0;\n    t = max(0.0, min(1.0, t));\n    ll lam = (ll)llround(1.5 + 1.5 * t);\n\n    vector<pair<ll,int>> rk;\n    rk.reserve(P);\n    for (int i = 0; i < P; i++) {\n        ll total = 0;\n        for (int d = 0; d < D; d++) total += calc_shortage(a[d], protos[i].areas);\n        ll score = total + lam * 1LL * D * protos[i].boundaryLen;\n        rk.push_back({score, i});\n    }\n    sort(rk.begin(), rk.end());\n\n    vector<Candidate> out;\n    out.reserve(maxK);\n    for (int i = 0; i < maxK; i++) {\n        Candidate c = protos[rk[i].second];\n        c.src |= 2;\n        out.push_back(move(c));\n    }\n    return out;\n}\n\nstatic vector<Candidate> select_global_prototypes(\n    const vector<vector<Candidate>>& cands,\n    const vector<vector<int>>& a,\n    int maxProto,\n    int avgFreeArea\n) {\n    vector<Candidate> pool;\n    for (auto& day : cands) for (auto& c : day) pool.push_back(c);\n    pool = dedup_shape_only(move(pool));\n    if (pool.empty()) return {};\n\n    int P = (int)pool.size();\n    int D = (int)a.size();\n    if (P <= maxProto) {\n        for (auto& c : pool) c.src = 2;\n        sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n            if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n            return x.shortage < y.shortage;\n        });\n        return pool;\n    }\n\n    double t = avgFreeArea / 250000.0;\n    t = max(0.0, min(1.0, t));\n\n    ll lam = (ll)llround(2.0 + 2.0 * t);\n    int perDayBoundaryCoef = (int)llround(3.0 + 3.0 * t);\n\n    vector<ll> total(P, 0), gscore(P, 0);\n    vector<int> wins(P, 0);\n\n    int TOPK = min(4, P);\n    vector<pair<ll,int>> rank(P);\n\n    for (int d = 0; d < D; d++) {\n        for (int p = 0; p < P; p++) {\n            ll sh = calc_shortage(a[d], pool[p].areas);\n            total[p] += sh;\n            rank[p] = {sh + (ll)perDayBoundaryCoef * pool[p].boundaryLen, p};\n        }\n\n        if (TOPK < P) nth_element(rank.begin(), rank.begin() + TOPK, rank.end());\n        sort(rank.begin(), rank.begin() + TOPK);\n\n        for (int k = 0; k < TOPK; k++) wins[rank[k].second] += (TOPK - k);\n    }\n\n    for (int p = 0; p < P; p++) gscore[p] = total[p] + lam * 1LL * D * pool[p].boundaryLen;\n\n    vector<int> ids(P);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byGlobal = ids;\n    sort(byGlobal.begin(), byGlobal.end(), [&](int i, int j) {\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        if (pool[i].boundaryLen != pool[j].boundaryLen) return pool[i].boundaryLen < pool[j].boundaryLen;\n        return i < j;\n    });\n\n    vector<int> byWins = ids;\n    sort(byWins.begin(), byWins.end(), [&](int i, int j) {\n        if (wins[i] != wins[j]) return wins[i] > wins[j];\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        return i < j;\n    });\n\n    vector<int> byBound = ids;\n    sort(byBound.begin(), byBound.end(), [&](int i, int j) {\n        if (pool[i].boundaryLen != pool[j].boundaryLen) return pool[i].boundaryLen < pool[j].boundaryLen;\n        return gscore[i] < gscore[j];\n    });\n\n    vector<char> used(P, 0);\n    vector<int> sel;\n    sel.reserve(maxProto);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxProto || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    int q1 = maxProto * 50 / 100;\n    int q2 = maxProto * 30 / 100;\n    int q3 = maxProto - q1 - q2;\n\n    pick(byGlobal, q1);\n    pick(byWins, q2);\n    pick(byBound, q3);\n    pick(byGlobal, maxProto);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) {\n        pool[id].src = 2;\n        out.push_back(pool[id]);\n    }\n    return out;\n}\n\nstatic vector<Candidate> build_path_prototypes(\n    const vector<vector<Candidate>>& cands,\n    const vector<int>& choice,\n    const vector<vector<int>>& a,\n    int W,\n    int limit,\n    bool addTranspose,\n    unsigned char srcBit\n) {\n    int D = (int)cands.size();\n    vector<Candidate> pool;\n    pool.reserve(D * 2);\n\n    for (int d = 0; d < D; d++) {\n        Candidate p = cands[d][choice[d]];\n        p.src = srcBit;\n        pool.push_back(move(p));\n        if (addTranspose && (d % 2 == 0)) {\n            Candidate t = transpose_candidate(cands[d][choice[d]], W, a[d], srcBit);\n            pool.push_back(move(t));\n        }\n    }\n\n    pool = dedup_shape_only(move(pool));\n    sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n        if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n        return x.shortage < y.shortage;\n    });\n    if ((int)pool.size() > limit) pool.resize(limit);\n    for (auto& p : pool) p.src = srcBit;\n    return pool;\n}\n\nstatic bool extract_shelf_heights(const Candidate& c, int W, vector<int>& heights) {\n    vector<int> ys = {0, W};\n\n    for (auto& h : c.hsegs) {\n        if (h.c <= 0 || h.c >= W) return false;\n        if (h.l != 0 || h.r != W) return false;\n        ys.push_back(h.c);\n    }\n\n    sort(ys.begin(), ys.end());\n    ys.erase(unique(ys.begin(), ys.end()), ys.end());\n    if (ys.front() != 0 || ys.back() != W) return false;\n\n    for (auto& v : c.vsegs) {\n        if (v.c <= 0 || v.c >= W) return false;\n        if (v.l < 0 || v.r > W || v.l >= v.r) return false;\n        auto it = upper_bound(ys.begin(), ys.end(), v.l);\n        if (it != ys.end() && *it < v.r) return false;\n    }\n\n    heights.clear();\n    for (int i = 0; i + 1 < (int)ys.size(); i++) {\n        int h = ys[i + 1] - ys[i];\n        if (h <= 0) return false;\n        heights.push_back(h);\n    }\n\n    int sumH = 0;\n    for (int h : heights) sumH += h;\n    return (sumH == W);\n}\n\nstatic vector<int> blend_heights(const vector<int>& h1, const vector<int>& h2, int W, int snapQ = 0) {\n    if (h1.size() != h2.size() || h1.empty()) return {};\n    int r = (int)h1.size();\n\n    vector<int> b1(r + 1, 0), b2(r + 1, 0), b(r + 1, 0);\n    for (int i = 0; i < r; i++) {\n        b1[i + 1] = b1[i] + h1[i];\n        b2[i + 1] = b2[i] + h2[i];\n    }\n    if (b1[r] != W || b2[r] != W) return {};\n\n    b[0] = 0;\n    b[r] = W;\n    for (int i = 1; i < r; i++) {\n        int y = (int)llround((b1[i] + b2[i]) * 0.5);\n        if (snapQ > 0) {\n            int dn = (y / snapQ) * snapQ;\n            int up = ((y + snapQ - 1) / snapQ) * snapQ;\n            y = (abs(y - dn) <= abs(up - y) ? dn : up);\n        }\n        b[i] = y;\n    }\n\n    for (int i = 1; i < r; i++) b[i] = max(b[i], b[i - 1] + 1);\n    for (int i = r - 1; i >= 1; i--) b[i] = min(b[i], b[i + 1] - 1);\n    for (int i = 1; i < r; i++) if (!(b[i - 1] < b[i] && b[i] < b[i + 1])) return {};\n\n    vector<int> h(r);\n    int sumH = 0;\n    for (int i = 0; i < r; i++) {\n        h[i] = b[i + 1] - b[i];\n        if (h[i] <= 0) return {};\n        sumH += h[i];\n    }\n    if (sumH != W) return {};\n    return h;\n}\n\nstatic vector<Candidate> build_synthetic_prototypes(\n    int W,\n    const vector<vector<int>>& a,\n    const vector<int>& ordAsc,\n    const vector<int>& ordDesc,\n    const vector<int>& zig1,\n    int capRows,\n    const vector<int>& widthModes,\n    bool smallScale\n) {\n    int D = (int)a.size();\n    int N = (int)a[0].size();\n\n    vector<int> meanA(N), medA(N), q25A(N), q75A(N);\n    for (int k = 0; k < N; k++) {\n        vector<int> vals(D);\n        ll s = 0;\n        for (int d = 0; d < D; d++) {\n            vals[d] = a[d][k];\n            s += a[d][k];\n        }\n        sort(vals.begin(), vals.end());\n        meanA[k] = (int)((s + D / 2) / D);\n        medA[k] = vals[D / 2];\n        q25A[k] = vals[D / 4];\n        q75A[k] = vals[(3 * D) / 4];\n    }\n\n    auto fix_nondec = [&](vector<int>& x) {\n        for (int i = 1; i < N; i++) x[i] = max(x[i], x[i - 1]);\n    };\n    fix_nondec(meanA);\n    fix_nondec(medA);\n    fix_nondec(q25A);\n    fix_nondec(q75A);\n\n    vector<vector<int>> synthArrs = {meanA, medA};\n    if (smallScale) {\n        synthArrs.push_back(q25A);\n        synthArrs.push_back(q75A);\n    }\n\n    vector<vector<int>> orders;\n    add_order_unique(orders, ordAsc);\n    add_order_unique(orders, ordDesc);\n    if (smallScale) add_order_unique(orders, zig1);\n\n    vector<Candidate> pool;\n    int capRows2 = min(capRows, 8);\n\n    for (int id = 0; id < (int)synthArrs.size(); id++) {\n        auto& arr = synthArrs[id];\n\n        for (int oi = 0; oi < (int)orders.size(); oi++) {\n            auto vv = generate_shelf_one_order(W, arr, orders[oi], capRows2, widthModes);\n            sort(vv.begin(), vv.end(), [](const Candidate& x, const Candidate& y) {\n                ll sx = x.shortage + 6LL * x.boundaryLen;\n                ll sy = y.shortage + 6LL * y.boundaryLen;\n                if (sx != sy) return sx < sy;\n                return x.boundaryLen < y.boundaryLen;\n            });\n            if ((int)vv.size() > 5) vv.resize(5);\n\n            bool doTrans = (smallScale && oi == 0);\n            for (auto& c : vv) {\n                c.src = 2;\n                pool.push_back(c);\n                if (doTrans) pool.push_back(transpose_candidate(c, W, arr, 2));\n            }\n        }\n\n        Candidate g;\n        uint64_t seed = 0x9e3779b97f4a7c15ULL ^ (uint64_t)(id + 1) * 1000003ULL;\n        if (generate_guillotine_candidate(W, arr, ordAsc, g, seed, 0, 2)) {\n            g.src = 2;\n            pool.push_back(g);\n            if (smallScale) pool.push_back(transpose_candidate(g, W, arr, 2));\n        }\n    }\n\n    pool = dedup_shape_only(move(pool));\n    sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n        if (x.boundaryLen != y.boundaryLen) return x.boundaryLen < y.boundaryLen;\n        return x.shortage < y.shortage;\n    });\n    int cap = smallScale ? 32 : 20;\n    if ((int)pool.size() > cap) pool.resize(cap);\n    for (auto& p : pool) p.src = 2;\n    return pool;\n}\n\nstatic void targeted_random_enrich_day(\n    int W,\n    const vector<int>& dayA,\n    vector<Candidate>& pool,\n    int capRows,\n    const vector<int>& widthModes,\n    int shelfTries,\n    int guillTries,\n    uint64_t seedBase,\n    bool addTranspose\n) {\n    int N = (int)dayA.size();\n    int rowCap = min(8, max(4, capRows));\n\n    for (int t = 0; t < shelfTries; t++) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        uint64_t sd = splitmix64(seedBase ^ (uint64_t)(t + 1) * 1000003ULL);\n        mt19937_64 rng(sd);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        auto vv = generate_shelf_one_order(W, dayA, ord, rowCap, widthModes);\n        sort(vv.begin(), vv.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.shortage != b.shortage) return a.shortage < b.shortage;\n            return a.boundaryLen < b.boundaryLen;\n        });\n        if ((int)vv.size() > 10) vv.resize(10);\n\n        for (auto& c : vv) {\n            c.src |= 1;\n            pool.push_back(c);\n            if (addTranspose && t == 0) pool.push_back(transpose_candidate(c, W, dayA, 1));\n        }\n\n        for (int g = 0; g < guillTries; g++) {\n            Candidate gc;\n            int mode = (g == 0 ? 1 : 2);\n            uint64_t sg = splitmix64(sd ^ (uint64_t)(g + 7) * 11995408973635179863ULL);\n            if (generate_guillotine_candidate(W, dayA, ord, gc, sg, mode, 1)) {\n                pool.push_back(gc);\n                if (addTranspose && g == 0) pool.push_back(transpose_candidate(gc, W, dayA, 1));\n            }\n        }\n    }\n}\n\nstatic vector<Candidate> build_proto_bank(\n    const vector<vector<Candidate>>& cands,\n    const vector<Candidate>& globalProtos,\n    const vector<Candidate>& synthProtos,\n    const vector<int>& choiceMain,\n    const vector<int>& choiceS1,\n    const vector<int>& choiceS2,\n    int perDayPick\n) {\n    int D = (int)cands.size();\n    vector<Candidate> bank;\n    bank.reserve(globalProtos.size() + synthProtos.size() + D * (3 + 3 * perDayPick));\n\n    for (auto& c : globalProtos) bank.push_back(c);\n    for (auto& c : synthProtos) bank.push_back(c);\n\n    int mixPick = max(1, perDayPick / 2);\n\n    for (int d = 0; d < D; d++) {\n        const auto& day = cands[d];\n        int M = (int)day.size();\n        if (M == 0) continue;\n\n        auto add_idx = [&](int id) {\n            if (0 <= id && id < M) bank.push_back(day[id]);\n        };\n\n        add_idx(choiceMain[d]);\n        add_idx(choiceS1[d]);\n        add_idx(choiceS2[d]);\n\n        vector<int> idx(M);\n        iota(idx.begin(), idx.end(), 0);\n\n        sort(idx.begin(), idx.end(), [&](int i, int j) {\n            if (day[i].shortage != day[j].shortage) return day[i].shortage < day[j].shortage;\n            return day[i].boundaryLen < day[j].boundaryLen;\n        });\n        for (int t = 0; t < min(perDayPick, M); t++) add_idx(idx[t]);\n\n        sort(idx.begin(), idx.end(), [&](int i, int j) {\n            if (day[i].boundaryLen != day[j].boundaryLen) return day[i].boundaryLen < day[j].boundaryLen;\n            return day[i].shortage < day[j].shortage;\n        });\n        for (int t = 0; t < min(perDayPick, M); t++) add_idx(idx[t]);\n\n        sort(idx.begin(), idx.end(), [&](int i, int j) {\n            ll si = day[i].shortage + 10LL * day[i].boundaryLen;\n            ll sj = day[j].shortage + 10LL * day[j].boundaryLen;\n            if (si != sj) return si < sj;\n            return i < j;\n        });\n        for (int t = 0; t < min(mixPick, M); t++) add_idx(idx[t]);\n    }\n\n    bank = dedup_shape_only(move(bank));\n    for (auto& c : bank) c.src |= 2;\n    return bank;\n}\n\nstatic vector<Candidate> trim_bank_diverse(vector<Candidate> bank, const vector<vector<int>>& a, int maxK, int avgFree) {\n    bank = dedup_shape_only(move(bank));\n    if ((int)bank.size() <= maxK) return bank;\n\n    int P = (int)bank.size();\n    int D = (int)a.size();\n\n    double t = avgFree / 250000.0;\n    t = max(0.0, min(1.0, t));\n    int dayCoef = (int)llround(2.0 + 2.0 * t);\n    ll lam = (ll)llround(1.8 + 1.8 * t);\n\n    vector<ll> total(P, 0), gscore(P, 0);\n    vector<int> wins(P, 0);\n    vector<pair<ll,int>> rk(P);\n\n    int TOP = min(5, P);\n\n    for (int d = 0; d < D; d++) {\n        for (int p = 0; p < P; p++) {\n            ll sh = calc_shortage(a[d], bank[p].areas);\n            total[p] += sh;\n            rk[p] = {sh + 1LL * dayCoef * bank[p].boundaryLen, p};\n        }\n        if (TOP < P) nth_element(rk.begin(), rk.begin() + TOP, rk.end());\n        sort(rk.begin(), rk.begin() + TOP);\n        for (int i = 0; i < TOP; i++) wins[rk[i].second] += (TOP - i);\n    }\n\n    for (int p = 0; p < P; p++) gscore[p] = total[p] + lam * 1LL * D * bank[p].boundaryLen;\n\n    vector<int> ids(P);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> byG = ids;\n    sort(byG.begin(), byG.end(), [&](int i, int j) {\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        if (bank[i].boundaryLen != bank[j].boundaryLen) return bank[i].boundaryLen < bank[j].boundaryLen;\n        return i < j;\n    });\n\n    vector<int> byW = ids;\n    sort(byW.begin(), byW.end(), [&](int i, int j) {\n        if (wins[i] != wins[j]) return wins[i] > wins[j];\n        if (gscore[i] != gscore[j]) return gscore[i] < gscore[j];\n        return i < j;\n    });\n\n    vector<int> byB = ids;\n    sort(byB.begin(), byB.end(), [&](int i, int j) {\n        if (bank[i].boundaryLen != bank[j].boundaryLen) return bank[i].boundaryLen < bank[j].boundaryLen;\n        return gscore[i] < gscore[j];\n    });\n\n    vector<int> byM = ids;\n    sort(byM.begin(), byM.end(), [&](int i, int j) {\n        ll si = gscore[i] + 3LL * bank[i].boundaryLen;\n        ll sj = gscore[j] + 3LL * bank[j].boundaryLen;\n        if (si != sj) return si < sj;\n        return i < j;\n    });\n\n    vector<char> used(P, 0);\n    vector<int> sel;\n    sel.reserve(maxK);\n\n    auto pick = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)sel.size() >= maxK || lim <= 0) break;\n            if (!used[id]) {\n                used[id] = 1;\n                sel.push_back(id);\n                --lim;\n            }\n        }\n    };\n\n    int qG = maxK * 45 / 100;\n    int qW = maxK * 30 / 100;\n    int qM = maxK * 15 / 100;\n    int qB = maxK - qG - qW - qM;\n\n    pick(byG, qG);\n    pick(byW, qW);\n    pick(byM, qM);\n    pick(byB, qB);\n    pick(byG, maxK);\n\n    vector<Candidate> out;\n    out.reserve(sel.size());\n    for (int id : sel) out.push_back(move(bank[id]));\n    return out;\n}\n\nstatic Candidate fallback_horizontal(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int y0 = (int)(1LL * W * k / N);\n        int y1 = (int)(1LL * W * (k + 1) / N);\n        cells.push_back({y0, 0, y1, W});\n    }\n    return build_candidate_from_cells(W, dayA, cells, 1);\n}\n\nstatic Candidate fallback_vertical(int W, const vector<int>& dayA) {\n    int N = (int)dayA.size();\n    vector<array<int, 4>> cells;\n    cells.reserve(N);\n    for (int k = 0; k < N; k++) {\n        int x0 = (int)(1LL * W * k / N);\n        int x1 = (int)(1LL * W * (k + 1) / N);\n        cells.push_back({0, x0, W, x1});\n    }\n    return build_candidate_from_cells(W, dayA, cells, 1);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int W, D, N;\n    cin >> W >> D >> N;\n\n    vector<vector<int>> a(D, vector<int>(N));\n    for (int d = 0; d < D; d++) for (int k = 0; k < N; k++) cin >> a[d][k];\n\n    vector<int> freeArea(D, 0);\n    int totalFree = 0;\n    for (int d = 0; d < D; d++) {\n        ll s = 0;\n        for (int x : a[d]) s += x;\n        freeArea[d] = (int)(1LL * W * W - s);\n        totalFree += freeArea[d];\n    }\n    int avgFree = totalFree / D;\n\n    int scale = D * N;\n    bool smallScale = (scale <= 1600);\n    bool largeScale = (scale > 2200);\n\n    int CAP_ROWS = smallScale ? min(N, 8) : (largeScale ? min(N, 5) : min(N, 6));\n    int INIT_MAX = smallScale ? 64 : (largeScale ? 46 : 54);\n    int MAX_CAND = smallScale ? 94 : (largeScale ? 70 : 82);\n    int GPROTO = smallScale ? 56 : (largeScale ? 36 : 46);\n    int PATHPROTO = smallScale ? 60 : (largeScale ? 42 : 50);\n    int GUILL_TRIES = smallScale ? 3 : (largeScale ? 1 : 2);\n    int ITER = smallScale ? 3 : (largeScale ? 1 : 2);\n\n    vector<int> widthModesLocal = {0, 2};\n    if (smallScale) widthModesLocal.push_back(3);\n    vector<int> widthModesFixed = {0, 2};\n    if (smallScale) widthModesFixed.push_back(3);\n    vector<int> widthModesRand = widthModesLocal;\n    if (find(widthModesRand.begin(), widthModesRand.end(), 1) == widthModesRand.end()) widthModesRand.push_back(1);\n\n    bool useFixedTemplates = true;\n    if (largeScale && avgFree < 60000) useFixedTemplates = false;\n\n    vector<vector<int>> fixedTemplates = make_fixed_templates(W, N, smallScale);\n\n    vector<int> ordAsc(N), ordDesc(N), zig1, zig2;\n    iota(ordAsc.begin(), ordAsc.end(), 0);\n    for (int i = 0; i < N; i++) ordDesc[i] = N - 1 - i;\n\n    {\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            if (l == r) { zig1.push_back(l); break; }\n            zig1.push_back(l++);\n            zig1.push_back(r--);\n        }\n    }\n    {\n        int l = 0, r = N - 1;\n        while (l <= r) {\n            if (l == r) { zig2.push_back(r); break; }\n            zig2.push_back(r--);\n            zig2.push_back(l++);\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> ll {\n        return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    vector<vector<Candidate>> cands(D);\n\n    // Initial local generation\n    for (int d = 0; d < D; d++) {\n        mt19937 rng(71236721u + 911u * d + 31u * N);\n        vector<int> rnd1 = ordAsc, rnd2 = ordAsc;\n        shuffle(rnd1.begin(), rnd1.end(), rng);\n        shuffle(rnd2.begin(), rnd2.end(), rng);\n\n        vector<vector<int>> shelfOrders, guillOrders;\n        add_order_unique(shelfOrders, ordAsc);\n        add_order_unique(shelfOrders, ordDesc);\n        add_order_unique(shelfOrders, zig1);\n        if (smallScale) add_order_unique(shelfOrders, zig2);\n        add_order_unique(shelfOrders, rnd1);\n        if (smallScale) add_order_unique(shelfOrders, rnd2);\n\n        add_order_unique(guillOrders, ordAsc);\n        add_order_unique(guillOrders, ordDesc);\n        if (!largeScale) add_order_unique(guillOrders, rnd1);\n\n        bool transposeAllShelf = smallScale;\n        bool transposeGuillAll = smallScale;\n\n        vector<Candidate> pool;\n        pool.reserve(1500);\n\n        for (int oi = 0; oi < (int)shelfOrders.size(); oi++) {\n            auto vv = generate_shelf_one_order(W, a[d], shelfOrders[oi], CAP_ROWS, widthModesLocal);\n            bool doTrans = transposeAllShelf || oi < 2;\n            for (auto& c : vv) {\n                pool.push_back(c);\n                if (doTrans) pool.push_back(transpose_candidate(c, W, a[d], 1));\n            }\n        }\n\n        if (useFixedTemplates) {\n            vector<vector<int>> fixedOrders;\n            add_order_unique(fixedOrders, ordAsc);\n            add_order_unique(fixedOrders, ordDesc);\n            if (smallScale) add_order_unique(fixedOrders, zig1);\n\n            for (int oi = 0; oi < (int)fixedOrders.size(); oi++) {\n                auto vv = generate_fixed_height_templates(W, a[d], fixedOrders[oi], fixedTemplates, widthModesFixed, 1);\n                bool doTrans = smallScale && oi == 0;\n                for (auto& c : vv) {\n                    pool.push_back(c);\n                    if (doTrans) pool.push_back(transpose_candidate(c, W, a[d], 1));\n                }\n            }\n        }\n\n        for (auto& ord : guillOrders) {\n            for (int t = 0; t < GUILL_TRIES; t++) {\n                int mode = (t == 0 ? 0 : (t == 1 ? 1 : 2));\n                uint64_t seed = 0x9e3779b97f4a7c15ULL\n                              ^ (uint64_t)(d + 1) * 1000003ULL\n                              ^ (uint64_t)(t + 1) * 911382323ULL\n                              ^ (uint64_t)ord[0] * 972663749ULL;\n\n                Candidate g;\n                if (generate_guillotine_candidate(W, a[d], ord, g, seed, mode, 1)) {\n                    pool.push_back(g);\n                    if (transposeGuillAll || t == 0) pool.push_back(transpose_candidate(g, W, a[d], 1));\n                }\n            }\n        }\n\n        pool.push_back(fallback_horizontal(W, a[d]));\n        pool.push_back(fallback_vertical(W, a[d]));\n\n        dedup_and_trim(pool, INIT_MAX, freeArea[d]);\n        if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n        cands[d] = move(pool);\n    }\n\n    vector<Candidate> synthProtos = build_synthetic_prototypes(\n        W, a, ordAsc, ordDesc, zig1, CAP_ROWS, widthModesLocal, smallScale\n    );\n\n    if (!synthProtos.empty()) {\n        int initAug = min(MAX_CAND, INIT_MAX + (smallScale ? 12 : 8));\n        for (int d = 0; d < D; d++) {\n            auto& pool = cands[d];\n            for (auto& p : synthProtos) pool.push_back(clone_for_day(p, a[d], 2));\n            dedup_and_trim(pool, initAug, freeArea[d]);\n            if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n        }\n    }\n\n    int w1, w2;\n    if (avgFree > 170000) { w1 = 3; w2 = 5; }\n    else if (avgFree > 90000) { w1 = 2; w2 = 4; }\n    else { w1 = 2; w2 = 3; }\n\n    auto res = solve_dp_three_paths(cands, w1, w2);\n    ll bestCost = res.cost0;\n    vector<int> choiceMain = res.path0;\n    vector<int> choiceS1 = res.path1;\n    vector<int> choiceS2 = res.path2;\n\n    vector<vector<array<int, 4>>> bestRects(D);\n    vector<Candidate> bestShape(D);\n    for (int d = 0; d < D; d++) {\n        bestShape[d] = cands[d][choiceMain[d]];\n        bestRects[d] = bestShape[d].rects;\n    }\n\n    vector<Candidate> globalProtos = select_global_prototypes(cands, a, GPROTO, avgFree);\n    for (auto& p : synthProtos) globalProtos.push_back(p);\n    globalProtos = trim_prototypes(move(globalProtos), a, GPROTO + (smallScale ? 10 : 6), avgFree);\n\n    vector<vector<int>> adaptOrders;\n    add_order_unique(adaptOrders, ordAsc);\n    add_order_unique(adaptOrders, ordDesc);\n    if (smallScale) add_order_unique(adaptOrders, zig1);\n\n    for (int iter = 0; iter < ITER; iter++) {\n        if (elapsed_ms() > 2200) break;\n\n        vector<Candidate> mainPathShape(D), s1PathShape(D), s2PathShape(D);\n        for (int d = 0; d < D; d++) {\n            mainPathShape[d] = cands[d][choiceMain[d]];\n            s1PathShape[d] = cands[d][choiceS1[d]];\n            s2PathShape[d] = cands[d][choiceS2[d]];\n            mainPathShape[d].src = s1PathShape[d].src = s2PathShape[d].src = 4;\n        }\n\n        auto pathP1 = build_path_prototypes(cands, choiceMain, a, W, PATHPROTO / 3 + 2, (iter == 0), 4);\n        auto pathP2 = build_path_prototypes(cands, choiceS1, a, W, PATHPROTO / 3 + 2, false, 4);\n        auto pathP3 = build_path_prototypes(cands, choiceS2, a, W, PATHPROTO / 3 + 2, false, 4);\n\n        vector<Candidate> protoAll = globalProtos;\n        for (auto& p : pathP1) protoAll.push_back(p);\n        for (auto& p : pathP2) protoAll.push_back(p);\n        for (auto& p : pathP3) protoAll.push_back(p);\n        if (iter == 0) for (auto& p : synthProtos) protoAll.push_back(p);\n\n        int protoCap = smallScale ? 90 : 66;\n        protoAll = trim_prototypes(move(protoAll), a, protoCap, avgFree);\n\n        vector<pair<ll,int>> hardRank;\n        hardRank.reserve(D);\n        auto local_cost = [&](const vector<Candidate>& path, int d) -> ll {\n            ll v = path[d].shortage;\n            if (d > 0) v += transition_cost(path[d - 1], path[d]);\n            if (d + 1 < D) v += transition_cost(path[d], path[d + 1]);\n            return v;\n        };\n        for (int d = 0; d < D; d++) {\n            ll imp = max(local_cost(mainPathShape, d), max(local_cost(s1PathShape, d), local_cost(s2PathShape, d)));\n            hardRank.push_back({imp, d});\n        }\n        sort(hardRank.begin(), hardRank.end(), [&](auto& x, auto& y) { return x.first > y.first; });\n\n        int hardK = smallScale ? 6 : 4;\n        vector<char> hardFlag(D, 0);\n        for (int i = 0; i < min(hardK, D); i++) {\n            int d = hardRank[i].second;\n            hardFlag[d] = 1;\n            if (d > 0) hardFlag[d - 1] = 1;\n            if (d + 1 < D) hardFlag[d + 1] = 1;\n        }\n\n        bool allowHeavy = elapsed_ms() < 2050;\n\n        for (int d = 0; d < D; d++) {\n            vector<Candidate> pool = cands[d];\n            pool.reserve(pool.size() + (int)protoAll.size() + 200);\n\n            for (auto& p : protoAll) pool.push_back(clone_for_day(p, a[d], p.src));\n\n            auto add_neighbors = [&](const vector<Candidate>& pathShape) {\n                if (d - 1 >= 0) pool.push_back(clone_for_day(pathShape[d - 1], a[d], 4));\n                if (d + 1 < D)  pool.push_back(clone_for_day(pathShape[d + 1], a[d], 4));\n                if (iter == 0) {\n                    if (d - 2 >= 0) pool.push_back(clone_for_day(pathShape[d - 2], a[d], 4));\n                    if (d + 2 < D)  pool.push_back(clone_for_day(pathShape[d + 2], a[d], 4));\n                }\n            };\n            add_neighbors(mainPathShape);\n            add_neighbors(s1PathShape);\n            add_neighbors(s2PathShape);\n\n            bool doLocalTemplate = allowHeavy && (!largeScale || ((d + iter) & 1) == 0) && elapsed_ms() < 2100;\n\n            if (doLocalTemplate) {\n                vector<vector<int>> baseTemps;\n\n                auto collect = [&](const Candidate& c) {\n                    vector<int> hs;\n                    if (extract_shelf_heights(c, W, hs)) add_template_unique(baseTemps, hs);\n                };\n\n                if (d - 1 >= 0) {\n                    collect(mainPathShape[d - 1]);\n                    collect(s1PathShape[d - 1]);\n                    collect(s2PathShape[d - 1]);\n                }\n                if (d + 1 < D) {\n                    collect(mainPathShape[d + 1]);\n                    collect(s1PathShape[d + 1]);\n                    collect(s2PathShape[d + 1]);\n                }\n                if (hardFlag[d]) {\n                    collect(mainPathShape[d]);\n                    collect(s1PathShape[d]);\n                    collect(s2PathShape[d]);\n                }\n\n                vector<vector<int>> localTemps = baseTemps;\n                for (int i = 0; i < (int)baseTemps.size(); i++) {\n                    for (int j = i + 1; j < (int)baseTemps.size(); j++) {\n                        if (baseTemps[i].size() != baseTemps[j].size()) continue;\n                        add_template_unique(localTemps, blend_heights(baseTemps[i], baseTemps[j], W, 0));\n                        if (smallScale) add_template_unique(localTemps, blend_heights(baseTemps[i], baseTemps[j], W, 50));\n                        if ((int)localTemps.size() >= 7) break;\n                    }\n                    if ((int)localTemps.size() >= 7) break;\n                }\n\n                if ((int)localTemps.size() > 5) localTemps.resize(5);\n\n                if (!localTemps.empty()) {\n                    int ordLim = min(2, (int)adaptOrders.size());\n                    if (smallScale && hardFlag[d]) ordLim = min(3, (int)adaptOrders.size());\n                    for (int oi = 0; oi < ordLim; oi++) {\n                        auto vv = generate_fixed_height_templates(W, a[d], adaptOrders[oi], localTemps, widthModesFixed, 4);\n                        for (auto& c : vv) {\n                            c.src = 4;\n                            pool.push_back(c);\n                        }\n                    }\n                }\n            }\n\n            bool doRand = hardFlag[d] && elapsed_ms() < 2000;\n            if (doRand) {\n                int shelfTries = smallScale ? 2 : (largeScale ? 0 : 1);\n                int guillTries = smallScale ? 1 : 0;\n                if (shelfTries > 0 || guillTries > 0) {\n                    uint64_t seedBase = 0x517cc1b727220a95ULL\n                                      ^ (uint64_t)(iter + 1) * 1000003ULL\n                                      ^ (uint64_t)(d + 1) * 911382323ULL\n                                      ^ (uint64_t)(freeArea[d] + 12345);\n                    targeted_random_enrich_day(\n                        W, a[d], pool, CAP_ROWS, widthModesRand,\n                        shelfTries, guillTries, seedBase, smallScale\n                    );\n                }\n            }\n\n            int dayCap = MAX_CAND + (hardFlag[d] ? (smallScale ? 8 : 5) : -(smallScale ? 2 : 1));\n            dayCap = max(dayCap, smallScale ? 56 : 46);\n\n            dedup_and_trim(pool, dayCap, freeArea[d]);\n            if (pool.empty()) pool.push_back(fallback_horizontal(W, a[d]));\n            cands[d] = move(pool);\n        }\n\n        res = solve_dp_three_paths(cands, w1, w2);\n        choiceMain = res.path0;\n        choiceS1 = res.path1;\n        choiceS2 = res.path2;\n\n        if (res.cost0 < bestCost) {\n            bestCost = res.cost0;\n            for (int d = 0; d < D; d++) {\n                bestShape[d] = cands[d][choiceMain[d]];\n                bestRects[d] = bestShape[d].rects;\n            }\n        }\n\n        if (elapsed_ms() < 2200) {\n            int nextG = max(22, GPROTO - 6 - 2 * iter);\n            globalProtos = select_global_prototypes(cands, a, nextG, avgFree);\n            for (auto& p : synthProtos) globalProtos.push_back(p);\n            globalProtos = trim_prototypes(move(globalProtos), a, nextG + (smallScale ? 8 : 5), avgFree);\n        }\n    }\n\n    // Final global prototype-bank DP refinement\n    if (elapsed_ms() < 2400) {\n        int perDayPick = smallScale ? 4 : 3;\n        vector<Candidate> bank = build_proto_bank(\n            cands, globalProtos, synthProtos,\n            choiceMain, choiceS1, choiceS2,\n            perDayPick\n        );\n\n        // add hard-day extras\n        vector<pair<ll,int>> hardRank;\n        hardRank.reserve(D);\n        for (int d = 0; d < D; d++) {\n            const auto& cm = cands[d][choiceMain[d]];\n            ll imp = cm.shortage;\n            if (d > 0) imp += transition_cost(cands[d - 1][choiceMain[d - 1]], cm);\n            if (d + 1 < D) imp += transition_cost(cm, cands[d + 1][choiceMain[d + 1]]);\n            hardRank.push_back({imp, d});\n        }\n        sort(hardRank.begin(), hardRank.end(), greater<pair<ll,int>>());\n\n        int hardExtraDays = min(D, smallScale ? 10 : 6);\n        for (int t = 0; t < hardExtraDays; t++) {\n            int d = hardRank[t].second;\n            const auto& day = cands[d];\n            int M = (int)day.size();\n            if (M == 0) continue;\n            vector<int> idx(M);\n            iota(idx.begin(), idx.end(), 0);\n\n            auto add_top = [&](auto cmp, int k) {\n                sort(idx.begin(), idx.end(), cmp);\n                for (int i = 0; i < min(k, M); i++) bank.push_back(day[idx[i]]);\n            };\n\n            add_top([&](int i, int j) {\n                if (day[i].shortage != day[j].shortage) return day[i].shortage < day[j].shortage;\n                return day[i].boundaryLen < day[j].boundaryLen;\n            }, smallScale ? 4 : 3);\n\n            add_top([&](int i, int j) {\n                if (day[i].boundaryLen != day[j].boundaryLen) return day[i].boundaryLen < day[j].boundaryLen;\n                return day[i].shortage < day[j].shortage;\n            }, smallScale ? 3 : 2);\n\n            add_top([&](int i, int j) {\n                ll si = day[i].shortage + 10LL * day[i].boundaryLen;\n                ll sj = day[j].shortage + 10LL * day[j].boundaryLen;\n                if (si != sj) return si < sj;\n                return i < j;\n            }, 2);\n        }\n\n        int Pmax;\n        if (smallScale) Pmax = (elapsed_ms() < 2000 ? 260 : 200);\n        else Pmax = (elapsed_ms() < 2000 ? 180 : 130);\n\n        bank = trim_bank_diverse(move(bank), a, Pmax, avgFree);\n\n        if (!bank.empty() && elapsed_ms() < 2550) {\n            auto [pcost, ppath] = solve_dp_prototypes(bank, a);\n            if (!ppath.empty() && pcost < bestCost) {\n                bestCost = pcost;\n                for (int d = 0; d < D; d++) {\n                    bestShape[d] = clone_for_day(bank[ppath[d]], a[d], bank[ppath[d]].src);\n                    bestRects[d] = bestShape[d].rects;\n                }\n            }\n        }\n    }\n\n    // Final local coordinate-descent refinement (time-gated)\n    if (elapsed_ms() < 2550) {\n        auto local_eval = [&](const vector<Candidate>& path, int d, const Candidate& cand) -> ll {\n            ll v = cand.shortage;\n            if (d > 0) v += transition_cost(path[d - 1], cand);\n            if (d + 1 < D) v += transition_cost(cand, path[d + 1]);\n            return v;\n        };\n\n        int passes = smallScale ? 2 : 1;\n        for (int pass = 0; pass < passes; pass++) {\n            if (elapsed_ms() > 2850) break;\n\n            vector<pair<ll,int>> rank;\n            rank.reserve(D);\n            for (int d = 0; d < D; d++) rank.push_back({local_eval(bestShape, d, bestShape[d]), d});\n            sort(rank.begin(), rank.end(), greater<pair<ll,int>>());\n\n            int focus = smallScale ? 12 : 7;\n            bool any = false;\n\n            for (int ii = 0; ii < min(focus, D); ii++) {\n                if (elapsed_ms() > 2890) break;\n                int d = rank[ii].second;\n\n                vector<Candidate> pool;\n                pool.reserve(300);\n\n                pool.push_back(bestShape[d]);\n                if (d > 0) pool.push_back(clone_for_day(bestShape[d - 1], a[d], 4));\n                if (d + 1 < D) pool.push_back(clone_for_day(bestShape[d + 1], a[d], 4));\n                if (pass == 0) {\n                    if (d > 1) pool.push_back(clone_for_day(bestShape[d - 2], a[d], 4));\n                    if (d + 2 < D) pool.push_back(clone_for_day(bestShape[d + 2], a[d], 4));\n                }\n\n                // Add top from existing day candidates\n                const auto& day = cands[d];\n                int M = (int)day.size();\n                if (M > 0) {\n                    vector<int> idx(M);\n                    iota(idx.begin(), idx.end(), 0);\n\n                    auto add_top = [&](auto cmp, int k) {\n                        sort(idx.begin(), idx.end(), cmp);\n                        for (int t = 0; t < min(k, M); t++) pool.push_back(day[idx[t]]);\n                    };\n\n                    add_top([&](int i, int j) {\n                        if (day[i].shortage != day[j].shortage) return day[i].shortage < day[j].shortage;\n                        return day[i].boundaryLen < day[j].boundaryLen;\n                    }, smallScale ? 10 : 7);\n\n                    add_top([&](int i, int j) {\n                        if (day[i].boundaryLen != day[j].boundaryLen) return day[i].boundaryLen < day[j].boundaryLen;\n                        return day[i].shortage < day[j].shortage;\n                    }, smallScale ? 6 : 4);\n\n                    add_top([&](int i, int j) {\n                        ll si = day[i].shortage + 10LL * day[i].boundaryLen;\n                        ll sj = day[j].shortage + 10LL * day[j].boundaryLen;\n                        if (si != sj) return si < sj;\n                        return i < j;\n                    }, smallScale ? 4 : 2);\n                }\n\n                // Template adaptation\n                if (elapsed_ms() < 2820) {\n                    vector<vector<int>> temps;\n                    auto collect = [&](const Candidate& c) {\n                        vector<int> hs;\n                        if (extract_shelf_heights(c, W, hs)) add_template_unique(temps, hs);\n                    };\n                    collect(bestShape[d]);\n                    if (d > 0) collect(bestShape[d - 1]);\n                    if (d + 1 < D) collect(bestShape[d + 1]);\n\n                    vector<vector<int>> useTemps = temps;\n                    for (int i = 0; i < (int)temps.size(); i++) {\n                        for (int j = i + 1; j < (int)temps.size(); j++) {\n                            if (temps[i].size() != temps[j].size()) continue;\n                            add_template_unique(useTemps, blend_heights(temps[i], temps[j], W, 0));\n                            if (smallScale) add_template_unique(useTemps, blend_heights(temps[i], temps[j], W, 50));\n                            if ((int)useTemps.size() >= 6) break;\n                        }\n                        if ((int)useTemps.size() >= 6) break;\n                    }\n                    if ((int)useTemps.size() > 4) useTemps.resize(4);\n\n                    if (!useTemps.empty()) {\n                        auto v1 = generate_fixed_height_templates(W, a[d], ordAsc, useTemps, widthModesFixed, 4);\n                        auto v2 = generate_fixed_height_templates(W, a[d], ordDesc, useTemps, widthModesFixed, 4);\n\n                        auto push_limited = [&](vector<Candidate>& vv, int lim) {\n                            sort(vv.begin(), vv.end(), [](const Candidate& x, const Candidate& y) {\n                                if (x.shortage != y.shortage) return x.shortage < y.shortage;\n                                return x.boundaryLen < y.boundaryLen;\n                            });\n                            if ((int)vv.size() > lim) vv.resize(lim);\n                            for (auto& c : vv) pool.push_back(c);\n                        };\n\n                        push_limited(v1, smallScale ? 10 : 7);\n                        push_limited(v2, smallScale ? 10 : 7);\n                    }\n                }\n\n                // tiny random perturbation for top few hard slots\n                if (ii < (smallScale ? 4 : 2) && elapsed_ms() < 2760) {\n                    uint64_t seedBase = 0x8f3f73b5cf1c9d7bULL\n                                      ^ (uint64_t)(pass + 1) * 1000003ULL\n                                      ^ (uint64_t)(d + 1) * 911382323ULL\n                                      ^ (uint64_t)(freeArea[d] + 54321);\n                    targeted_random_enrich_day(\n                        W, a[d], pool, min(CAP_ROWS, 6), widthModesRand,\n                        1, smallScale ? 1 : 0, seedBase, false\n                    );\n                }\n\n                // local dedup\n                vector<Candidate> uniq;\n                uniq.reserve(pool.size());\n                unordered_map<uint64_t, vector<int>> mp;\n                mp.reserve(pool.size() * 2 + 1);\n\n                for (auto& c : pool) {\n                    auto& vec = mp[c.hash];\n                    bool merged = false;\n                    for (int id : vec) {\n                        if (same_shape(c, uniq[id])) {\n                            if (c.shortage < uniq[id].shortage ||\n                                (c.shortage == uniq[id].shortage && c.boundaryLen < uniq[id].boundaryLen)) {\n                                uniq[id] = c;\n                            }\n                            merged = true;\n                            break;\n                        }\n                    }\n                    if (!merged) {\n                        vec.push_back((int)uniq.size());\n                        uniq.push_back(c);\n                    }\n                }\n\n                ll oldv = local_eval(bestShape, d, bestShape[d]);\n                ll bestv = oldv;\n                Candidate bestC = bestShape[d];\n\n                for (auto& c : uniq) {\n                    ll v = local_eval(bestShape, d, c);\n                    if (v < bestv || (v == bestv && c.boundaryLen < bestC.boundaryLen)) {\n                        bestv = v;\n                        bestC = c;\n                    }\n                }\n\n                if (bestv < oldv) {\n                    bestShape[d] = move(bestC);\n                    any = true;\n                }\n            }\n\n            if (!any) break;\n        }\n\n        ll newCost = 0;\n        for (int d = 0; d < D; d++) newCost += bestShape[d].shortage;\n        for (int d = 1; d < D; d++) newCost += transition_cost(bestShape[d - 1], bestShape[d]);\n\n        if (newCost < bestCost) {\n            bestCost = newCost;\n            for (int d = 0; d < D; d++) bestRects[d] = bestShape[d].rects;\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            auto& r = bestRects[d][k];\n            cout << r[0] << ' ' << r[1] << ' ' << r[2] << ' ' << r[3] << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr uint32_t MOD = 998244353u;\nstatic constexpr int N = 9;\nstatic constexpr int K = 81;\nstatic constexpr int CELLS = 81;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return static_cast<int>(next_u64() % static_cast<uint64_t>(n));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // [0,1)\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct Action {\n    uint8_t cell[9];\n    uint32_t val[9];\n    uint32_t thr[9]; // MOD - val\n    long long raw = 0; // sum val\n    int m = 0, p = 0, q = 0;\n};\n\nstruct State {\n    array<uint32_t, CELLS> board{};\n    array<int, K> ops{};\n    long long score = 0;\n};\n\ninline long long gain_add(const uint32_t* b, const Action& a) {\n    int wraps = 0;\n    for (int k = 0; k < 9; k++) wraps += (b[a.cell[k]] >= a.thr[k]);\n    return a.raw - 1LL * MOD * wraps;\n}\n\ninline void apply_add(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        int idx = a.cell[k];\n        uint32_t ov = b[idx];\n        uint32_t nv = ov + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)ov;\n    }\n}\n\ninline void apply_remove(State& st, const Action& a) {\n    uint32_t* b = st.board.data();\n    for (int k = 0; k < 9; k++) {\n        int idx = a.cell[k];\n        uint32_t ov = b[idx];\n        uint32_t v = a.val[k];\n        uint32_t nv = (ov >= v) ? (ov - v) : (ov + MOD - v);\n        b[idx] = nv;\n        st.score += (long long)nv - (long long)ov;\n    }\n}\n\nState make_empty_state(const array<uint32_t, CELLS>& base, int dummy_id) {\n    State st;\n    st.board = base;\n    st.ops.fill(dummy_id);\n    st.score = 0;\n    for (uint32_t v : base) st.score += v;\n    return st;\n}\n\ninline void shuffle_order(array<int, K>& ord, XorShift64& rng) {\n    for (int i = K - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nbool one_sweep(State& st, const vector<Action>& actions, int dummy_id,\n               array<int, K>& order, XorShift64& rng) {\n    shuffle_order(order, rng);\n    bool changed = false;\n    const int A = dummy_id;\n\n    for (int t = 0; t < K; t++) {\n        int pos = order[t];\n        int old = st.ops[pos];\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int best = dummy_id;\n        long long best_gain = 0; // dummy gain\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain || (g == best_gain && id == old)) {\n                best_gain = g;\n                best = id;\n            }\n        }\n\n        if (best != dummy_id) apply_add(st, actions[best]);\n        st.ops[pos] = best;\n        if (best != old) changed = true;\n    }\n    return changed;\n}\n\nvoid local_opt(State& st, const vector<Action>& actions, int dummy_id,\n               Timer& timer, double tl, XorShift64& rng, int max_sweeps) {\n    array<int, K> ord;\n    iota(ord.begin(), ord.end(), 0);\n    for (int sw = 0; sw < max_sweeps; sw++) {\n        if (timer.elapsed() >= tl) break;\n        bool changed = one_sweep(st, actions, dummy_id, ord, rng);\n        if (!changed) break;\n    }\n}\n\nState construct_best_greedy(const array<uint32_t, CELLS>& base,\n                            const vector<Action>& actions, int dummy_id) {\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        int best = dummy_id;\n        long long best_gain = 0;\n        const uint32_t* b = st.board.data();\n\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g > best_gain) {\n                best_gain = g;\n                best = id;\n            }\n        }\n        if (best == dummy_id) break;\n        st.ops[pos] = best;\n        apply_add(st, actions[best]);\n    }\n    return st;\n}\n\nState construct_random_greedy(const array<uint32_t, CELLS>& base,\n                              const vector<Action>& actions, int dummy_id,\n                              XorShift64& rng, int topR) {\n    constexpr int LIM = 8;\n    topR = max(1, min(topR, LIM));\n\n    State st = make_empty_state(base, dummy_id);\n    const int A = dummy_id;\n\n    for (int pos = 0; pos < K; pos++) {\n        array<long long, LIM> bestG;\n        array<int, LIM> bestId;\n        bestG.fill(LLONG_MIN);\n        bestId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (g <= 0) continue;\n            if (g <= bestG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > bestG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                bestG[t] = bestG[t - 1];\n                bestId[t] = bestId[t - 1];\n            }\n            bestG[at] = g;\n            bestId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && bestId[cnt] != -1) cnt++;\n        if (cnt == 0) break;\n\n        int pick;\n        int r = rng.next_int(100);\n        if (r < 55) pick = bestId[0];\n        else if (r < 80) pick = bestId[rng.next_int(min(cnt, 2))];\n        else pick = bestId[rng.next_int(cnt)];\n\n        st.ops[pos] = pick;\n        apply_add(st, actions[pick]);\n    }\n    return st;\n}\n\nvoid compute_marginals(State& st, const vector<Action>& actions, int dummy_id,\n                       array<long long, K>& mg) {\n    static constexpr long long DUMMY_WEAK = -(1LL << 55);\n    for (int i = 0; i < K; i++) {\n        int id = st.ops[i];\n        if (id == dummy_id) {\n            mg[i] = DUMMY_WEAK;\n            continue;\n        }\n        apply_remove(st, actions[id]);\n        mg[i] = gain_add(st.board.data(), actions[id]); // reinsertion gain\n        apply_add(st, actions[id]);\n    }\n}\n\nvector<int> select_positions(State& st, const vector<Action>& actions, int dummy_id,\n                             XorShift64& rng, int cnt, double worst_ratio, bool focus_bad) {\n    cnt = max(0, min(cnt, K));\n    vector<int> res;\n    res.reserve(cnt);\n    array<unsigned char, K> used{};\n    used.fill(0);\n\n    if (focus_bad && cnt > 0) {\n        array<long long, K> mg;\n        compute_marginals(st, actions, dummy_id, mg);\n\n        array<int, K> idx;\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            if (mg[a] != mg[b]) return mg[a] < mg[b];\n            return a < b;\n        });\n\n        int bad = (int)llround(cnt * worst_ratio);\n        bad = max(1, min(bad, cnt));\n        int pool = min(K, max(bad + 4, bad * 3));\n\n        for (int t = 0; t < bad; t++) {\n            int chosen = -1;\n            for (int tr = 0; tr < 20; tr++) {\n                int cand = idx[rng.next_int(pool)];\n                if (!used[cand]) {\n                    chosen = cand;\n                    break;\n                }\n            }\n            if (chosen == -1) {\n                for (int j = 0; j < K; j++) {\n                    int cand = idx[j];\n                    if (!used[cand]) {\n                        chosen = cand;\n                        break;\n                    }\n                }\n            }\n            if (chosen == -1) break;\n            used[chosen] = 1;\n            res.push_back(chosen);\n        }\n    }\n\n    while ((int)res.size() < cnt) {\n        int p = rng.next_int(K);\n        if (used[p]) continue;\n        used[p] = 1;\n        res.push_back(p);\n    }\n\n    for (int i = (int)res.size() - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(res[i], res[j]);\n    }\n    return res;\n}\n\nvoid destroy_repair_guided(State& st, const vector<Action>& actions, int dummy_id,\n                           vector<int> positions, XorShift64& rng,\n                           int topR, bool allow_negative) {\n    constexpr int LIM = 8;\n    topR = max(1, min(topR, LIM));\n    const int A = dummy_id;\n\n    for (int pos : positions) {\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n        st.ops[pos] = dummy_id;\n    }\n\n    for (int i = (int)positions.size() - 1; i > 0; --i) {\n        int j = rng.next_int(i + 1);\n        swap(positions[i], positions[j]);\n    }\n\n    for (int pos : positions) {\n        array<long long, LIM> bestG;\n        array<int, LIM> bestId;\n        bestG.fill(LLONG_MIN);\n        bestId.fill(-1);\n\n        const uint32_t* b = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g = gain_add(b, actions[id]);\n            if (!allow_negative && g <= 0) continue;\n            if (g <= bestG[topR - 1]) continue;\n\n            int at = topR - 1;\n            while (at > 0 && g > bestG[at - 1]) --at;\n            for (int t = topR - 1; t > at; --t) {\n                bestG[t] = bestG[t - 1];\n                bestId[t] = bestId[t - 1];\n            }\n            bestG[at] = g;\n            bestId[at] = id;\n        }\n\n        int cnt = 0;\n        while (cnt < topR && bestId[cnt] != -1) cnt++;\n\n        int pick = dummy_id;\n        if (cnt > 0) {\n            int r = rng.next_int(100);\n            if (allow_negative && bestG[0] <= 0) {\n                if (r < 70) {\n                    pick = dummy_id;\n                } else if (r < 88) {\n                    pick = bestId[0];\n                } else {\n                    pick = bestId[rng.next_int(cnt)];\n                }\n            } else {\n                if (r < 58) pick = bestId[0];\n                else if (r < 83) pick = bestId[rng.next_int(min(cnt, 2))];\n                else pick = bestId[rng.next_int(cnt)];\n            }\n        }\n\n        st.ops[pos] = pick;\n        if (pick != dummy_id) apply_add(st, actions[pick]);\n    }\n}\n\nvoid random_perturb(State& st, const vector<Action>& actions, int dummy_id,\n                    XorShift64& rng, int cnt) {\n    const int A = dummy_id;\n    for (int t = 0; t < cnt; t++) {\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int nid = dummy_id;\n        int mode = rng.next_int(100);\n\n        if (mode < 12) {\n            nid = dummy_id;\n        } else if (mode < 70) {\n            long long bestg = LLONG_MIN;\n            int bestid = dummy_id;\n            for (int s = 0; s < 24; s++) {\n                int id = rng.next_int(A);\n                long long g = gain_add(st.board.data(), actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            if (bestg > 0 || rng.next_int(100) < 35) nid = bestid;\n        } else if (mode < 90) {\n            int id = rng.next_int(A);\n            long long g = gain_add(st.board.data(), actions[id]);\n            if (g > -(long long)MOD / 5 || rng.next_int(100) < 20) nid = id;\n        } else {\n            long long bestg = 0;\n            int bestid = dummy_id;\n            const uint32_t* b = st.board.data();\n            for (int id = 0; id < A; id++) {\n                long long g = gain_add(b, actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            nid = bestid;\n        }\n\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n    }\n}\n\nbool pair_improve_once(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, const vector<int>* pool,\n                       int top_first, bool allow_neg_first) {\n    constexpr int LIM = 8;\n    top_first = max(1, min(top_first, LIM));\n\n    int p1, p2;\n    if (pool && (int)pool->size() >= 2) {\n        p1 = (*pool)[rng.next_int((int)pool->size())];\n        do p2 = (*pool)[rng.next_int((int)pool->size())];\n        while (p2 == p1);\n        if (rng.next_int(100) < 25) {\n            int q = rng.next_int(K - 1);\n            if (q >= p1) q++;\n            p2 = q;\n        }\n    } else {\n        p1 = rng.next_int(K);\n        p2 = rng.next_int(K - 1);\n        if (p2 >= p1) p2++;\n    }\n\n    long long before = st.score;\n    int old1 = st.ops[p1];\n    int old2 = st.ops[p2];\n\n    if (old1 != dummy_id) apply_remove(st, actions[old1]);\n    if (old2 != dummy_id) apply_remove(st, actions[old2]);\n    st.ops[p1] = dummy_id;\n    st.ops[p2] = dummy_id;\n\n    array<long long, LIM> firstG;\n    array<int, LIM> firstId;\n    firstG.fill(LLONG_MIN);\n    firstId.fill(-1);\n\n    const int A = dummy_id;\n    const uint32_t* b = st.board.data();\n    for (int id = 0; id < A; id++) {\n        long long g = gain_add(b, actions[id]);\n        if (!allow_neg_first && g <= 0) continue;\n        if (g <= firstG[top_first - 1]) continue;\n\n        int at = top_first - 1;\n        while (at > 0 && g > firstG[at - 1]) --at;\n        for (int t = top_first - 1; t > at; --t) {\n            firstG[t] = firstG[t - 1];\n            firstId[t] = firstId[t - 1];\n        }\n        firstG[at] = g;\n        firstId[at] = id;\n    }\n\n    array<long long, LIM + 1> candG{};\n    array<int, LIM + 1> candId{};\n    int candCnt = 1;\n    candG[0] = 0;\n    candId[0] = dummy_id;\n    for (int i = 0; i < top_first; i++) {\n        if (firstId[i] == -1) break;\n        candG[candCnt] = firstG[i];\n        candId[candCnt] = firstId[i];\n        candCnt++;\n    }\n\n    long long bestTot = LLONG_MIN;\n    int best1 = dummy_id, best2 = dummy_id;\n\n    for (int c = 0; c < candCnt; c++) {\n        int id1 = candId[c];\n        long long g1 = candG[c];\n\n        if (id1 != dummy_id) apply_add(st, actions[id1]);\n\n        long long bestg2 = 0;\n        int bestid2 = dummy_id;\n        const uint32_t* b2 = st.board.data();\n        for (int id = 0; id < A; id++) {\n            long long g2 = gain_add(b2, actions[id]);\n            if (g2 > bestg2) {\n                bestg2 = g2;\n                bestid2 = id;\n            }\n        }\n\n        long long tot = g1 + bestg2;\n        if (tot > bestTot) {\n            bestTot = tot;\n            best1 = id1;\n            best2 = bestid2;\n        }\n\n        if (id1 != dummy_id) apply_remove(st, actions[id1]);\n    }\n\n    if (best1 != dummy_id) apply_add(st, actions[best1]);\n    if (best2 != dummy_id) apply_add(st, actions[best2]);\n    st.ops[p1] = best1;\n    st.ops[p2] = best2;\n\n    if (st.score > before) return true;\n\n    // revert\n    if (best1 != dummy_id) apply_remove(st, actions[best1]);\n    if (best2 != dummy_id) apply_remove(st, actions[best2]);\n    if (old1 != dummy_id) apply_add(st, actions[old1]);\n    if (old2 != dummy_id) apply_add(st, actions[old2]);\n    st.ops[p1] = old1;\n    st.ops[p2] = old2;\n    return false;\n}\n\nbool pair_local_search(State& st, const vector<Action>& actions, int dummy_id,\n                       XorShift64& rng, int trials, int top_first,\n                       bool targeted, bool allow_neg_first,\n                       Timer& timer, double tl) {\n    vector<int> pool;\n    if (targeted) {\n        int ps = min(30, K);\n        pool = select_positions(st, actions, dummy_id, rng, ps, 0.85, true);\n    }\n\n    bool improved = false;\n    for (int t = 0; t < trials; t++) {\n        if ((t & 3) == 0 && timer.elapsed() >= tl) break;\n        if (pair_improve_once(st, actions, dummy_id, rng,\n                              targeted ? &pool : nullptr,\n                              top_first, allow_neg_first)) {\n            improved = true;\n        }\n    }\n    return improved;\n}\n\nvoid anneal_kick(State& st, const vector<Action>& actions, int dummy_id,\n                 XorShift64& rng, int steps, int sample_n,\n                 double T0, double T1, Timer& timer, double tl) {\n    const int A = dummy_id;\n    for (int t = 0; t < steps; t++) {\n        if ((t & 15) == 0 && timer.elapsed() >= tl) break;\n\n        double T = T0 + (T1 - T0) * (double)t / (double)max(1, steps - 1);\n\n        int pos = rng.next_int(K);\n        int old = st.ops[pos];\n        long long oldScore = st.score;\n\n        if (old != dummy_id) apply_remove(st, actions[old]);\n\n        int nid = dummy_id;\n        int mode = rng.next_int(100);\n        if (mode < 10) {\n            nid = dummy_id;\n        } else {\n            long long bestg = LLONG_MIN;\n            int bestid = dummy_id;\n            for (int s = 0; s < sample_n; s++) {\n                int id = rng.next_int(A);\n                long long g = gain_add(st.board.data(), actions[id]);\n                if (g > bestg) {\n                    bestg = g;\n                    bestid = id;\n                }\n            }\n            nid = bestid;\n\n            if (mode >= 85) { // occasional random candidate\n                int rid = rng.next_int(A);\n                long long rg = gain_add(st.board.data(), actions[rid]);\n                if (rg > bestg - (long long)MOD / 8) nid = rid;\n            }\n        }\n\n        if (nid != dummy_id) apply_add(st, actions[nid]);\n        st.ops[pos] = nid;\n\n        long long delta = st.score - oldScore;\n        bool accept = false;\n        if (delta >= 0) accept = true;\n        else {\n            double prob = exp((double)delta / T);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (!accept) {\n            if (nid != dummy_id) apply_remove(st, actions[nid]);\n            if (old != dummy_id) apply_add(st, actions[old]);\n            st.ops[pos] = old;\n        }\n    }\n}\n\nvoid insert_elite(vector<State>& elite, const State& cand, int cap) {\n    for (const auto& e : elite) {\n        if (cand.score == e.score && cand.ops == e.ops) return;\n    }\n    elite.push_back(cand);\n    sort(elite.begin(), elite.end(), [](const State& a, const State& b) {\n        return a.score > b.score;\n    });\n    if ((int)elite.size() > cap) elite.resize(cap);\n}\n\nint pick_elite_index(const vector<State>& elite, XorShift64& rng) {\n    int sz = (int)elite.size();\n    if (sz == 1) return 0;\n    int r = rng.next_int(100);\n    if (r < 55) return 0;\n    if (r < 82) return rng.next_int(min(sz, 3));\n    if (r < 94) return rng.next_int(min(sz, 5));\n    return rng.next_int(sz);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin, M, Kin;\n    cin >> Nin >> M >> Kin;\n\n    array<uint32_t, CELLS> base{};\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(Nin); mix(M); mix(Kin);\n\n    for (int i = 0; i < Nin; i++) {\n        for (int j = 0; j < Nin; j++) {\n            uint32_t v;\n            cin >> v;\n            base[i * N + j] = v;\n            mix(v);\n        }\n    }\n\n    vector<array<array<uint32_t, 3>, 3>> stamp(M);\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                uint32_t v;\n                cin >> v;\n                stamp[m][i][j] = v;\n                mix(v);\n            }\n        }\n    }\n\n    vector<Action> actions;\n    actions.reserve(M * (N - 2) * (N - 2));\n\n    for (int m = 0; m < M; m++) {\n        for (int p = 0; p <= N - 3; p++) {\n            for (int q = 0; q <= N - 3; q++) {\n                Action ac;\n                ac.m = m;\n                ac.p = p;\n                ac.q = q;\n                ac.raw = 0;\n\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        uint32_t v = stamp[m][i][j];\n                        ac.val[t] = v;\n                        ac.thr[t] = MOD - v;\n                        ac.cell[t] = (uint8_t)((p + i) * N + (q + j));\n                        ac.raw += v;\n                        t++;\n                    }\n                }\n                actions.push_back(ac);\n            }\n        }\n    }\n\n    const int dummy_id = (int)actions.size(); // 980\n    XorShift64 rng(seed);\n    Timer timer;\n    const double TL = 1.90;\n    const double MAIN_END = TL * 0.90;\n\n    // Initial solution\n    State best = construct_best_greedy(base, actions, dummy_id);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 45);\n    pair_local_search(best, actions, dummy_id, rng, 14, 6, true, false, timer, TL);\n    local_opt(best, actions, dummy_id, timer, TL, rng, 16);\n\n    const int ELITE_CAP = 8;\n    vector<State> elite;\n    elite.reserve(ELITE_CAP + 4);\n    insert_elite(elite, best, ELITE_CAP);\n\n    // Multi-start initialization\n    while (timer.elapsed() < TL * 0.24) {\n        int topR = 3 + rng.next_int(5); // 3..7\n        State cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 22);\n\n        if (rng.next_int(100) < 65 && timer.elapsed() < TL * 0.23) {\n            int R = 6 + rng.next_int(5); // 6..10\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.70, true);\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, 4 + rng.next_int(2), false);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 8);\n        }\n\n        if (rng.next_int(100) < 50) {\n            pair_local_search(cand, actions, dummy_id, rng, 8, 6, true, false, timer, TL);\n            local_opt(cand, actions, dummy_id, timer, TL, rng, 6);\n        }\n\n        if (cand.score > best.score) best = cand;\n        insert_elite(elite, cand, ELITE_CAP);\n    }\n\n    int stagnation = 0;\n\n    // Main search loop\n    while (timer.elapsed() < MAIN_END) {\n        int ei = pick_elite_index(elite, rng);\n        State cand = elite[ei];\n\n        int mode = rng.next_int(100);\n\n        if (mode < 46) {\n            int R = (stagnation < 20) ? (5 + rng.next_int(5)) : (8 + rng.next_int(6));\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.78, true);\n            bool allow_neg = (stagnation > 35 && rng.next_int(100) < 35);\n            int topR = 4 + rng.next_int(3); // 4..6\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, topR, allow_neg);\n        } else if (mode < 67) {\n            int cnt = 2 + rng.next_int((stagnation < 25) ? 10 : 20);\n            random_perturb(cand, actions, dummy_id, rng, cnt);\n        } else if (mode < 84) {\n            int steps = (stagnation < 25) ? 60 : 110;\n            int sample_n = (stagnation < 25) ? 22 : 30;\n            double T0 = (stagnation < 25) ? 3.0e8 : 5.0e8;\n            anneal_kick(cand, actions, dummy_id, rng, steps, sample_n, T0, 3.0e6, timer, MAIN_END);\n        } else {\n            int topR = 3 + rng.next_int(5);\n            cand = construct_random_greedy(base, actions, dummy_id, rng, topR);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, MAIN_END, rng, 9 + (stagnation > 30 ? 5 : 0));\n\n        if (rng.next_int(100) < 42) {\n            bool allow_neg_pair = (stagnation > 40 && rng.next_int(100) < 40);\n            pair_local_search(cand, actions, dummy_id, rng,\n                              6 + (stagnation > 25 ? 4 : 0),\n                              6, true, allow_neg_pair, timer, MAIN_END);\n            local_opt(cand, actions, dummy_id, timer, MAIN_END, rng, 4);\n        }\n\n        if (cand.score > best.score) {\n            best = cand;\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n        insert_elite(elite, cand, ELITE_CAP);\n\n        if (stagnation > 70 && timer.elapsed() < MAIN_END * 0.98) {\n            State kick = best;\n            auto pos = select_positions(kick, actions, dummy_id, rng, 12, 0.82, true);\n            destroy_repair_guided(kick, actions, dummy_id, pos, rng, 6, true);\n            local_opt(kick, actions, dummy_id, timer, MAIN_END, rng, 14);\n\n            if (kick.score > best.score) {\n                best = kick;\n                stagnation = 0;\n                insert_elite(elite, best, ELITE_CAP);\n            } else {\n                stagnation = 30;\n            }\n        }\n    }\n\n    // Final intensification\n    while (timer.elapsed() < TL) {\n        State cand = best;\n        int mode = rng.next_int(100);\n\n        if (mode < 68) {\n            int R = 7 + rng.next_int(5); // 7..11\n            auto pos = select_positions(cand, actions, dummy_id, rng, R, 0.85, true);\n            destroy_repair_guided(cand, actions, dummy_id, pos, rng, 6, true);\n        } else {\n            anneal_kick(cand, actions, dummy_id, rng, 90, 28, 2.5e8, 2.0e6, timer, TL);\n        }\n\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 12);\n        pair_local_search(cand, actions, dummy_id, rng, 10, 6, true, true, timer, TL);\n        local_opt(cand, actions, dummy_id, timer, TL, rng, 8);\n\n        if (cand.score > best.score) {\n            best = cand;\n            insert_elite(elite, best, ELITE_CAP);\n        }\n\n        if (timer.elapsed() > TL - 0.018) break;\n    }\n\n    vector<tuple<int, int, int>> ans;\n    ans.reserve(K);\n    for (int i = 0; i < K; i++) {\n        int id = best.ops[i];\n        if (id == dummy_id) continue;\n        const auto& ac = actions[id];\n        ans.emplace_back(ac.m, ac.p, ac.q);\n    }\n\n    cout << ans.size() << '\\n';\n    for (auto [m, p, q] : ans) {\n        cout << m << ' ' << p << ' ' << q << '\\n';\n    }\n\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\nusing Clock = chrono::steady_clock;\n\nstatic inline uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\n/* ===================== Greedy strict baseline ===================== */\n\nstruct GreedySolver {\n    int N;\n    const vector<vector<int>>& A;\n    int revealDepthW;\n\n    vector<int> nextIn;\n    vector<vector<int>> grid; // -1 or container id\n    int pr = 0, pc = 0;\n    int hold = -1;\n\n    vector<int> srcRow, srcIdx;\n    vector<char> dispatched;\n    vector<int> need; // next required in each dispatch row\n    int dispatchedCnt = 0;\n\n    int turn = 0;\n    string acts;\n\n    GreedySolver(int n, const vector<vector<int>>& a, int rw)\n        : N(n), A(a), revealDepthW(rw) {\n        nextIn.assign(N, 0);\n        grid.assign(N, vector<int>(N, -1));\n        srcRow.assign(N * N, -1);\n        srcIdx.assign(N * N, -1);\n        dispatched.assign(N * N, 0);\n        need.resize(N);\n        for (int r = 0; r < N; r++) need[r] = r * N;\n\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n    }\n\n    inline int md(int r1, int c1, int r2, int c2) const {\n        return abs(r1 - r2) + abs(c1 - c2);\n    }\n\n    inline bool is_ready(int v) const {\n        int dr = v / N;\n        int hi = dr * N + (N - 1);\n        return (need[dr] <= hi && v == need[dr]);\n    }\n\n    void spawn_step() {\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] >= N) continue;\n            if (grid[r][0] != -1) continue;\n            // spawn blocked only if crane is holding at gate\n            if (pr == r && pc == 0 && hold != -1) continue;\n            grid[r][0] = A[r][nextIn[r]];\n            nextIn[r]++;\n        }\n    }\n\n    void dispatch_step() {\n        int dc = N - 1;\n        for (int r = 0; r < N; r++) {\n            if (grid[r][dc] == -1) continue;\n            int v = grid[r][dc];\n            grid[r][dc] = -1;\n\n            if (!dispatched[v]) {\n                dispatched[v] = 1;\n                dispatchedCnt++;\n            }\n\n            int dr = v / N;\n            int hi = dr * N + (N - 1);\n            while (need[dr] <= hi && dispatched[need[dr]]) need[dr]++;\n        }\n    }\n\n    // one full turn: spawn -> action -> dispatch\n    void apply(char act) {\n        if (turn >= 10000) return;\n\n        spawn_step();\n\n        char real = act;\n        if (act == 'P') {\n            if (!(hold == -1 && grid[pr][pc] != -1)) real = '.';\n        } else if (act == 'Q') {\n            if (!(hold != -1 && grid[pr][pc] == -1)) real = '.';\n        } else if (act == 'U') {\n            if (pr == 0) real = '.';\n        } else if (act == 'D') {\n            if (pr == N - 1) real = '.';\n        } else if (act == 'L') {\n            if (pc == 0) real = '.';\n        } else if (act == 'R') {\n            if (pc == N - 1) real = '.';\n        } else if (act != '.') {\n            real = '.';\n        }\n\n        switch (real) {\n            case 'P':\n                hold = grid[pr][pc];\n                grid[pr][pc] = -1;\n                break;\n            case 'Q':\n                grid[pr][pc] = hold;\n                hold = -1;\n                break;\n            case 'U': pr--; break;\n            case 'D': pr++; break;\n            case 'L': pc--; break;\n            case 'R': pc++; break;\n            case '.': break;\n        }\n\n        dispatch_step();\n        acts.push_back(real);\n        turn++;\n    }\n\n    bool find_container(int v, int& rr, int& cc) const {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == v) {\n                    rr = r; cc = c;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    bool has_ready_container(int& bestV, int& bestR, int& bestC) const {\n        int bestScore = INT_MAX;\n        bestV = -1; bestR = -1; bestC = -1;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (!find_container(x, r, c)) continue;\n\n            int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestV = x; bestR = r; bestC = c;\n            }\n        }\n        return bestV != -1;\n    }\n\n    int choose_reveal_row() const {\n        int bestRow = -1;\n        int bestScore = INT_MAX;\n\n        for (int dr = 0; dr < N; dr++) {\n            int lo = dr * N, hi = lo + (N - 1);\n            if (need[dr] > hi) continue;\n\n            int x = need[dr];\n            int r, c;\n            if (find_container(x, r, c)) continue; // already on board\n\n            int s = srcRow[x];\n            int frontIdx = (grid[s][0] != -1 ? nextIn[s] - 1 : nextIn[s]);\n            int depth = srcIdx[x] - frontIdx;\n            if (depth < 0) depth = 0;\n\n            int sc = depth * revealDepthW + md(pr, pc, s, 0);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestRow = dr;\n            }\n        }\n        return bestRow;\n    }\n\n    pair<int,int> choose_storage_cell() const {\n        int bestR = -1, bestC = -1;\n        int bestScore = INT_MAX;\n        int dr = (hold == -1 ? 0 : hold / N);\n\n        // prefer internal columns\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= N - 2; c++) {\n                if (grid[r][c] != -1) continue;\n                int sc = md(pr, pc, r, c) + md(r, c, dr, N - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestR = r; bestC = c;\n                }\n            }\n        }\n\n        // then exhausted receiving gates\n        for (int r = 0; r < N; r++) {\n            if (nextIn[r] != N) continue;\n            if (grid[r][0] != -1) continue;\n            int sc = md(pr, pc, r, 0) + md(r, 0, dr, N - 1);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestR = r; bestC = 0;\n            }\n        }\n\n        // fallback: any free receiving gate (active) with penalty\n        for (int r = 0; r < N; r++) {\n            if (grid[r][0] != -1) continue;\n            int pen = (nextIn[r] < N ? 35 : 0);\n            int sc = md(pr, pc, r, 0) + md(r, 0, dr, N - 1) + pen;\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestR = r; bestC = 0;\n            }\n        }\n\n        return {bestR, bestC};\n    }\n\n    pair<int,int> nearest_container() const {\n        int bestR = -1, bestC = -1, best = INT_MAX;\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                if (grid[r][c] == -1) continue;\n                int d = md(pr, pc, r, c);\n                if (d < best) {\n                    best = d;\n                    bestR = r; bestC = c;\n                }\n            }\n        }\n        return {bestR, bestC};\n    }\n\n    void move_to(int tr, int tc) {\n        while (turn < 10000 && (pr != tr || pc != tc)) {\n            if (pc < tc) apply('R');\n            else if (pc > tc) apply('L');\n            else if (pr < tr) apply('D');\n            else apply('U');\n        }\n    }\n\n    void dispatch_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        int dr = hold / N;\n        move_to(dr, N - 1);\n        if (turn < 10000) apply('Q');\n    }\n\n    void store_holding() {\n        if (hold == -1 || turn >= 10000) return;\n        auto [sr, sc] = choose_storage_cell();\n        if (sr == -1) {\n            apply('.');\n            return;\n        }\n        move_to(sr, sc);\n        if (turn < 10000) apply('Q');\n    }\n\n    vector<char> solve(bool& complete) {\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n                continue;\n            }\n\n            int v, r, c;\n            if (has_ready_container(v, r, c)) {\n                move_to(r, c);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) {\n                    if (is_ready(hold)) dispatch_holding();\n                    else store_holding();\n                }\n                continue;\n            }\n\n            int rr = choose_reveal_row();\n            if (rr != -1) {\n                int x = need[rr];\n                int s = srcRow[x];\n                move_to(s, 0);\n                if (turn >= 10000) break;\n                apply('P');\n                if (hold != -1) {\n                    if (is_ready(hold)) dispatch_holding();\n                    else store_holding();\n                }\n                continue;\n            }\n\n            auto [nr, nc] = nearest_container();\n            if (nr == -1) {\n                bool anyQueue = false;\n                for (int i = 0; i < N; i++) if (nextIn[i] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(nr, nc);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n            }\n        }\n\n        if (turn < 10000 && hold != -1) {\n            if (is_ready(hold)) dispatch_holding();\n            else store_holding();\n        }\n\n        // safety cleanup\n        while (turn < 10000 && dispatchedCnt < N * N) {\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n                continue;\n            }\n\n            auto [nr, nc] = nearest_container();\n            if (nr == -1) {\n                bool anyQueue = false;\n                for (int i = 0; i < N; i++) if (nextIn[i] < N) anyQueue = true;\n                if (!anyQueue) break;\n                apply('.');\n                continue;\n            }\n\n            move_to(nr, nc);\n            if (turn >= 10000) break;\n            apply('P');\n            if (hold != -1) {\n                if (is_ready(hold)) dispatch_holding();\n                else store_holding();\n            }\n        }\n\n        complete = (dispatchedCnt == N * N && hold == -1);\n        vector<char> res(acts.begin(), acts.end());\n        if (res.empty()) res.push_back('.');\n        return res;\n    }\n};\n\n/* ===================== Strict simulator + beam ===================== */\n\nstruct BeamSolver {\n    static constexpr int N = 5;\n    vector<vector<int>> A;\n    array<int, 25> srcRow{}, srcIdx{};\n    int dist[25][25]{};\n\n    struct State {\n        array<int8_t, 25> cell;   // -1 empty, 0..24 container\n        array<int8_t, 25> loc;    // -3 dispatched, -2 hold, -1 not yet on board, 0..24 on board\n        array<uint8_t, 5> nextIn; // 0..5\n        array<uint8_t, 5> need;   // current required by dispatch row\n        int8_t hold;              // -1 or 0..24\n        uint8_t pos;              // 0..24\n    };\n\n    struct Trace {\n        int parent;\n        char act;\n    };\n\n    struct BeamItem {\n        State st;\n        int trace;\n        int eval;\n    };\n\n    struct Cand {\n        State st;\n        int parentTrace;\n        char act;\n        int eval;\n        uint64_t h;\n    };\n\n    BeamSolver(const vector<vector<int>>& a) : A(a) {\n        srcRow.fill(-1);\n        srcIdx.fill(-1);\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int v = A[r][j];\n                srcRow[v] = r;\n                srcIdx[v] = j;\n            }\n        }\n        for (int i = 0; i < 25; i++) {\n            for (int j = 0; j < 25; j++) {\n                dist[i][j] = abs(i / N - j / N) + abs(i % N - j % N);\n            }\n        }\n    }\n\n    State initial_state() const {\n        State s;\n        s.cell.fill(-1);\n        s.loc.fill(-1);\n        s.nextIn.fill(0);\n        for (int r = 0; r < N; r++) s.need[r] = (uint8_t)(r * N);\n        s.hold = -1;\n        s.pos = 0;\n        return s;\n    }\n\n    inline int dispatched_count(const State& s) const {\n        int d = 0;\n        for (int r = 0; r < N; r++) d += (int)s.need[r] - r * N;\n        return d;\n    }\n\n    inline bool is_goal(const State& s) const {\n        return dispatched_count(s) == 25 && s.hold == -1;\n    }\n\n    void spawn(State& s) const {\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] != -1) continue;\n            if (s.pos == g && s.hold != -1) continue;\n            int v = A[r][s.nextIn[r]];\n            s.nextIn[r]++;\n            s.cell[g] = (int8_t)v;\n            s.loc[v] = (int8_t)g;\n        }\n    }\n\n    // sp: already after spawn\n    bool apply_action_dispatch(const State& sp, char act, State& ns) const {\n        ns = sp;\n        int p = ns.pos;\n        int r = p / N, c = p % N;\n\n        switch (act) {\n            case '.':\n                break;\n            case 'P': {\n                if (ns.hold != -1) return false;\n                int v = ns.cell[p];\n                if (v < 0) return false;\n                ns.hold = (int8_t)v;\n                ns.cell[p] = -1;\n                ns.loc[v] = -2;\n                break;\n            }\n            case 'Q': {\n                if (ns.hold == -1) return false;\n                if (ns.cell[p] != -1) return false;\n                if (c == N - 1) {\n                    // strict in-order dispatch only\n                    if (ns.hold != (int8_t)ns.need[r]) return false;\n                }\n                int v = ns.hold;\n                ns.hold = -1;\n                ns.cell[p] = (int8_t)v;\n                ns.loc[v] = (int8_t)p;\n                break;\n            }\n            case 'U':\n                if (r == 0) return false;\n                ns.pos = (uint8_t)(p - N);\n                break;\n            case 'D':\n                if (r == N - 1) return false;\n                ns.pos = (uint8_t)(p + N);\n                break;\n            case 'L':\n                if (c == 0) return false;\n                ns.pos = (uint8_t)(p - 1);\n                break;\n            case 'R':\n                if (c == N - 1) return false;\n                ns.pos = (uint8_t)(p + 1);\n                break;\n            default:\n                return false;\n        }\n\n        // strict dispatch\n        for (int rr = 0; rr < N; rr++) {\n            int idx = rr * N + (N - 1);\n            int v = ns.cell[idx];\n            if (v == -1) continue;\n            if (v != ns.need[rr]) return false;\n            ns.need[rr]++;\n            ns.cell[idx] = -1;\n            ns.loc[v] = -3;\n        }\n\n        return true;\n    }\n\n    int lower_bound(const State& s) const {\n        int lb = 0;\n        int pos = s.pos;\n\n        for (int v = 0; v < 25; v++) {\n            int dr = v / N;\n            if (v < (int)s.need[dr]) continue;\n\n            int gate = dr * N + (N - 1);\n            if (s.hold == v) {\n                lb += dist[pos][gate] + 1; // carry + drop\n                continue;\n            }\n\n            int lp = s.loc[v];\n            if (lp >= 0) {\n                lb += dist[lp][gate] + 2; // pick + carry + drop\n            } else if (lp == -1) {\n                int sr = srcRow[v];\n                lb += (abs(sr - dr) + (N - 1)) + 2;\n            } else if (lp == -2) {\n                lb += dist[pos][gate] + 1;\n            }\n        }\n        return lb;\n    }\n\n    int eval_state(const State& s, int lb, int mode, uint64_t seed, uint64_t h) const {\n        int disp = dispatched_count(s);\n        int ready = 0;\n        for (int r = 0; r < N; r++) {\n            int x = s.need[r];\n            if (x >= r * N + N) continue;\n            if (s.hold == x || s.loc[x] >= 0) ready++;\n        }\n\n        int e = disp * 100000 - lb * 450 + ready * 2500;\n        if (mode == 1) e += ready * 700;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            if (v == s.need[dr]) {\n                e += 6000 - dist[s.pos][dr * N + (N - 1)] * 180;\n            } else {\n                e -= 1200;\n            }\n        }\n\n        for (int r = 0; r < N; r++) {\n            int g = r * N;\n            if (s.nextIn[r] >= N) continue;\n            if (s.cell[g] == -1) continue;\n            if (s.nextIn[r] == 0) continue;\n            int expected = A[r][s.nextIn[r] - 1];\n            if ((int)s.cell[g] != expected) e -= 5000;\n        }\n\n        if (seed != 0) {\n            int noise = (int)(splitmix64(h ^ seed) & 127ULL) - 63;\n            e += noise;\n        }\n\n        return e;\n    }\n\n    uint64_t hash_state(const State& s) const {\n        uint64_t h = 1469598103934665603ULL;\n        auto add = [&](uint8_t x) {\n            h ^= x;\n            h *= 1099511628211ULL;\n        };\n\n        add((uint8_t)s.pos);\n        add((uint8_t)(s.hold + 1));\n        for (int r = 0; r < N; r++) {\n            add(s.nextIn[r]);\n            add((uint8_t)((int)s.need[r] - r * N));\n        }\n        for (int i = 0; i < 25; i++) {\n            add((uint8_t)(s.cell[i] + 1));\n        }\n        return h;\n    }\n\n    void gen_actions(const State& s, array<char, 12>& acts, int& acnt, int mode) const {\n        acnt = 0;\n        bool used[256] = {};\n        auto add = [&](char ch) {\n            unsigned u = (unsigned char)ch;\n            if (!used[u]) {\n                used[u] = true;\n                acts[acnt++] = ch;\n            }\n        };\n        auto add_toward = [&](int target) {\n            int p = s.pos;\n            int r = p / N, c = p % N;\n            int tr = target / N, tc = target % N;\n            if (r < tr) add('D');\n            if (r > tr) add('U');\n            if (c < tc) add('R');\n            if (c > tc) add('L');\n        };\n\n        int kReady = (mode == 1 ? 4 : 3);\n        int kReveal = (mode == 1 ? 3 : 2);\n        int kStore = (mode == 1 ? 3 : 2);\n\n        int pos = s.pos;\n        int r = pos / N, c = pos % N;\n\n        if (s.hold != -1) {\n            int v = s.hold;\n            int dr = v / N;\n            int gate = dr * N + (N - 1);\n\n            if (v == s.need[dr]) {\n                if (pos == gate && s.cell[pos] == -1) add('Q');\n                add_toward(gate);\n            } else {\n                if (s.cell[pos] == -1 && c != N - 1) add('Q');\n\n                pair<int,int> cand[25];\n                int m = 0;\n                for (int idx = 0; idx < 25; idx++) {\n                    int rr = idx / N, cc = idx % N;\n                    if (cc == N - 1) continue;\n                    if (s.cell[idx] != -1) continue;\n                    int pen = (cc == 0 && s.nextIn[rr] < N) ? 30 : 0;\n                    int sc = dist[pos][idx] + dist[idx][gate] + pen;\n                    cand[m++] = {sc, idx};\n                }\n                sort(cand, cand + m);\n                for (int i = 0; i < min(kStore, m); i++) add_toward(cand[i].second);\n            }\n        } else {\n            if (s.cell[pos] != -1) add('P');\n\n            pair<int,int> ready[5];\n            int rcnt = 0;\n            for (int rr = 0; rr < N; rr++) {\n                int x = s.need[rr];\n                if (x >= rr * N + N) continue;\n                int lp = s.loc[x];\n                if (lp >= 0) {\n                    int sc = dist[pos][lp] + dist[lp][rr * N + (N - 1)];\n                    ready[rcnt++] = {sc, lp};\n                }\n            }\n\n            if (rcnt > 0) {\n                sort(ready, ready + rcnt);\n                for (int i = 0; i < min(kReady, rcnt); i++) add_toward(ready[i].second);\n            } else {\n                pair<int,int> rev[5];\n                int vcnt = 0;\n                for (int rr = 0; rr < N; rr++) {\n                    int x = s.need[rr];\n                    if (x >= rr * N + N) continue;\n                    int sr = srcRow[x];\n                    int front = (int)s.nextIn[sr] - (s.cell[sr * N] == -1 ? 0 : 1);\n                    int depth = srcIdx[x] - front;\n                    if (depth < 0) depth = 0;\n                    int gp = sr * N;\n                    int sc = depth * 10 + dist[pos][gp];\n                    rev[vcnt++] = {sc, gp};\n                }\n                sort(rev, rev + vcnt);\n                for (int i = 0; i < min(kReveal, vcnt); i++) add_toward(rev[i].second);\n            }\n        }\n\n        if (acnt < 2) {\n            if (r > 0) add('U');\n            if (r < N - 1) add('D');\n            if (c > 0) add('L');\n            if (c < N - 1) add('R');\n        }\n\n        if (acnt == 0) add('.');\n    }\n\n    vector<char> reconstruct(int traceId, const vector<Trace>& traces) const {\n        vector<char> rev;\n        while (traceId > 0) {\n            rev.push_back(traces[traceId].act);\n            traceId = traces[traceId].parent;\n        }\n        reverse(rev.begin(), rev.end());\n        return rev;\n    }\n\n    bool validate(const vector<char>& actions) const {\n        State s = initial_state();\n        for (char a : actions) {\n            State sp = s, ns;\n            spawn(sp);\n            if (!apply_action_dispatch(sp, a, ns)) return false;\n            s = ns;\n        }\n        return is_goal(s);\n    }\n\n    // Find improved solution:\n    // - need length < improveLen\n    // - prune with boundLen (can be > improveLen for looser pruning)\n    bool search(int improveLen, int boundLen, int width, int mode, uint64_t seed,\n                const Clock::time_point& deadline, vector<char>& outActions) const {\n        if (improveLen <= 1) return false;\n        boundLen = max(boundLen, improveLen);\n        int maxDepth = min(improveLen - 1, 10000);\n\n        vector<Trace> traces;\n        traces.reserve((size_t)width * 400 + 16);\n        traces.push_back({-1, '?'});\n\n        vector<BeamItem> cur, nxt;\n        cur.reserve(width + 16);\n        nxt.reserve(width + 16);\n\n        State init = initial_state();\n        int lb0 = lower_bound(init);\n        if (lb0 >= boundLen) return false;\n        cur.push_back({init, 0, eval_state(init, lb0, mode, seed, hash_state(init))});\n\n        vector<Cand> cands;\n        cands.reserve((size_t)width * 7 + 128);\n\n        auto over = [&]() -> bool {\n            return Clock::now() >= deadline;\n        };\n\n        for (int depth = 0; depth < maxDepth; depth++) {\n            if (over()) return false;\n            cands.clear();\n\n            int it = 0;\n            for (const auto& bi : cur) {\n                if ((it++ & 127) == 0 && over()) return false;\n\n                State sp = bi.st;\n                spawn(sp);\n\n                array<char, 12> acts{};\n                int acnt = 0;\n                gen_actions(sp, acts, acnt, mode);\n\n                for (int i = 0; i < acnt; i++) {\n                    State ns;\n                    char act = acts[i];\n                    if (!apply_action_dispatch(sp, act, ns)) continue;\n\n                    int nd = depth + 1;\n                    if (is_goal(ns)) {\n                        // nd < improveLen guaranteed by depth loop\n                        int tr = (int)traces.size();\n                        traces.push_back({bi.trace, act});\n                        outActions = reconstruct(tr, traces);\n                        return true;\n                    }\n\n                    int lb = lower_bound(ns);\n                    if (nd + lb >= boundLen) continue;\n\n                    uint64_t h = hash_state(ns);\n                    int ev = eval_state(ns, lb, mode, seed, h);\n                    cands.push_back({ns, bi.trace, act, ev, h});\n                }\n            }\n\n            if (cands.empty()) return false;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                if (a.h != b.h) return a.h < b.h;\n                return a.eval > b.eval;\n            });\n\n            vector<Cand> uniq;\n            uniq.reserve(cands.size());\n            for (size_t i = 0; i < cands.size();) {\n                size_t j = i + 1;\n                Cand best = cands[i];\n                while (j < cands.size() && cands[j].h == cands[i].h) {\n                    if (cands[j].eval > best.eval) best = cands[j];\n                    j++;\n                }\n                uniq.push_back(std::move(best));\n                i = j;\n            }\n\n            if ((int)uniq.size() > width) {\n                nth_element(uniq.begin(), uniq.begin() + width, uniq.end(),\n                            [](const Cand& a, const Cand& b) {\n                                return a.eval > b.eval;\n                            });\n                uniq.resize(width);\n            }\n\n            nxt.clear();\n            nxt.reserve(uniq.size());\n            for (const auto& cd : uniq) {\n                int tr = (int)traces.size();\n                traces.push_back({cd.parentTrace, cd.act});\n                nxt.push_back({cd.st, tr, cd.eval});\n            }\n\n            cur.swap(nxt);\n            if (cur.empty()) return false;\n        }\n\n        return false;\n    }\n};\n\n/* ===================== tiny local compression ===================== */\n\nstatic bool isOppMove(char a, char b) {\n    return (a == 'U' && b == 'D') || (a == 'D' && b == 'U') ||\n           (a == 'L' && b == 'R') || (a == 'R' && b == 'L');\n}\n\nstatic vector<char> compress_actions(vector<char> acts, const BeamSolver& beam,\n                                     const Clock::time_point& deadline) {\n    auto over = [&]() -> bool { return Clock::now() >= deadline; };\n\n    auto try_remove = [&](int l, int k) -> bool {\n        if (l < 0 || l + k > (int)acts.size()) return false;\n        vector<char> t;\n        t.reserve((int)acts.size() - k);\n        t.insert(t.end(), acts.begin(), acts.begin() + l);\n        t.insert(t.end(), acts.begin() + l + k, acts.end());\n        if (beam.validate(t)) {\n            acts.swap(t);\n            return true;\n        }\n        return false;\n    };\n\n    bool changed = true;\n    while (changed && !over()) {\n        changed = false;\n        for (int i = 0; i < (int)acts.size() && !over(); i++) {\n            if (acts[i] != '.') continue;\n            if (try_remove(i, 1)) {\n                changed = true;\n                break;\n            }\n        }\n    }\n\n    changed = true;\n    while (changed && !over()) {\n        changed = false;\n        for (int i = 0; i + 1 < (int)acts.size() && !over(); i++) {\n            if (!isOppMove(acts[i], acts[i + 1])) continue;\n            if (try_remove(i, 2)) {\n                changed = true;\n                break;\n            }\n        }\n    }\n\n    if (acts.empty()) acts.push_back('.');\n    return acts;\n}\n\n/* ===================== main ===================== */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> A(N, vector<int>(N));\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> A[i][j];\n    }\n\n    auto start = Clock::now();\n\n    // Unexpected N fallback (problem states N=5 always)\n    if (N != 5) {\n        GreedySolver g(N, A, 100);\n        bool complete = false;\n        vector<char> acts = g.solve(complete);\n        if (acts.empty()) acts.push_back('.');\n        int T = (int)acts.size();\n        cout << string(acts.begin(), acts.end()) << '\\n';\n        for (int i = 1; i < N; i++) {\n            string s(T, '.');\n            s[0] = 'B';\n            cout << s << '\\n';\n        }\n        return 0;\n    }\n\n    BeamSolver beam(A);\n\n    // Multi-start greedy baseline\n    vector<int> revealWs = {100, 90, 110, 75};\n    const int INF = 1e9;\n\n    vector<char> bestStrictActs;\n    int bestStrictLen = INF;\n\n    vector<char> bestCompleteActs;\n    int bestCompleteLen = INF;\n\n    vector<char> bestAnyActs;\n    int bestAnyLen = INF;\n\n    for (int rw : revealWs) {\n        GreedySolver g(N, A, rw);\n        bool complete = false;\n        vector<char> acts = g.solve(complete);\n        if (acts.empty()) acts.push_back('.');\n        int L = (int)acts.size();\n\n        if (L < bestAnyLen) {\n            bestAnyLen = L;\n            bestAnyActs = acts;\n        }\n\n        if (complete && L < bestCompleteLen) {\n            bestCompleteLen = L;\n            bestCompleteActs = acts;\n        }\n\n        if (complete && beam.validate(acts) && L < bestStrictLen) {\n            bestStrictLen = L;\n            bestStrictActs = acts;\n        }\n    }\n\n    vector<char> bestActs;\n    bool bestStrict = false;\n\n    if (bestStrictLen < INF) {\n        bestActs = bestStrictActs;\n        bestStrict = true;\n    } else if (bestCompleteLen < INF) {\n        bestActs = bestCompleteActs;\n        bestStrict = beam.validate(bestActs);\n    } else {\n        bestActs = bestAnyActs;\n        bestStrict = beam.validate(bestActs);\n    }\n\n    if (bestActs.empty()) bestActs.push_back('.');\n    int bestLen = (int)bestActs.size();\n\n    vector<char> safeFallback = bestActs;\n    if (!beam.validate(safeFallback) && !bestStrictActs.empty()) {\n        safeFallback = bestStrictActs;\n    }\n\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            seed = splitmix64(seed ^ (uint64_t)(A[i][j] + 1) * 0x9e3779b97f4a7c15ULL);\n        }\n    }\n\n    auto hardDeadline = start + chrono::milliseconds(2780);\n\n    // Beam attempt 1 (deterministic)\n    if (bestStrict && Clock::now() + chrono::milliseconds(50) < hardDeadline) {\n        vector<char> cand;\n        int width1 = (bestLen <= 305 ? 2600 : 2300);\n        auto d1 = min(hardDeadline, start + chrono::milliseconds(2150));\n\n        bool ok = beam.search(\n            bestLen,                      // must beat this\n            min(10000, bestLen + 8),     // looser prune bound\n            width1,\n            0,                           // mode\n            0ULL,                        // deterministic\n            d1,\n            cand\n        );\n\n        if (ok && !cand.empty() && (int)cand.size() < bestLen && beam.validate(cand)) {\n            bestActs = cand;\n            bestLen = (int)bestActs.size();\n            bestStrict = true;\n        }\n    }\n\n    // Beam attempt 2 (diversified)\n    if (bestStrict && Clock::now() + chrono::milliseconds(40) < hardDeadline) {\n        vector<char> cand;\n        int width2 = (bestLen <= 305 ? 2000 : 1700);\n\n        bool ok = beam.search(\n            bestLen,\n            min(10000, bestLen + 10),\n            width2,\n            1,        // slightly different mode\n            seed,     // tiny randomized tie-break in eval\n            hardDeadline,\n            cand\n        );\n\n        if (ok && !cand.empty() && (int)cand.size() < bestLen && beam.validate(cand)) {\n            bestActs = cand;\n            bestLen = (int)bestActs.size();\n            bestStrict = true;\n        }\n    }\n\n    // Tiny post-compression\n    if (bestStrict && Clock::now() + chrono::milliseconds(20) < hardDeadline) {\n        vector<char> cmp = compress_actions(bestActs, beam, hardDeadline);\n        if (!cmp.empty() && (int)cmp.size() <= bestLen && beam.validate(cmp)) {\n            bestActs = cmp;\n            bestLen = (int)bestActs.size();\n        }\n    }\n\n    // Final safety\n    if (!beam.validate(bestActs)) {\n        bestActs = safeFallback;\n        if (bestActs.empty()) bestActs.push_back('.');\n    }\n\n    int T = (int)bestActs.size();\n    if (T <= 0) {\n        bestActs = {'.'};\n        T = 1;\n    }\n\n    cout << string(bestActs.begin(), bestActs.end()) << '\\n';\n    for (int i = 1; i < N; i++) {\n        string s(T, '.');\n        s[0] = 'B';\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct SimResult {\n    long long cost = (1LL << 62);\n    int turns = 0;\n    bool valid = false;\n    vector<string> ops;\n};\n\nclass Solver {\n    static constexpr int MAX_N = 20;\n    static constexpr int MAX_M = 400;\n    static constexpr int MAX_TURNS = 100000;\n    static constexpr long long INF64 = (1LL << 62);\n    static constexpr int INF_CAP = 1000000000;\n    inline static const array<int, 11> CAPS = {\n        160, 220, 300, 400, 550, 750, 1000, 1400, 2000, 3000, INF_CAP\n    };\n\n    int N = 0, M = 0;\n    int init_h[MAX_M]{};\n    int rr[MAX_M]{}, cc[MAX_M]{};\n    uint8_t distm[MAX_M][MAX_M]{};\n\n    int init_near_pos[MAX_M]{};\n    int init_near_neg[MAX_M]{};\n    long long total_positive = 0;\n\n    uint64_t input_hash = 0;\n\n    vector<vector<int>> cycles;\n    vector<vector<int>> paths;\n\n    struct GParam {\n        int cap = 800;\n        int mode = 0;               // 0: strict, 1: mixed, 2: trip-aware\n        int dist_scale = 256;\n        int link_scale = 80;        // mainly mode=2\n        int src_bias = 2;\n        int dst_bias = 2;\n        bool collect_when_loaded = false;\n        int force_sink_ratio = 70;\n        int src_loaded_pen = 1;\n        int sink_empty_pen = 1;\n        int axis_pref = 2;          // 0 vertical, 1 horizontal, 2 adaptive\n        int path_unload_bonus = 130;\n        int path_load_bonus = 70;\n        int back_penalty = 40;\n        bool retarget_on_change = true;\n    };\n\n    enum class BestType { NONE, CYCLE, PATH, GREEDY };\n\n    struct CycleSpec {\n        int ci = 0;\n        int dir = 1;\n        int shift = 0;\n    };\n    struct PathSpec {\n        int pi = 0;\n        int cleanup_type = 0;\n    };\n    struct GreedySpec {\n        GParam p{};\n        uint64_t seed = 1;\n    };\n    struct EliteItem {\n        GParam p{};\n        uint64_t seed = 1;\n        long long cost = INF64;\n    };\n\n    static uint64_t xorshift64(uint64_t &x) {\n        if (x == 0) x = 88172645463325252ULL;\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n\n    static int randInt(uint64_t &x, int l, int r) {\n        return l + (int)(xorshift64(x) % (uint64_t)(r - l + 1));\n    }\n\n    int modM(int x) const {\n        x %= M;\n        if (x < 0) x += M;\n        return x;\n    }\n\n    vector<int> buildBaseCycle() const {\n        // Hamiltonian cycle for even N\n        vector<int> cyc;\n        cyc.reserve(M);\n\n        for (int c = 0; c < N; c++) cyc.push_back(c);\n        for (int r = 1; r < N; r++) {\n            if (r & 1) for (int c = N - 1; c >= 1; c--) cyc.push_back(r * N + c);\n            else for (int c = 1; c < N; c++) cyc.push_back(r * N + c);\n        }\n        for (int r = N - 1; r >= 1; r--) cyc.push_back(r * N);\n\n        return cyc;\n    }\n\n    pair<int, int> transformPoint(int r, int c, int t) const {\n        switch (t) {\n            case 0: return {r, c};\n            case 1: return {r, N - 1 - c};\n            case 2: return {N - 1 - r, c};\n            case 3: return {N - 1 - r, N - 1 - c};\n            case 4: return {c, r};\n            case 5: return {c, N - 1 - r};\n            case 6: return {N - 1 - c, r};\n            case 7: return {N - 1 - c, N - 1 - r};\n        }\n        return {r, c};\n    }\n\n    vector<int> transformCycle(const vector<int> &base, int t) const {\n        vector<int> out;\n        out.reserve(M);\n        for (int id : base) {\n            int r = id / N, c = id % N;\n            auto [nr, nc] = transformPoint(r, c, t);\n            out.push_back(nr * N + nc);\n        }\n        auto it = find(out.begin(), out.end(), 0);\n        if (it != out.end()) rotate(out.begin(), it, out.end());\n        return out;\n    }\n\n    vector<int> buildRowSnake() const {\n        vector<int> v;\n        v.reserve(M);\n        for (int r = 0; r < N; r++) {\n            if ((r & 1) == 0) for (int c = 0; c < N; c++) v.push_back(r * N + c);\n            else for (int c = N - 1; c >= 0; c--) v.push_back(r * N + c);\n        }\n        return v;\n    }\n\n    vector<int> buildColSnake() const {\n        vector<int> v;\n        v.reserve(M);\n        for (int c = 0; c < N; c++) {\n            if ((c & 1) == 0) for (int r = 0; r < N; r++) v.push_back(r * N + c);\n            else for (int r = N - 1; r >= 0; r--) v.push_back(r * N + c);\n        }\n        return v;\n    }\n\n    vector<int> buildSpiralCW() const {\n        vector<int> ord;\n        ord.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int c = left; c <= right; c++) ord.push_back(top * N + c);\n            top++;\n            for (int r = top; r <= bottom; r++) ord.push_back(r * N + right);\n            right--;\n            if (top <= bottom) {\n                for (int c = right; c >= left; c--) ord.push_back(bottom * N + c);\n                bottom--;\n            }\n            if (left <= right) {\n                for (int r = bottom; r >= top; r--) ord.push_back(r * N + left);\n                left++;\n            }\n        }\n        return ord;\n    }\n\n    vector<int> buildSpiralCCW() const {\n        vector<int> ord;\n        ord.reserve(M);\n        int top = 0, bottom = N - 1, left = 0, right = N - 1;\n        while (top <= bottom && left <= right) {\n            for (int r = top; r <= bottom; r++) ord.push_back(r * N + left);\n            left++;\n            for (int c = left; c <= right; c++) ord.push_back(bottom * N + c);\n            bottom--;\n            if (left <= right) {\n                for (int r = bottom; r >= top; r--) ord.push_back(r * N + right);\n                right--;\n            }\n            if (top <= bottom) {\n                for (int c = right; c >= left; c--) ord.push_back(top * N + c);\n                top++;\n            }\n        }\n        return ord;\n    }\n\n    bool isValidPath(const vector<int> &ord) const {\n        if ((int)ord.size() != M) return false;\n        if (ord[0] != 0) return false;\n\n        static int seen[MAX_M];\n        for (int i = 0; i < M; i++) seen[i] = 0;\n\n        for (int i = 0; i < M; i++) {\n            int id = ord[i];\n            if (id < 0 || id >= M || seen[id]) return false;\n            seen[id] = 1;\n            if (i > 0 && distm[ord[i - 1]][id] != 1) return false;\n        }\n        return true;\n    }\n\n    void addPathIfValid(const vector<int> &ord) {\n        if (!isValidPath(ord)) return;\n        for (auto &p : paths) if (p == ord) return;\n        paths.push_back(ord);\n    }\n\n    void addPathTransforms(const vector<int> &base) {\n        for (int t = 0; t < 8; t++) {\n            vector<int> p;\n            p.reserve(M);\n            for (int id : base) {\n                int r = id / N, c = id % N;\n                auto [nr, nc] = transformPoint(r, c, t);\n                p.push_back(nr * N + nc);\n            }\n            addPathIfValid(p);\n            reverse(p.begin(), p.end());\n            addPathIfValid(p);\n        }\n    }\n\n    template <bool RECORD>\n    SimResult simulateCycle(const vector<int> &cyc, int dir, int shift, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0, idx = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(30000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        // initial shift\n        for (int t = 0; t < shift; t++) {\n            idx = modM(idx + dir);\n            if (!doMove(cyc[idx])) return fail();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n        }\n\n        // one-pass processing\n        for (int t = 0; t < M; t++) {\n            int cell = cyc[idx];\n            if (h[cell] > 0) {\n                doLoad(h[cell]);\n                h[cell] = 0;\n            } else if (h[cell] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[cell]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                idx = modM(idx + dir);\n                if (!doMove(cyc[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // cleanup remaining deficits if load > 0\n        while (load > 0) {\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (load == 0) break;\n\n            int best = -1, bestDist = INT_MAX, bestDef = -1;\n            for (int id = 0; id < M; id++) if (h[id] < 0) {\n                int d = distm[pos][id];\n                int def = -h[id];\n                if (d < bestDist || (d == bestDist && def > bestDef)) {\n                    bestDist = d;\n                    bestDef = def;\n                    best = id;\n                }\n            }\n            if (best < 0) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (nxt < 0) return fail();\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!doMove(nxt)) return fail();\n\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (turns <= MAX_TURNS && load == 0 && posRemain == 0 && negRemain == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    template <bool RECORD>\n    SimResult simulatePath(const vector<int> &ord, int cleanup_type, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(35000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        for (int t = 0; t < M; t++) {\n            int cell = ord[t];\n            if (cell != pos) return fail();\n\n            if (h[cell] > 0) {\n                doLoad(h[cell]);\n                h[cell] = 0;\n            } else if (h[cell] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[cell]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[cell] += d;\n                }\n            }\n\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n\n            if (t + 1 < M) {\n                if (!doMove(ord[t + 1])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        // optional reverse backtrack before nearest cleanup\n        if (cleanup_type == 1) {\n            int idx = M - 1;\n            while (load > 0 && idx > 0) {\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n                if (load == 0) break;\n\n                idx--;\n                if (!doMove(ord[idx])) return fail();\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        while (load > 0) {\n            if (h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (load == 0) break;\n\n            int best = -1, bestDist = INT_MAX, bestDef = -1;\n            for (int id = 0; id < M; id++) if (h[id] < 0) {\n                int d = distm[pos][id];\n                int def = -h[id];\n                if (d < bestDist || (d == bestDist && def > bestDef)) {\n                    bestDist = d;\n                    bestDef = def;\n                    best = id;\n                }\n            }\n            if (best < 0) return fail();\n\n            while (pos != best && load > 0) {\n                int r = rr[pos], c = cc[pos];\n                int br = rr[best], bc = cc[best];\n\n                int cand1 = -1, cand2 = -1;\n                if (r < br) cand1 = pos + N;\n                else if (r > br) cand1 = pos - N;\n\n                if (c < bc) {\n                    if (cand1 == -1) cand1 = pos + 1;\n                    else cand2 = pos + 1;\n                } else if (c > bc) {\n                    if (cand1 == -1) cand1 = pos - 1;\n                    else cand2 = pos - 1;\n                }\n\n                int nxt = cand1;\n                if (nxt < 0) return fail();\n                if (cand2 != -1) {\n                    int d1 = (h[cand1] < 0 ? -h[cand1] : 0);\n                    int d2 = (h[cand2] < 0 ? -h[cand2] : 0);\n                    if (d2 > d1) nxt = cand2;\n                }\n\n                if (!doMove(nxt)) return fail();\n\n                if (h[pos] < 0) {\n                    int d = (int)min<long long>(load, -1LL * h[pos]);\n                    if (d > 0) {\n                        doUnload(d);\n                        h[pos] += d;\n                    }\n                }\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            }\n        }\n\n        bool valid = (turns <= MAX_TURNS && load == 0 && posRemain == 0 && negRemain == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    template <bool RECORD>\n    SimResult simulateGreedy(const GParam &p, uint64_t seed, long long cutoff) const {\n        int h[MAX_M];\n        memcpy(h, init_h, sizeof(int) * M);\n\n        long long posRemain = 0, negRemain = 0;\n        for (int i = 0; i < M; i++) {\n            if (h[i] > 0) posRemain += h[i];\n            else negRemain += -1LL * h[i];\n        }\n\n        long long cost = 0, load = 0;\n        int turns = 0, pos = 0, prevPos = -1;\n        vector<string> ops;\n        if constexpr (RECORD) ops.reserve(100000);\n\n        auto fail = [&]() -> SimResult {\n            SimResult r;\n            r.cost = INF64;\n            r.turns = turns;\n            r.valid = false;\n            return r;\n        };\n\n        auto doLoad = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load += d;\n            posRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"+\" + to_string(d));\n        };\n\n        auto doUnload = [&](int d) {\n            if (d <= 0) return;\n            cost += d;\n            load -= d;\n            negRemain -= d;\n            turns++;\n            if constexpr (RECORD) ops.push_back(\"-\" + to_string(d));\n        };\n\n        auto doMove = [&](int nxt) -> bool {\n            int r1 = rr[pos], c1 = cc[pos];\n            int r2 = rr[nxt], c2 = cc[nxt];\n            char ch = '?';\n            if (r2 == r1 - 1 && c2 == c1) ch = 'U';\n            else if (r2 == r1 + 1 && c2 == c1) ch = 'D';\n            else if (r2 == r1 && c2 == c1 - 1) ch = 'L';\n            else if (r2 == r1 && c2 == c1 + 1) ch = 'R';\n            else return false;\n\n            cost += 100 + load;\n            pos = nxt;\n            turns++;\n            if constexpr (RECORD) ops.emplace_back(1, ch);\n            return true;\n        };\n\n        auto canLoadPolicy = [&](long long curLoad) -> bool {\n            if (curLoad >= p.cap) return false;\n            if (curLoad == 0) return true;\n            return p.collect_when_loaded;\n        };\n\n        auto processHere = [&]() {\n            if (load > 0 && h[pos] < 0) {\n                int d = (int)min<long long>(load, -1LL * h[pos]);\n                if (d > 0) {\n                    doUnload(d);\n                    h[pos] += d;\n                }\n            }\n            if (h[pos] > 0 && canLoadPolicy(load)) {\n                long long room = (long long)p.cap - load;\n                if (room > 0) {\n                    int d = (int)min<long long>(room, (long long)h[pos]);\n                    if (d > 0) {\n                        doLoad(d);\n                        h[pos] -= d;\n                    }\n                }\n            }\n        };\n\n        struct TargetInfo {\n            int id = -1;\n            long long val = INF64;\n            int gain = -1;\n        };\n\n        auto bestSource = [&](int from, long long curLoad) -> TargetInfo {\n            TargetInfo best;\n            if (!canLoadPolicy(curLoad)) return best;\n            long long room = (long long)p.cap - curLoad;\n            if (room <= 0) return best;\n\n            for (int id = 0; id < M; id++) {\n                int amt = h[id];\n                if (amt <= 0) continue;\n\n                int gain = (int)min<long long>((long long)amt, room);\n                int d = distm[from][id];\n\n                long long val = 1LL * p.dist_scale * d - 1LL * p.src_bias * gain;\n                if (p.mode == 2) val += 1LL * p.link_scale * init_near_neg[id];\n\n                if (val < best.val ||\n                    (val == best.val && gain > best.gain) ||\n                    (val == best.val && gain == best.gain && (xorshift64(seed) & 1ULL))) {\n                    best.id = id;\n                    best.val = val;\n                    best.gain = gain;\n                }\n            }\n            return best;\n        };\n\n        auto bestSink = [&](int from, long long curLoad) -> TargetInfo {\n            TargetInfo best;\n            if (curLoad <= 0) return best;\n\n            for (int id = 0; id < M; id++) {\n                int amt = -h[id];\n                if (amt <= 0) continue;\n\n                int gain = (int)min<long long>((long long)amt, curLoad);\n                int d = distm[from][id];\n\n                long long val = 1LL * p.dist_scale * d - 1LL * p.dst_bias * gain;\n                if (p.mode == 2) val += 1LL * p.link_scale * init_near_pos[id];\n\n                if (val < best.val ||\n                    (val == best.val && gain > best.gain) ||\n                    (val == best.val && gain == best.gain && (xorshift64(seed) & 1ULL))) {\n                    best.id = id;\n                    best.val = val;\n                    best.gain = gain;\n                }\n            }\n            return best;\n        };\n\n        auto chooseNext = [&](int target, int prevCell) -> int {\n            int r = rr[pos], c = cc[pos];\n            int tr = rr[target], tc = cc[target];\n\n            int cand[2];\n            int sz = 0;\n            if (r < tr) cand[sz++] = pos + N;\n            else if (r > tr) cand[sz++] = pos - N;\n            if (c < tc) cand[sz++] = pos + 1;\n            else if (c > tc) cand[sz++] = pos - 1;\n\n            if (sz == 0) return -1;\n            if (sz == 1) return cand[0];\n\n            auto scoreCell = [&](int id) -> long long {\n                long long s = 0;\n                if (load > 0 && h[id] < 0) {\n                    s += 1LL * p.path_unload_bonus * min<long long>(load, -1LL * h[id]);\n                }\n                if (canLoadPolicy(load) && h[id] > 0) {\n                    long long room = (long long)p.cap - load;\n                    if (room > 0) {\n                        s += 1LL * p.path_load_bonus * min<long long>(room, (long long)h[id]);\n                    }\n                }\n                if (id == prevCell) s -= p.back_penalty;\n                return s;\n            };\n\n            long long s0 = scoreCell(cand[0]);\n            long long s1 = scoreCell(cand[1]);\n            if (s1 > s0) return cand[1];\n            if (s1 < s0) return cand[0];\n\n            bool v0 = (rr[cand[0]] != r);\n            bool v1 = (rr[cand[1]] != r);\n\n            if (p.axis_pref == 0) {\n                if (v0 != v1) return v0 ? cand[0] : cand[1];\n            } else if (p.axis_pref == 1) {\n                if (v0 != v1) return v0 ? cand[1] : cand[0];\n            } else {\n                int dr = abs(tr - r), dc = abs(tc - c);\n                if (dr != dc && v0 != v1) {\n                    if (dr > dc) return v0 ? cand[0] : cand[1];\n                    else return v0 ? cand[1] : cand[0];\n                }\n            }\n\n            return (xorshift64(seed) & 1ULL) ? cand[0] : cand[1];\n        };\n\n        int stagnation = 0;\n\n        for (int outer = 0; outer < 180000; outer++) {\n            long long beforePos = posRemain;\n            long long beforeNeg = negRemain;\n            long long beforeLoad = load;\n            int beforeCell = pos;\n\n            processHere();\n            if (turns > MAX_TURNS || cost >= cutoff) return fail();\n            if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n            TargetInfo src = bestSource(pos, load);\n            TargetInfo sink = bestSink(pos, load);\n\n            bool seekSource = false;\n            if (p.mode == 0) {\n                seekSource = (load == 0);\n            } else {\n                if (load == 0) {\n                    seekSource = true;\n                } else {\n                    long long refCap = (p.cap >= INF_CAP / 2)\n                        ? min<long long>(max<long long>(400, total_positive / 3), 4000)\n                        : p.cap;\n\n                    if (load * 100 >= 1LL * p.force_sink_ratio * refCap) {\n                        seekSource = false;\n                    } else {\n                        long long srcEval = (src.id == -1 ? INF64 : src.val + 1LL * p.src_loaded_pen * load);\n                        long long sinkEval = (sink.id == -1 ? INF64 : sink.val + 1LL * p.sink_empty_pen * max<long long>(0, refCap - load));\n\n                        if (p.mode == 2) {\n                            sinkEval -= load / 5;\n                            if (load > refCap / 2) srcEval += load / 8;\n                        }\n                        seekSource = (srcEval < sinkEval);\n                    }\n                }\n            }\n\n            if (seekSource && src.id == -1) seekSource = false;\n            if (!seekSource && sink.id == -1) seekSource = true;\n\n            int target = seekSource ? src.id : sink.id;\n            if (target < 0) return fail();\n\n            long long startLoad = load;\n            int guard = 0;\n\n            while (pos != target) {\n                int nxt = chooseNext(target, prevPos);\n                if (nxt < 0) return fail();\n\n                int old = pos;\n                if (!doMove(nxt)) return fail();\n                prevPos = old;\n\n                processHere();\n\n                if (turns > MAX_TURNS || cost >= cutoff) return fail();\n                if (posRemain == 0 && negRemain == 0 && load == 0) break;\n\n                if (seekSource) {\n                    if (load >= p.cap) break;\n                    if (!p.collect_when_loaded && load > 0) break;\n                    if (p.retarget_on_change && load > startLoad) break;\n                } else {\n                    if (load == 0) break;\n                    if (p.retarget_on_change && load < startLoad) break;\n                }\n\n                if (++guard > 3000) break;\n            }\n\n            if (beforePos == posRemain && beforeNeg == negRemain &&\n                beforeLoad == load && beforeCell == pos) stagnation++;\n            else stagnation = 0;\n\n            if (stagnation > 3200) return fail();\n        }\n\n        bool valid = (turns <= MAX_TURNS && posRemain == 0 && negRemain == 0 && load == 0);\n        if (valid) {\n            for (int i = 0; i < M; i++) if (h[i] != 0) { valid = false; break; }\n        }\n\n        SimResult res;\n        res.cost = valid ? cost : INF64;\n        res.turns = turns;\n        res.valid = valid;\n        if constexpr (RECORD) if (valid) res.ops = move(ops);\n        return res;\n    }\n\n    int capIndex(int cap) const {\n        int best = 0;\n        long long bestDiff = llabs((long long)CAPS[0] - cap);\n        for (int i = 1; i < (int)CAPS.size(); i++) {\n            long long d = llabs((long long)CAPS[i] - cap);\n            if (d < bestDiff) {\n                bestDiff = d;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    GParam randomParam(uint64_t &rng) const {\n        GParam p;\n        p.cap = CAPS[randInt(rng, 0, (int)CAPS.size() - 1)];\n        p.mode = randInt(rng, 0, 2);\n        p.dist_scale = randInt(rng, 150, 430);\n        p.link_scale = randInt(rng, 0, 260);\n        p.src_bias = randInt(rng, 0, 12);\n        p.dst_bias = randInt(rng, 0, 12);\n\n        int collectProb = (p.mode == 0 ? 25 : 45);\n        p.collect_when_loaded = (randInt(rng, 0, 99) < collectProb);\n\n        p.force_sink_ratio = randInt(rng, 40, 95);\n        p.src_loaded_pen = randInt(rng, 0, 8);\n        p.sink_empty_pen = randInt(rng, 0, 8);\n        p.axis_pref = randInt(rng, 0, 2);\n        p.path_unload_bonus = randInt(rng, 60, 260);\n        p.path_load_bonus = randInt(rng, 10, 190);\n        p.back_penalty = randInt(rng, 0, 180);\n        p.retarget_on_change = (randInt(rng, 0, 1) == 1);\n        return p;\n    }\n\n    GParam mutateParam(const GParam &base, uint64_t &rng) const {\n        GParam p = base;\n\n        auto clampi = [&](int &x, int l, int r) {\n            if (x < l) x = l;\n            if (x > r) x = r;\n        };\n\n        int changes = randInt(rng, 1, 5);\n        for (int it = 0; it < changes; it++) {\n            int sw = randInt(rng, 0, 14);\n            int delta = (int)(xorshift64(rng) % 5ULL) - 2; // [-2,2]\n\n            switch (sw) {\n                case 0: {\n                    int idx = capIndex(p.cap);\n                    idx += delta;\n                    idx = max(0, min((int)CAPS.size() - 1, idx));\n                    p.cap = CAPS[idx];\n                    break;\n                }\n                case 1:\n                    p.mode = randInt(rng, 0, 2);\n                    break;\n                case 2:\n                    p.dist_scale += delta * 20;\n                    clampi(p.dist_scale, 130, 520);\n                    break;\n                case 3:\n                    p.link_scale += delta * 20;\n                    clampi(p.link_scale, 0, 340);\n                    break;\n                case 4:\n                    p.src_bias += delta;\n                    clampi(p.src_bias, 0, 16);\n                    break;\n                case 5:\n                    p.dst_bias += delta;\n                    clampi(p.dst_bias, 0, 16);\n                    break;\n                case 6:\n                    p.collect_when_loaded = !p.collect_when_loaded;\n                    break;\n                case 7:\n                    p.force_sink_ratio += delta * 5;\n                    clampi(p.force_sink_ratio, 30, 99);\n                    break;\n                case 8:\n                    p.src_loaded_pen += delta;\n                    clampi(p.src_loaded_pen, 0, 12);\n                    break;\n                case 9:\n                    p.sink_empty_pen += delta;\n                    clampi(p.sink_empty_pen, 0, 12);\n                    break;\n                case 10:\n                    p.axis_pref = randInt(rng, 0, 2);\n                    break;\n                case 11:\n                    p.path_unload_bonus += delta * 20;\n                    clampi(p.path_unload_bonus, 30, 340);\n                    break;\n                case 12:\n                    p.path_load_bonus += delta * 20;\n                    clampi(p.path_load_bonus, 0, 260);\n                    break;\n                case 13:\n                    p.back_penalty += delta * 20;\n                    clampi(p.back_penalty, 0, 240);\n                    break;\n                case 14:\n                    p.retarget_on_change = !p.retarget_on_change;\n                    break;\n            }\n        }\n        return p;\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        M = N * N;\n\n        bool allZero = true;\n        input_hash = 1469598103934665603ULL;\n        total_positive = 0;\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int x;\n                cin >> x;\n                int id = r * N + c;\n                init_h[id] = x;\n                rr[id] = r;\n                cc[id] = c;\n                if (x != 0) allZero = false;\n                if (x > 0) total_positive += x;\n\n                input_hash ^= (uint64_t)(x + 1000);\n                input_hash *= 1099511628211ULL;\n            }\n        }\n\n        if (allZero) return;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                distm[i][j] = (uint8_t)(abs(rr[i] - rr[j]) + abs(cc[i] - cc[j]));\n            }\n        }\n\n        vector<int> posIds, negIds;\n        posIds.reserve(M);\n        negIds.reserve(M);\n        for (int i = 0; i < M; i++) {\n            if (init_h[i] > 0) posIds.push_back(i);\n            else if (init_h[i] < 0) negIds.push_back(i);\n        }\n\n        for (int i = 0; i < M; i++) {\n            int bp = INT_MAX, bn = INT_MAX;\n            for (int id : posIds) bp = min(bp, (int)distm[i][id]);\n            for (int id : negIds) bn = min(bn, (int)distm[i][id]);\n            init_near_pos[i] = (bp == INT_MAX ? 0 : bp);\n            init_near_neg[i] = (bn == INT_MAX ? 0 : bn);\n        }\n\n        // Build cycle candidates\n        cycles.clear();\n        vector<int> baseCycle = buildBaseCycle();\n        for (int t = 0; t < 8; t++) {\n            auto cyc = transformCycle(baseCycle, t);\n            if ((int)cyc.size() != M || cyc[0] != 0) continue;\n            bool dup = false;\n            for (auto &v : cycles) if (v == cyc) { dup = true; break; }\n            if (!dup) cycles.push_back(move(cyc));\n        }\n        if (cycles.empty()) cycles.push_back(baseCycle);\n\n        // Build path candidates (with transforms/reverse)\n        paths.clear();\n        addPathTransforms(buildRowSnake());\n        addPathTransforms(buildColSnake());\n        addPathTransforms(buildSpiralCW());\n        addPathTransforms(buildSpiralCCW());\n        if (paths.empty()) addPathIfValid(buildRowSnake());\n\n        auto tStart = chrono::steady_clock::now();\n        auto elapsed = [&]() -> double {\n            return chrono::duration<double>(chrono::steady_clock::now() - tStart).count();\n        };\n        const double TIME_LIMIT = 1.90;\n\n        long long bestCost = INF64;\n        BestType bestType = BestType::NONE;\n        CycleSpec bestCycle;\n        PathSpec bestPath;\n        GreedySpec bestGreedy;\n\n        // quick baseline\n        if (!paths.empty()) {\n            auto b = simulatePath<false>(paths[0], 1, INF64);\n            if (b.valid && b.cost < bestCost) {\n                bestCost = b.cost;\n                bestType = BestType::PATH;\n                bestPath = {0, 1};\n            }\n        }\n\n        // cycle search\n        for (int ci = 0; ci < (int)cycles.size(); ci++) {\n            for (int dir : {1, -1}) {\n                for (int shift = 0; shift < M; shift++) {\n                    auto cur = simulateCycle<false>(cycles[ci], dir, shift, bestCost);\n                    if (cur.valid && cur.cost < bestCost) {\n                        bestCost = cur.cost;\n                        bestType = BestType::CYCLE;\n                        bestCycle = {ci, dir, shift};\n                    }\n                }\n            }\n        }\n\n        // path search\n        for (int pi = 0; pi < (int)paths.size(); pi++) {\n            for (int ct = 0; ct <= 1; ct++) {\n                auto cur = simulatePath<false>(paths[pi], ct, bestCost);\n                if (cur.valid && cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::PATH;\n                    bestPath = {pi, ct};\n                }\n            }\n        }\n\n        vector<EliteItem> elite;\n        auto addElite = [&](const GParam &p, uint64_t sd, long long c) {\n            if (c >= INF64 / 2) return;\n            elite.push_back({p, sd, c});\n            sort(elite.begin(), elite.end(), [](const EliteItem &a, const EliteItem &b) {\n                return a.cost < b.cost;\n            });\n            const int EL = 12;\n            if ((int)elite.size() > EL) elite.resize(EL);\n        };\n\n        // deterministic greedy seeds\n        vector<GParam> seedParams;\n        auto makeP = [&](int cap, int mode, int dist, int link, int sb, int db, bool collect,\n                         int force, int slp, int sep, int axis, int ub, int lb, int back, bool ret) {\n            GParam p;\n            p.cap = cap;\n            p.mode = mode;\n            p.dist_scale = dist;\n            p.link_scale = link;\n            p.src_bias = sb;\n            p.dst_bias = db;\n            p.collect_when_loaded = collect;\n            p.force_sink_ratio = force;\n            p.src_loaded_pen = slp;\n            p.sink_empty_pen = sep;\n            p.axis_pref = axis;\n            p.path_unload_bonus = ub;\n            p.path_load_bonus = lb;\n            p.back_penalty = back;\n            p.retarget_on_change = ret;\n            return p;\n        };\n\n        vector<int> capList = {220, 400, 750, 1400, 3000, INF_CAP};\n        for (int cap : capList) {\n            seedParams.push_back(makeP(cap, 0, 250, 60, 2, 2, false, 70, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 1, 240, 70, 2, 2, false, 68, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 1, 230, 80, 2, 2, true,  65, 1, 1, 2, 120, 90, 45, true));\n            seedParams.push_back(makeP(cap, 2, 230, 100, 2, 2, false, 70, 1, 1, 2, 130, 70, 40, true));\n            seedParams.push_back(makeP(cap, 2, 220, 120, 2, 2, true,  65, 1, 1, 2, 120, 95, 45, true));\n        }\n        seedParams.push_back(makeP(INF_CAP, 2, 250, 140, 1, 3, false, 75, 2, 1, 0, 110, 70, 60, true));\n        seedParams.push_back(makeP(INF_CAP, 2, 250, 140, 1, 3, false, 75, 2, 1, 1, 110, 70, 60, true));\n\n        const uint64_t MUL = 0x9e3779b97f4a7c15ULL;\n\n        bool stopSeed = false;\n        for (int i = 0; i < (int)seedParams.size() && !stopSeed; i++) {\n            for (int rep = 0; rep < 2; rep++) {\n                if (elapsed() > 1.20) { stopSeed = true; break; }\n\n                uint64_t sd = input_hash ^ (MUL * (uint64_t)(i * 2 + rep + 1));\n                if (sd == 0) sd = 88172645463325252ULL;\n\n                auto cur = simulateGreedy<false>(seedParams[i], sd, INF64);\n                if (!cur.valid) continue;\n\n                addElite(seedParams[i], sd, cur.cost);\n\n                if (cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::GREEDY;\n                    bestGreedy = {seedParams[i], sd};\n                }\n            }\n        }\n\n        // randomized elite local search\n        uint64_t rng = input_hash ^ 0xd1b54a32d192ed03ULL;\n        if (rng == 0) rng = 88172645463325252ULL;\n\n        int iter = 0;\n        while (elapsed() < TIME_LIMIT) {\n            GParam p;\n            if (!elite.empty() && randInt(rng, 0, 99) < 85) {\n                int top = min<int>((int)elite.size(), 6);\n                int idx = randInt(rng, 0, top - 1);\n                p = mutateParam(elite[idx].p, rng);\n                if (randInt(rng, 0, 99) < 8) p = randomParam(rng);\n            } else {\n                p = randomParam(rng);\n            }\n\n            uint64_t sd = xorshift64(rng) ^ (MUL * (uint64_t)(iter + 10007));\n            if (sd == 0) sd = 88172645463325252ULL;\n\n            long long cutoff = INF64;\n            if (bestCost < INF64 / 2) {\n                if ((iter & 3) != 0) cutoff = bestCost;\n                else cutoff = min(INF64, bestCost + 20000);\n            }\n\n            auto cur = simulateGreedy<false>(p, sd, cutoff);\n            if (cur.valid) {\n                addElite(p, sd, cur.cost);\n\n                if (cur.cost < bestCost) {\n                    bestCost = cur.cost;\n                    bestType = BestType::GREEDY;\n                    bestGreedy = {p, sd};\n                }\n            }\n            iter++;\n        }\n\n        SimResult ans;\n        if (bestType == BestType::CYCLE) {\n            ans = simulateCycle<true>(cycles[bestCycle.ci], bestCycle.dir, bestCycle.shift, INF64);\n        } else if (bestType == BestType::PATH) {\n            ans = simulatePath<true>(paths[bestPath.pi], bestPath.cleanup_type, INF64);\n        } else if (bestType == BestType::GREEDY) {\n            ans = simulateGreedy<true>(bestGreedy.p, bestGreedy.seed, INF64);\n        }\n\n        // safety fallback\n        if (!ans.valid) {\n            bool ok = false;\n\n            if (!elite.empty()) {\n                auto r = simulateGreedy<true>(elite[0].p, elite[0].seed, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            for (int pi = 0; pi < (int)paths.size() && !ok; pi++) {\n                auto r = simulatePath<true>(paths[pi], 1, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            for (int ci = 0; ci < (int)cycles.size() && !ok; ci++) {\n                auto r = simulateCycle<true>(cycles[ci], 1, 0, INF64);\n                if (r.valid) { ans = move(r); ok = true; }\n            }\n\n            if (!ok) {\n                // legal fallback: do nothing\n                ans.valid = true;\n            }\n        }\n\n        for (const auto &s : ans.ops) {\n            cout << s << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next_u64() % (uint64_t)n); }\n    double next_double() { return (next_u64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nclass Solver {\n    static constexpr int MAXS = 60;\n    static constexpr int MAXM = 15;\n    static constexpr int MAXSUM = 1500;\n    using Arr = array<int, MAXM>;\n\n    struct Params {\n        double progress = 0.0;\n\n        // pair score = mu + cSigma*sigma + cGain*gain\n        double cSigma = 1.0, cGain = 0.5;\n\n        // heuristic layout score\n        double wSum = 1.0, wBest1 = 0.0, wBest24 = 0.0;\n        double beta1 = 0.0, beta2 = 0.0, beta3 = 0.0, betaFrag = 0.0;\n\n        // seed base score\n        double rareExact = 0.0, rareNear = 0.0, rareCur2 = 0.0, rareFrag = 0.0;\n\n        // selection\n        int topR = 1, topV = 20;\n        double bonusMand = 0.0, bonusV = 0.0;\n        bool forceTop1 = false;\n        bool forceInit = false;\n        int initFragThr = 2;\n        double noiseAmp = 2.0;\n\n        // constructive placement\n        double nodeCoef = 1.0, neighCoef = 1.3;\n\n        // SA\n        int restarts = 2;\n        int iterBase = 6000;\n        double replaceProb = 0.6;\n        double temp0 = 70.0, temp1 = 0.35;\n    };\n\n    struct FutureStats {\n        double exTop1 = 0.0;\n        double exTop2 = 0.0;\n        double keepInit = 0.0;\n    };\n\n    int N = 0, M = 0, T = 0;\n    int S = 0, P = 0, E = 0;\n\n    int X[MAXS][MAXM]{};\n    int V[MAXS]{};\n\n    int initMax[MAXM]{};\n    int initCnt[MAXM]{};\n\n    int G1[MAXM]{}, G2[MAXM]{}, G3[MAXM]{};\n    int topCnt[MAXM]{};\n    int ordDim[MAXM][MAXS]{};\n\n    // adaptive hard constraints\n    int reqTop[MAXM]{};\n    int reqInit[MAXM]{};\n    bool anyReq = false;\n\n    double seedBase[MAXS]{};\n    double pairSc[MAXS][MAXS]{};\n\n    vector<int> ordV, ordBase;\n    vector<pair<int, int>> edges;\n    vector<vector<int>> nbr;\n    vector<int> posOrder;\n\n    // exact table for final turn\n    vector<float> pairCDF; // size: S*S*(MAXSUM+1)\n\n    XorShift64 rng;\n\npublic:\n    Solver() : rng(1) {}\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        if (!(cin >> N >> M >> T)) return;\n        S = 2 * N * (N - 1);\n        P = N * N;\n\n        build_field();\n        if (!read_state()) return;\n\n        for (int l = 0; l < M; ++l) {\n            int mx = 0;\n            for (int i = 0; i < S; ++i) mx = max(mx, X[i][l]);\n            initMax[l] = mx;\n        }\n        init_rng_from_state();\n\n        for (int turn = 0; turn < T; ++turn) {\n            vector<int> layout = decide_layout(turn);\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = 0; j < N; ++j) {\n                    if (j) cout << ' ';\n                    cout << layout[i * N + j];\n                }\n                cout << '\\n';\n            }\n            cout.flush();\n\n            if (turn + 1 < T) {\n                if (!read_state()) return;\n            }\n        }\n    }\n\nprivate:\n    bool read_state() {\n        for (int i = 0; i < S; ++i) {\n            for (int l = 0; l < M; ++l) {\n                if (!(cin >> X[i][l])) return false;\n                if (X[i][l] < 0) return false;\n            }\n            for (int l = M; l < MAXM; ++l) X[i][l] = 0;\n        }\n        return true;\n    }\n\n    void init_rng_from_state() {\n        uint64_t h = 1469598103934665603ull;\n        for (int i = 0; i < S; ++i) {\n            for (int l = 0; l < M; ++l) {\n                h ^= (uint64_t)(X[i][l] + 1);\n                h *= 1099511628211ull;\n            }\n        }\n        rng.x = h ^ 0x9e3779b97f4a7c15ull;\n    }\n\n    void build_field() {\n        edges.clear();\n        nbr.assign(P, {});\n\n        for (int i = 0; i < N; ++i) {\n            for (int j = 0; j < N; ++j) {\n                int p = i * N + j;\n                if (j + 1 < N) {\n                    int q = p + 1;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n                if (i + 1 < N) {\n                    int q = p + N;\n                    edges.emplace_back(p, q);\n                    nbr[p].push_back(q);\n                    nbr[q].push_back(p);\n                }\n            }\n        }\n        E = (int)edges.size();\n\n        posOrder.resize(P);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        const double c = (N - 1) * 0.5;\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            int da = (int)nbr[a].size(), db = (int)nbr[b].size();\n            if (da != db) return da > db;\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n            double ra = fabs(ai - c) + fabs(aj - c);\n            double rb = fabs(bi - c) + fabs(bj - c);\n            if (ra != rb) return ra < rb;\n            return a < b;\n        });\n    }\n\n    Params make_params(int turn) const {\n        Params prm;\n        double p = (T <= 1 ? 1.0 : (double)turn / (double)(T - 1));\n        double q = 1.0 - p;\n        prm.progress = p;\n\n        prm.cSigma = 0.80 + 0.90 * p;\n        prm.cGain  = 0.24 + 0.56 * p;\n\n        prm.wSum    = 1.00 - 0.12 * p;\n        prm.wBest1  = 0.40 + 7.2 * p;\n        prm.wBest24 = 0.14 + 2.6 * p;\n\n        prm.beta1 = 10.5 * q * q + 1.0;\n        prm.beta2 = 4.0 * q * q;\n        prm.beta3 = 1.2 * q * q;\n        prm.betaFrag = 12.0 * q * q;\n\n        prm.rareExact = 9.0 * q + 3.0;\n        prm.rareNear  = 3.0 * q + 1.0;\n        prm.rareCur2  = 1.1 * q + 0.2;\n        prm.rareFrag  = 9.0 * q + 1.0;\n\n        prm.topR = (p < 0.25 ? 3 : (p < 0.75 ? 2 : 1));\n        prm.topV = 20 + (int)llround(6.0 * p);\n        prm.bonusMand = 17.0 * q + 9.0;\n        prm.bonusV = 7.0 + 2.4 * p;\n\n        prm.forceTop1 = (turn <= 7);\n        prm.forceInit = (turn <= 4);\n        prm.initFragThr = (turn <= 2 ? 4 : (turn <= 5 ? 3 : 2));\n\n        prm.noiseAmp = 1.7 + 1.5 * q;\n\n        prm.nodeCoef = 1.0;\n        prm.neighCoef = 1.30 + 0.20 * p;\n\n        prm.replaceProb = 0.62 - 0.20 * p;\n        prm.temp0 = 74.0 - 14.0 * p;\n        prm.temp1 = 0.35;\n\n        if (turn == T - 1) {\n            prm.restarts = 2;\n            prm.iterBase = 3200;\n        } else if (turn <= 1) {\n            prm.restarts = 3;\n            prm.iterBase = 5000 + 600 * turn;\n        } else if (turn <= 6) {\n            prm.restarts = 2;\n            prm.iterBase = 6200;\n        } else if (turn == T - 2) {\n            prm.restarts = 3;\n            prm.iterBase = 7000;\n        } else {\n            prm.restarts = 2;\n            prm.iterBase = 6500;\n        }\n\n        return prm;\n    }\n\n    void compute_turn_stats(const Params& prm) {\n        for (int i = 0; i < S; ++i) {\n            int s = 0;\n            for (int l = 0; l < M; ++l) s += X[i][l];\n            V[i] = s;\n        }\n\n        ordV.resize(S);\n        iota(ordV.begin(), ordV.end(), 0);\n        sort(ordV.begin(), ordV.end(), [&](int a, int b) {\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        for (int l = 0; l < M; ++l) {\n            vector<int> ord(S);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                if (V[a] != V[b]) return V[a] > V[b];\n                return a < b;\n            });\n            for (int i = 0; i < S; ++i) ordDim[l][i] = ord[i];\n\n            G1[l] = X[ordDim[l][0]][l];\n            G2[l] = X[ordDim[l][min(1, S - 1)]][l];\n            G3[l] = X[ordDim[l][min(2, S - 1)]][l];\n\n            int cTop = 0, cInit = 0;\n            for (int i = 0; i < S; ++i) {\n                if (X[i][l] == G1[l]) ++cTop;\n                if (X[i][l] == initMax[l]) ++cInit;\n            }\n            topCnt[l] = cTop;\n            initCnt[l] = cInit;\n        }\n\n        for (int i = 0; i < S; ++i) {\n            int c1 = 0, c2 = 0, c3 = 0;\n            double frag = 0.0;\n\n            for (int l = 0; l < M; ++l) {\n                if (X[i][l] == G1[l]) {\n                    ++c1;\n                    frag += 1.0 / max(1, topCnt[l]);\n                }\n                if (X[i][l] >= G2[l]) ++c2;\n                if (X[i][l] >= G3[l]) ++c3;\n                if (initCnt[l] > 0 && X[i][l] == initMax[l]) {\n                    frag += 0.7 / (double)initCnt[l];\n                }\n            }\n\n            seedBase[i] = (double)V[i]\n                        + prm.rareExact * c1\n                        + prm.rareNear * c2\n                        + prm.rareCur2 * c3\n                        + prm.rareFrag * frag;\n        }\n\n        ordBase.resize(S);\n        iota(ordBase.begin(), ordBase.end(), 0);\n        sort(ordBase.begin(), ordBase.end(), [&](int a, int b) {\n            if (seedBase[a] != seedBase[b]) return seedBase[a] > seedBase[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        for (int i = 0; i < S; ++i) {\n            pairSc[i][i] = (double)V[i];\n            for (int j = i + 1; j < S; ++j) {\n                long long d2 = 0;\n                int sumMax = 0;\n                for (int l = 0; l < M; ++l) {\n                    int a = X[i][l], b = X[j][l];\n                    int d = a - b;\n                    d2 += 1LL * d * d;\n                    sumMax += max(a, b);\n                }\n                double mu = 0.5 * (V[i] + V[j]);\n                double sigma = 0.5 * sqrt((double)d2);\n                double gain = (double)sumMax - mu;\n                pairSc[i][j] = pairSc[j][i] = mu + prm.cSigma * sigma + prm.cGain * gain;\n            }\n        }\n    }\n\n    void build_requirements(int turn) {\n        anyReq = false;\n        int gapTop[MAXM], gapInit[MAXM];\n\n        for (int l = 0; l < M; ++l) {\n            reqTop[l] = 0;\n            reqInit[l] = 0;\n\n            gapTop[l] = G1[l] - G2[l];\n            gapInit[l] = initMax[l] - G2[l];\n\n            // top constraints\n            if (turn <= 2) {\n                if (topCnt[l] == 1 && gapTop[l] >= 2) reqTop[l] = 1;\n                else if (topCnt[l] == 2) {\n                    if (gapTop[l] >= 6) reqTop[l] = 2;\n                    else if (gapTop[l] >= 3) reqTop[l] = 1;\n                }\n            } else if (turn <= 5) {\n                if (topCnt[l] == 1 && gapTop[l] >= 3) reqTop[l] = 1;\n                else if (topCnt[l] == 2 && gapTop[l] >= 5) reqTop[l] = 1;\n            }\n            reqTop[l] = min(reqTop[l], topCnt[l]);\n\n            // init constraints\n            if (initCnt[l] > 0) {\n                if (turn <= 1) {\n                    if (initCnt[l] == 1 && gapInit[l] >= 2) reqInit[l] = 1;\n                    else if (initCnt[l] == 2) {\n                        if (gapInit[l] >= 6) reqInit[l] = 2;\n                        else if (gapInit[l] >= 3) reqInit[l] = 1;\n                    }\n                } else if (turn <= 4) {\n                    if (initCnt[l] == 1 && gapInit[l] >= 4) reqInit[l] = 1;\n                    else if (initCnt[l] == 2 && gapInit[l] >= 7) reqInit[l] = 1;\n                }\n            }\n            reqInit[l] = min(reqInit[l], initCnt[l]);\n\n            if (reqTop[l] > 0 || reqInit[l] > 0) anyReq = true;\n        }\n\n        // adaptive requirement budget to avoid over-constraining\n        int reqBudget = 0;\n        if (turn <= 1) reqBudget = 14;\n        else if (turn <= 3) reqBudget = 10;\n        else if (turn <= 5) reqBudget = 7;\n        else reqBudget = 0;\n\n        if (reqBudget > 0) {\n            int totalReq = 0;\n            for (int l = 0; l < M; ++l) totalReq += reqTop[l] + reqInit[l];\n\n            while (totalReq > reqBudget) {\n                int remType = -1; // 0 top, 1 init\n                int remL = -1;\n                double minPri = 1e100;\n\n                for (int l = 0; l < M; ++l) {\n                    if (reqTop[l] > 0) {\n                        double pri = 2.0 * gapTop[l] + (topCnt[l] <= 2 ? 10.0 : 0.0) + (reqTop[l] >= 2 ? 2.0 : 0.0);\n                        if (pri < minPri) {\n                            minPri = pri;\n                            remType = 0;\n                            remL = l;\n                        }\n                    }\n                    if (reqInit[l] > 0) {\n                        double pri = 2.0 * gapInit[l] + (initCnt[l] <= 2 ? 11.0 : 0.0) + (reqInit[l] >= 2 ? 2.0 : 0.0);\n                        if (pri < minPri) {\n                            minPri = pri;\n                            remType = 1;\n                            remL = l;\n                        }\n                    }\n                }\n\n                if (remL == -1) break;\n                if (remType == 0) --reqTop[remL];\n                else --reqInit[remL];\n                --totalReq;\n            }\n        }\n\n        anyReq = false;\n        for (int l = 0; l < M; ++l) {\n            if (reqTop[l] > 0 || reqInit[l] > 0) {\n                anyReq = true;\n                break;\n            }\n        }\n    }\n\n    bool valid_counts(const Arr& topSel, const Arr& initSel) const {\n        if (!anyReq) return true;\n        for (int l = 0; l < M; ++l) {\n            if (topSel[l] < reqTop[l]) return false;\n            if (initSel[l] < reqInit[l]) return false;\n        }\n        return true;\n    }\n\n    void compute_counts(const vector<int>& a, Arr& topSel, Arr& initSel) const {\n        topSel.fill(0);\n        initSel.fill(0);\n        for (int p = 0; p < P; ++p) {\n            int s = a[p];\n            for (int l = 0; l < M; ++l) {\n                if (X[s][l] == G1[l]) ++topSel[l];\n                if (X[s][l] == initMax[l]) ++initSel[l];\n            }\n        }\n    }\n\n    void repair_layout(vector<int>& a) {\n        if (!anyReq) return;\n\n        vector<int> pos(S, -1);\n        for (int p = 0; p < P; ++p) pos[a[p]] = p;\n\n        Arr topSel, initSel;\n        compute_counts(a, topSel, initSel);\n        if (valid_counts(topSel, initSel)) return;\n\n        for (int it = 0; it < 240; ++it) {\n            int kind = 0; // 1 top, 2 init\n            int dim = -1;\n            int worstDef = 0;\n\n            for (int l = 0; l < M; ++l) {\n                int d = reqTop[l] - topSel[l];\n                if (d > worstDef) {\n                    worstDef = d;\n                    kind = 1;\n                    dim = l;\n                }\n            }\n            for (int l = 0; l < M; ++l) {\n                int d = reqInit[l] - initSel[l];\n                if (d > worstDef) {\n                    worstDef = d;\n                    kind = 2;\n                    dim = l;\n                }\n            }\n            if (worstDef <= 0) break;\n\n            int cand = -1;\n            double candScore = -1e100;\n            for (int s = 0; s < S; ++s) {\n                if (pos[s] != -1) continue;\n                bool ok = (kind == 1 ? X[s][dim] == G1[dim] : X[s][dim] == initMax[dim]);\n                if (!ok) continue;\n                double sc = seedBase[s] + 0.01 * V[s];\n                if (sc > candScore) {\n                    candScore = sc;\n                    cand = s;\n                }\n            }\n            if (cand == -1) break;\n\n            int bestPos = -1;\n            double worstVal = 1e100;\n\n            for (int p = 0; p < P; ++p) {\n                int old = a[p];\n                Arr nt = topSel, ni = initSel;\n\n                for (int l = 0; l < M; ++l) {\n                    nt[l] += (X[cand][l] == G1[l]) - (X[old][l] == G1[l]);\n                    ni[l] += (X[cand][l] == initMax[l]) - (X[old][l] == initMax[l]);\n                }\n\n                if (!valid_counts(nt, ni)) continue;\n\n                double val = seedBase[old] + 0.01 * V[old];\n                if (val < worstVal) {\n                    worstVal = val;\n                    bestPos = p;\n                }\n            }\n\n            if (bestPos == -1) break;\n\n            int old = a[bestPos];\n            a[bestPos] = cand;\n            pos[old] = -1;\n            pos[cand] = bestPos;\n\n            compute_counts(a, topSel, initSel);\n            if (valid_counts(topSel, initSel)) return;\n        }\n    }\n\n    int pick_unused_from(const vector<int>& posOf, const vector<int>& order, int topN) {\n        topN = min(topN, (int)order.size());\n        if (topN <= 0) return -1;\n\n        for (int t = 0; t < 24; ++t) {\n            int id = order[rng.next_int(topN)];\n            if (posOf[id] == -1) return id;\n        }\n        for (int t = 0; t < 120; ++t) {\n            int id = rng.next_int(S);\n            if (posOf[id] == -1) return id;\n        }\n        return -1;\n    }\n\n    vector<int> select_seeds(const Params& prm, int mode, int turn) {\n        (void)turn;\n        vector<double> pri(S);\n        for (int i = 0; i < S; ++i) pri[i] = seedBase[i];\n\n        for (int l = 0; l < M; ++l) {\n            for (int k = 0; k < prm.topR && k < S; ++k) {\n                int id = ordDim[l][k];\n                pri[id] += prm.bonusMand * (prm.topR - k);\n            }\n        }\n\n        for (int k = 0; k < prm.topV && k < S; ++k) {\n            int id = ordV[k];\n            pri[id] += prm.bonusV * (double)(prm.topV - k) / (double)prm.topV;\n        }\n\n        if (mode > 0) {\n            double amp = prm.noiseAmp * (0.55 + 0.22 * mode);\n            for (int i = 0; i < S; ++i) pri[i] += (rng.next_double() - 0.5) * amp;\n        }\n\n        vector<int> ord(S);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (pri[a] != pri[b]) return pri[a] > pri[b];\n            if (V[a] != V[b]) return V[a] > V[b];\n            return a < b;\n        });\n\n        vector<int> sel(ord.begin(), ord.begin() + P);\n        vector<char> inSel(S, 0), locked(S, 0);\n        for (int id : sel) inSel[id] = 1;\n\n        auto enforce_seed = [&](int id, bool lockit) -> bool {\n            if (id < 0) return false;\n            if (inSel[id]) {\n                if (lockit) locked[id] = 1;\n                return true;\n            }\n\n            int worstPos = -1;\n            double worstPri = 1e100;\n            for (int i = 0; i < P; ++i) {\n                int sid = sel[i];\n                if (locked[sid]) continue;\n                if (pri[sid] < worstPri) {\n                    worstPri = pri[sid];\n                    worstPos = i;\n                }\n            }\n            if (worstPos == -1) return false;\n\n            inSel[sel[worstPos]] = 0;\n            sel[worstPos] = id;\n            inSel[id] = 1;\n            if (lockit) locked[id] = 1;\n            return true;\n        };\n\n        if (prm.forceTop1) {\n            for (int l = 0; l < M; ++l) enforce_seed(ordDim[l][0], false);\n        }\n\n        if (prm.forceInit) {\n            int budget = 8;\n            for (int l = 0; l < M && budget > 0; ++l) {\n                if (initCnt[l] == 0) continue;\n                bool has = false;\n                for (int id : sel) if (X[id][l] == initMax[l]) { has = true; break; }\n                if (has) continue;\n\n                int cand = -1;\n                double bs = -1e100;\n                for (int s = 0; s < S; ++s) {\n                    if (!inSel[s] && X[s][l] == initMax[l]) {\n                        if (pri[s] > bs) {\n                            bs = pri[s];\n                            cand = s;\n                        }\n                    }\n                }\n                if (cand != -1 && enforce_seed(cand, false)) --budget;\n            }\n        }\n\n        // enforce hard reqTop\n        for (int l = 0; l < M; ++l) {\n            while (true) {\n                int cur = 0;\n                for (int id : sel) if (X[id][l] == G1[l]) ++cur;\n                if (cur >= reqTop[l]) break;\n\n                int cand = -1;\n                double bs = -1e100;\n                for (int s = 0; s < S; ++s) {\n                    if (!inSel[s] && X[s][l] == G1[l]) {\n                        if (pri[s] > bs) {\n                            bs = pri[s];\n                            cand = s;\n                        }\n                    }\n                }\n                if (cand == -1) break;\n                if (!enforce_seed(cand, true)) break;\n            }\n        }\n\n        // enforce hard reqInit\n        for (int l = 0; l < M; ++l) {\n            while (true) {\n                int cur = 0;\n                for (int id : sel) if (X[id][l] == initMax[l]) ++cur;\n                if (cur >= reqInit[l]) break;\n\n                int cand = -1;\n                double bs = -1e100;\n                for (int s = 0; s < S; ++s) {\n                    if (!inSel[s] && X[s][l] == initMax[l]) {\n                        if (pri[s] > bs) {\n                            bs = pri[s];\n                            cand = s;\n                        }\n                    }\n                }\n                if (cand == -1) break;\n                if (!enforce_seed(cand, true)) break;\n            }\n        }\n\n        return sel;\n    }\n\n    vector<int> construct_layout(const vector<int>& selected, const Params& prm, int mode) {\n        vector<int> order = posOrder;\n        if (mode > 0) {\n            for (int i = P - 1; i > 0; --i) {\n                int j = rng.next_int(i + 1);\n                swap(order[i], order[j]);\n            }\n            stable_sort(order.begin(), order.end(), [&](int a, int b) {\n                return (int)nbr[a].size() > (int)nbr[b].size();\n            });\n        }\n\n        vector<int> rem = selected;\n        vector<int> a(P, -1);\n\n        for (int t = 0; t < P; ++t) {\n            int pos = order[t];\n\n            vector<pair<double, int>> cand;\n            cand.reserve(rem.size());\n\n            for (int idx = 0; idx < (int)rem.size(); ++idx) {\n                int s = rem[idx];\n                double sc = prm.nodeCoef * seedBase[s];\n\n                double nb = 0.0;\n                for (int q : nbr[pos]) {\n                    int sq = a[q];\n                    if (sq != -1) nb += pairSc[s][sq];\n                }\n                sc += prm.neighCoef * nb;\n\n                if (mode > 0) sc += (rng.next_double() - 0.5) * 0.8;\n                cand.emplace_back(sc, idx);\n            }\n\n            sort(cand.begin(), cand.end(),\n                 [](const auto& x, const auto& y) { return x.first > y.first; });\n\n            int pick = 0;\n            if (mode > 0) {\n                int cap = min<int>(3 + mode, cand.size());\n                pick = rng.next_int(cap);\n            }\n\n            int ridx = cand[pick].second;\n            int seed = rem[ridx];\n            a[pos] = seed;\n            rem[ridx] = rem.back();\n            rem.pop_back();\n        }\n\n        return a;\n    }\n\n    double evaluate_layout(const vector<int>& a, const Params& prm) const {\n        double sumE = 0.0;\n        double b1 = -1e100, b2 = -1e100, b3 = -1e100, b4 = -1e100;\n\n        for (const auto& e : edges) {\n            double s = pairSc[a[e.first]][a[e.second]];\n            sumE += s;\n\n            if (s > b1) {\n                b4 = b3; b3 = b2; b2 = b1; b1 = s;\n            } else if (s > b2) {\n                b4 = b3; b3 = b2; b2 = s;\n            } else if (s > b3) {\n                b4 = b3; b3 = s;\n            } else if (s > b4) {\n                b4 = s;\n            }\n        }\n\n        double cov1 = 0.0, cov2 = 0.0, cov3 = 0.0;\n        double fragKeep = 0.0;\n\n        for (int l = 0; l < M; ++l) {\n            int m1 = -1, m2 = -1, m3 = -1;\n            int cntTopSel = 0, cntInitSel = 0;\n\n            for (int p = 0; p < P; ++p) {\n                int v = X[a[p]][l];\n\n                if (v > m1) {\n                    m3 = m2; m2 = m1; m1 = v;\n                } else if (v > m2) {\n                    m3 = m2; m2 = v;\n                } else if (v > m3) {\n                    m3 = v;\n                }\n\n                if (v == G1[l]) ++cntTopSel;\n                if (v == initMax[l]) ++cntInitSel;\n            }\n\n            if (m2 < 0) m2 = 0;\n            if (m3 < 0) m3 = 0;\n\n            cov1 += m1;\n            cov2 += m2;\n            cov3 += m3;\n\n            if (topCnt[l] <= 2) fragKeep += min(cntTopSel, topCnt[l]);\n            else if (topCnt[l] == 3) fragKeep += 0.5 * min(cntTopSel, 2);\n\n            if (initCnt[l] > 0) {\n                if (cntInitSel > 0) fragKeep += 0.5;\n                if (initCnt[l] <= 2) fragKeep += 0.7 * min(cntInitSel, 2);\n            }\n\n            // mild penalty if violating hard req\n            if (reqTop[l] > 0 && cntTopSel < reqTop[l]) fragKeep -= 2.5 * (reqTop[l] - cntTopSel);\n            if (reqInit[l] > 0 && cntInitSel < reqInit[l]) fragKeep -= 2.5 * (reqInit[l] - cntInitSel);\n        }\n\n        return prm.wSum * sumE\n             + prm.wBest1 * b1\n             + prm.wBest24 * (b2 + b3 + b4)\n             + prm.beta1 * cov1\n             + prm.beta2 * cov2\n             + prm.beta3 * cov3\n             + prm.betaFrag * fragKeep;\n    }\n\n    pair<vector<int>, double> sa_layout(const vector<int>& init, const Params& prm, int iters) {\n        vector<int> a = init;\n        if (anyReq) repair_layout(a);\n\n        vector<int> bestA = a;\n        vector<int> posOf(S, -1);\n        for (int p = 0; p < P; ++p) posOf[a[p]] = p;\n\n        Arr topSel, initSel;\n        compute_counts(a, topSel, initSel);\n        bool useReq = anyReq && valid_counts(topSel, initSel);\n\n        double cur = evaluate_layout(a, prm);\n        double best = cur;\n\n        for (int it = 0; it < iters; ++it) {\n            double temp = prm.temp0 + (prm.temp1 - prm.temp0) * (double)it / (double)iters;\n\n            if (rng.next_double() < prm.replaceProb) {\n                int p = rng.next_int(P);\n                int s = pick_unused_from(posOf, ordBase, 46);\n                if (s == -1) continue;\n\n                int old = a[p];\n\n                Arr nt = topSel, ni = initSel;\n                if (useReq) {\n                    for (int l = 0; l < M; ++l) {\n                        nt[l] += (X[s][l] == G1[l]) - (X[old][l] == G1[l]);\n                        ni[l] += (X[s][l] == initMax[l]) - (X[old][l] == initMax[l]);\n                    }\n                    if (!valid_counts(nt, ni)) continue;\n                }\n\n                a[p] = s;\n                posOf[s] = p;\n                posOf[old] = -1;\n\n                double nxt = evaluate_layout(a, prm);\n                double d = nxt - cur;\n                bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (useReq) {\n                        topSel = nt;\n                        initSel = ni;\n                    }\n                    if (cur > best) {\n                        best = cur;\n                        bestA = a;\n                    }\n                } else {\n                    a[p] = old;\n                    posOf[old] = p;\n                    posOf[s] = -1;\n                }\n            } else {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                posOf[sp] = q;\n                posOf[sq] = p;\n\n                double nxt = evaluate_layout(a, prm);\n                double d = nxt - cur;\n                bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestA = a;\n                    }\n                } else {\n                    swap(a[p], a[q]);\n                    posOf[sp] = p;\n                    posOf[sq] = q;\n                }\n            }\n        }\n\n        return {bestA, best};\n    }\n\n    double greedy_polish(vector<int>& a, const Params& prm) {\n        if (anyReq) repair_layout(a);\n\n        vector<int> posOf(S, -1);\n        for (int p = 0; p < P; ++p) posOf[a[p]] = p;\n\n        Arr topSel, initSel;\n        compute_counts(a, topSel, initSel);\n        bool useReq = anyReq && valid_counts(topSel, initSel);\n\n        double cur = evaluate_layout(a, prm);\n\n        vector<int> plist(P);\n        iota(plist.begin(), plist.end(), 0);\n        for (int i = P - 1; i > 0; --i) {\n            int j = rng.next_int(i + 1);\n            swap(plist[i], plist[j]);\n        }\n\n        for (int p : plist) {\n            int old = a[p];\n\n            double bestSc = cur;\n            int bestS = -1;\n            int bestQ = -2;\n            Arr bestNt = topSel, bestNi = initSel;\n\n            for (int s = 0; s < S; ++s) {\n                int q = posOf[s];\n                if (q == p) continue;\n\n                double sc;\n                Arr nt = topSel, ni = initSel;\n                bool feasible = true;\n\n                if (q == -1) {\n                    if (useReq) {\n                        for (int l = 0; l < M; ++l) {\n                            nt[l] += (X[s][l] == G1[l]) - (X[old][l] == G1[l]);\n                            ni[l] += (X[s][l] == initMax[l]) - (X[old][l] == initMax[l]);\n                        }\n                        if (!valid_counts(nt, ni)) feasible = false;\n                    }\n                    if (!feasible) continue;\n\n                    a[p] = s;\n                    posOf[s] = p;\n                    posOf[old] = -1;\n                    sc = evaluate_layout(a, prm);\n                    a[p] = old;\n                    posOf[old] = p;\n                    posOf[s] = -1;\n                } else {\n                    swap(a[p], a[q]);\n                    posOf[s] = p;\n                    posOf[old] = q;\n                    sc = evaluate_layout(a, prm);\n                    swap(a[p], a[q]);\n                    posOf[s] = q;\n                    posOf[old] = p;\n                }\n\n                if (sc > bestSc + 1e-9) {\n                    bestSc = sc;\n                    bestS = s;\n                    bestQ = q;\n                    bestNt = nt;\n                    bestNi = ni;\n                }\n            }\n\n            if (bestS != -1) {\n                if (bestQ == -1) {\n                    int out = a[p];\n                    a[p] = bestS;\n                    posOf[bestS] = p;\n                    posOf[out] = -1;\n                    if (useReq) {\n                        topSel = bestNt;\n                        initSel = bestNi;\n                    }\n                } else {\n                    int q = bestQ;\n                    int out = a[p];\n                    swap(a[p], a[q]);\n                    posOf[bestS] = p;\n                    posOf[out] = q;\n                }\n                cur = bestSc;\n            }\n        }\n\n        return cur;\n    }\n\n    void random_perturb(vector<int>& a, int ops) {\n        vector<int> pos(S, -1);\n        for (int p = 0; p < P; ++p) pos[a[p]] = p;\n\n        for (int op = 0; op < ops; ++op) {\n            if (rng.next_double() < 0.58) {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                pos[sp] = q;\n                pos[sq] = p;\n            } else {\n                int p = rng.next_int(P);\n                int s = pick_unused_from(pos, ordBase, 44);\n                if (s == -1) continue;\n                int old = a[p];\n                a[p] = s;\n                pos[s] = p;\n                pos[old] = -1;\n            }\n        }\n    }\n\n    FutureStats evaluate_future_stats(const vector<int>& a) const {\n        FutureStats fs;\n        int lo[64], hi[64];\n\n        for (int l = 0; l < M; ++l) {\n            for (int e = 0; e < E; ++e) {\n                int p = edges[e].first, q = edges[e].second;\n                int s1 = a[p], s2 = a[q];\n                int x1 = X[s1][l], x2 = X[s2][l];\n                if (x1 <= x2) {\n                    lo[e] = x1;\n                    hi[e] = x2;\n                } else {\n                    lo[e] = x2;\n                    hi[e] = x1;\n                }\n            }\n\n            double keepProb = (initMax[l] == 0 ? 1.0 : 0.0);\n\n            for (int v = 1; v <= 100; ++v) {\n                double p0 = 1.0, p1 = 0.0;\n                for (int e = 0; e < E; ++e) {\n                    if (v <= lo[e]) {\n                        double np1 = p0;\n                        p0 = 0.0;\n                        p1 = np1;\n                    } else if (v <= hi[e]) {\n                        double np1 = p1 * 0.5 + p0 * 0.5;\n                        p0 *= 0.5;\n                        p1 = np1;\n                    }\n                }\n\n                double ge1 = 1.0 - p0;\n                double ge2 = 1.0 - p0 - p1;\n                if (ge2 < 0.0) ge2 = 0.0;\n\n                fs.exTop1 += ge1;\n                fs.exTop2 += ge2;\n\n                if (v == initMax[l] && initCnt[l] > 0) keepProb = ge1;\n            }\n\n            if (initCnt[l] > 0) fs.keepInit += keepProb;\n        }\n\n        return fs;\n    }\n\n    // ---------- exact utils ----------\n    void build_pair_cdf() {\n        constexpr int STR = MAXSUM + 1;\n        pairCDF.assign((size_t)S * (size_t)S * (size_t)STR, 1.0f);\n\n        static double dp[STR], ndp[STR];\n\n        for (int i = 0; i < S; ++i) {\n            for (int j = i; j < S; ++j) {\n                for (int s = 0; s <= MAXSUM; ++s) dp[s] = 0.0;\n                dp[0] = 1.0;\n                int lim = 0;\n\n                for (int l = 0; l < M; ++l) {\n                    int a = X[i][l], b = X[j][l];\n                    int nlim = lim + max(a, b);\n                    for (int s = 0; s <= nlim; ++s) ndp[s] = 0.0;\n\n                    if (a == b) {\n                        for (int s = 0; s <= lim; ++s) ndp[s + a] += dp[s];\n                    } else {\n                        for (int s = 0; s <= lim; ++s) {\n                            double v = dp[s] * 0.5;\n                            ndp[s + a] += v;\n                            ndp[s + b] += v;\n                        }\n                    }\n\n                    for (int s = 0; s <= nlim; ++s) dp[s] = ndp[s];\n                    lim = nlim;\n                }\n\n                size_t base1 = ((size_t)i * S + (size_t)j) * STR;\n                size_t base2 = ((size_t)j * S + (size_t)i) * STR;\n\n                double run = 0.0;\n                for (int s = 0; s <= lim; ++s) {\n                    run += dp[s];\n                    if (run > 1.0) run = 1.0;\n                    pairCDF[base1 + s] = (float)run;\n                    pairCDF[base2 + s] = (float)run;\n                }\n            }\n        }\n    }\n\n    double exact_expected_max(const vector<int>& a) const {\n        constexpr int STR = MAXSUM + 1;\n        static double prod[STR];\n\n        for (int s = 0; s <= MAXSUM; ++s) prod[s] = 1.0;\n\n        for (const auto& e : edges) {\n            int s1 = a[e.first], s2 = a[e.second];\n            const float* cdf = &pairCDF[((size_t)s1 * S + (size_t)s2) * STR];\n            for (int s = 0; s <= MAXSUM; ++s) prod[s] *= (double)cdf[s];\n        }\n\n        double ans = 0.0;\n        for (int s = 1; s <= MAXSUM; ++s) {\n            double p = prod[s - 1];\n            if (p < 0.0) p = 0.0;\n            if (p > 1.0) p = 1.0;\n            ans += 1.0 - p;\n        }\n        return ans;\n    }\n\n    vector<int> choose_tminus2(const vector<vector<int>>& cands, const vector<double>& hs) {\n        int C = (int)cands.size();\n        if (C == 1) return cands[0];\n\n        // robust, mostly heuristic, plus future stats\n        vector<double> score(C, -1e100);\n        int best = 0, bestH = 0;\n        for (int i = 1; i < C; ++i) if (hs[i] > hs[bestH]) bestH = i;\n\n        for (int i = 0; i < C; ++i) {\n            FutureStats fs = evaluate_future_stats(cands[i]);\n            score[i] = hs[i]\n                     + 3.6 * fs.exTop1\n                     + 1.6 * fs.exTop2\n                     + 75.0 * fs.keepInit;\n            if (score[i] > score[best]) best = i;\n        }\n\n        // conservative fallback: avoid switching from best-hs on tiny future margin\n        if (best != bestH) {\n            double diff = score[best] - score[bestH];\n            if (diff < 180.0 && hs[best] < hs[bestH] + 40.0) {\n                best = bestH;\n            }\n        }\n\n        return cands[best];\n    }\n\n    pair<vector<int>, double> sa_exact(const vector<int>& init, int iters, double replaceProb) {\n        vector<int> a = init, bestA = a;\n        vector<int> pos(S, -1);\n        for (int p = 0; p < P; ++p) pos[a[p]] = p;\n\n        double cur = exact_expected_max(a);\n        double best = cur;\n\n        double t0 = 1.8, t1 = 0.03;\n\n        for (int it = 0; it < iters; ++it) {\n            double temp = t0 + (t1 - t0) * (double)it / (double)iters;\n\n            if (rng.next_double() < replaceProb) {\n                int p = rng.next_int(P);\n                int s = pick_unused_from(pos, ordV, 46);\n                if (s == -1) continue;\n\n                int old = a[p];\n                a[p] = s;\n                pos[s] = p;\n                pos[old] = -1;\n\n                double nxt = exact_expected_max(a);\n                double d = nxt - cur;\n                bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestA = a;\n                    }\n                } else {\n                    a[p] = old;\n                    pos[old] = p;\n                    pos[s] = -1;\n                }\n            } else {\n                int p = rng.next_int(P);\n                int q = rng.next_int(P - 1);\n                if (q >= p) ++q;\n\n                int sp = a[p], sq = a[q];\n                swap(a[p], a[q]);\n                pos[sp] = q;\n                pos[sq] = p;\n\n                double nxt = exact_expected_max(a);\n                double d = nxt - cur;\n                bool ok = (d >= 0.0) || (exp(d / temp) > rng.next_double());\n\n                if (ok) {\n                    cur = nxt;\n                    if (cur > best) {\n                        best = cur;\n                        bestA = a;\n                    }\n                } else {\n                    swap(a[p], a[q]);\n                    pos[sp] = p;\n                    pos[sq] = q;\n                }\n            }\n        }\n\n        return {bestA, best};\n    }\n\n    void add_unique(vector<vector<int>>& vv, const vector<int>& a) {\n        for (const auto& b : vv) if (b == a) return;\n        vv.push_back(a);\n    }\n\n    vector<int> choose_final_exact(const vector<vector<int>>& cands,\n                                   const vector<double>& hs,\n                                   const Params& prm) {\n        vector<vector<int>> pool;\n        for (const auto& c : cands) add_unique(pool, c);\n\n        if (pool.empty()) return cands[0];\n        if (pool.size() == 1) return pool[0];\n\n        build_pair_cdf();\n\n        vector<double> ex(pool.size()), hv(pool.size());\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            ex[i] = exact_expected_max(pool[i]);\n            hv[i] = evaluate_layout(pool[i], prm);\n        }\n\n        vector<int> ids(pool.size());\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            double sa = ex[a] + 0.00004 * hv[a];\n            double sb = ex[b] + 0.00004 * hv[b];\n            return sa > sb;\n        });\n\n        int bestH = 0;\n        for (int i = 1; i < (int)hs.size(); ++i) if (hs[i] > hs[bestH]) bestH = i;\n\n        vector<vector<int>> starts;\n        add_unique(starts, pool[ids[0]]);\n        if ((int)ids.size() >= 2) add_unique(starts, pool[ids[1]]);\n        add_unique(starts, cands[bestH]);\n\n        static const int itTbl[] = {170, 120, 80};\n        for (int i = 0; i < (int)starts.size(); ++i) {\n            vector<int> st = starts[i];\n            if (i > 0) random_perturb(st, 3 + 2 * i);\n\n            int iters = itTbl[min(i, 2)];\n            auto [lay, sc] = sa_exact(st, iters, 0.60);\n            (void)sc;\n            add_unique(pool, lay);\n        }\n\n        // tiny extra refine\n        int b = 0;\n        double bv = -1e100;\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            double v = exact_expected_max(pool[i]);\n            if (v > bv) {\n                bv = v;\n                b = i;\n            }\n        }\n        vector<int> pert = pool[b];\n        random_perturb(pert, 2);\n        auto [lay2, sc2] = sa_exact(pert, 50, 0.62);\n        (void)sc2;\n        add_unique(pool, lay2);\n\n        int best = 0;\n        double bestScore = -1e100;\n        for (int i = 0; i < (int)pool.size(); ++i) {\n            double emax = exact_expected_max(pool[i]);\n            double h = evaluate_layout(pool[i], prm);\n            double sc = emax + 0.00003 * h;\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n        return pool[best];\n    }\n\n    vector<int> decide_layout(int turn) {\n        Params prm = make_params(turn);\n        compute_turn_stats(prm);\n        build_requirements(turn);\n\n        vector<vector<int>> cands;\n        vector<double> hs;\n\n        // constrained multi-start\n        for (int r = 0; r < prm.restarts; ++r) {\n            vector<int> selected = select_seeds(prm, r, turn);\n            vector<int> init = construct_layout(selected, prm, r);\n\n            int iters = prm.iterBase + 260 * r;\n            auto [lay, sc] = sa_layout(init, prm, iters);\n            cands.push_back(lay);\n            hs.push_back(sc);\n        }\n\n        // one relaxed candidate (early-mid only)\n        if (anyReq && turn <= 6) {\n            Arr bkTop{}, bkInit{};\n            for (int l = 0; l < M; ++l) {\n                bkTop[l] = reqTop[l];\n                bkInit[l] = reqInit[l];\n                reqTop[l] = 0;\n                reqInit[l] = 0;\n            }\n            bool bkAny = anyReq;\n            anyReq = false;\n\n            vector<int> selected = select_seeds(prm, prm.restarts + 1, turn);\n            vector<int> init = construct_layout(selected, prm, 1);\n            auto [lay, sc] = sa_layout(init, prm, max(1400, prm.iterBase / 2));\n            cands.push_back(lay);\n            hs.push_back(sc);\n\n            anyReq = bkAny;\n            for (int l = 0; l < M; ++l) {\n                reqTop[l] = bkTop[l];\n                reqInit[l] = bkInit[l];\n            }\n        }\n\n        // very-early portfolio\n        if (turn <= 2) {\n            vector<int> selV(P);\n            for (int i = 0; i < P; ++i) selV[i] = ordV[i];\n            vector<int> initV = construct_layout(selV, prm, 1);\n            auto [layV, scV] = sa_layout(initV, prm, max(1200, prm.iterBase / 3));\n            cands.push_back(layV);\n            hs.push_back(scV);\n        }\n\n        // polish best\n        int best = 0;\n        for (int i = 1; i < (int)hs.size(); ++i) if (hs[i] > hs[best]) best = i;\n\n        vector<int> polished = cands[best];\n        double psc = greedy_polish(polished, prm);\n        cands.push_back(polished);\n        hs.push_back(psc);\n\n        // nearby candidate\n        {\n            vector<int> v = polished;\n            random_perturb(v, 4);\n            auto [lay, sc] = sa_layout(v, prm, max(900, prm.iterBase / 5));\n            cands.push_back(lay);\n            hs.push_back(sc);\n        }\n\n        if (turn == T - 2) {\n            return choose_tminus2(cands, hs);\n        }\n\n        if (turn == T - 1) {\n            vector<int> ids(cands.size());\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) { return hs[a] > hs[b]; });\n\n            for (int z = 0; z < min(2, (int)ids.size()); ++z) {\n                vector<int> v = cands[ids[z]];\n                random_perturb(v, 4 + 2 * z);\n                auto [lay, sc] = sa_layout(v, prm, 700 + 200 * z);\n                cands.push_back(lay);\n                hs.push_back(sc);\n            }\n\n            return choose_final_exact(cands, hs, prm);\n        }\n\n        best = 0;\n        for (int i = 1; i < (int)hs.size(); ++i) if (hs[i] > hs[best]) best = i;\n        return cands[best];\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic double nowMsGlobal() {\n    using namespace std::chrono;\n    return duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count();\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    x = x ^ (x >> 31);\n    return x;\n}\n\nstruct Config {\n    int lenMode;       // 0: full spread, 1: medium spread, 2: mostly short + one long\n    int weightMode;    // 0: balanced, 1: drop-biased, 2: pick-biased\n    int oppMode;       // 0: long-first, 1: short-first, 2: index order (or tie-order)\n    int lookaheadMode; // 0: off, 1: light, 2: stronger\n    int moveMode;      // 0: conservative, 1: normal, 2: aggressive move opportunism\n    int pickMargin;    // opportunistic pick cap margin\n    int initMode;      // 0: src-centric init, 1: mixed centroid init\n    int tieMode;       // 0: deterministic index ties, 1: randomized tie-order\n    uint64_t seed;\n};\n\nstruct AttemptResult {\n    long long score = (1LL << 60);\n    bool success = false;\n    vector<int> len;\n    int initX = 0, initY = 0;\n    vector<string> ops;\n};\n\nclass Attempt {\n    static constexpr int MAXC = 900; // 30*30\n    static constexpr int MAXK = 14;  // V-1, V<=15\n    static constexpr long long INF_SCORE = (1LL << 60);\n\n    const int DX[4] = {0, 1, 0, -1}; // R,D,L,U\n    const int DY[4] = {1, 0, -1, 0};\n\n    int N, V, K, Vp, C;\n    Config cfg;\n    double deadlineMs;\n    long long cutoffScore;\n\n    // Immutable initial task\n    const vector<uint8_t>& src0;\n    const vector<uint8_t>& dst0;\n    int remSrc0, remDst0;\n    long long sumSrcX0, sumSrcY0, sumDstX0, sumDstY0;\n\n    // Mutable state\n    vector<uint8_t> src, dst;\n    int remSrc = 0, remDst = 0;\n    long long sumSrcX = 0, sumSrcY = 0, sumDstX = 0, sumDstY = 0;\n\n    vector<int> len;\n    vector<int> curDir;\n    vector<char> hold;\n    int heldNow = 0;\n\n    int curX = 0, curY = 0;\n    int initX = 0, initY = 0;\n\n    int rotD[4][4];\n    vector<int> rx, ry;   // cell id -> x,y\n    vector<int> reach;    // ((rid*K + leaf)<<2)+dir -> cell id or -1\n\n    vector<string> ops;\n    vector<int> leafPriority;\n    vector<int> leafRank;\n    int dirRank[4] = {0, 1, 2, 3};\n\n    // Matching buffers\n    int owner[MAXC], ownerDir[MAXC], ownerStamp[MAXC];\n    int vis[MAXC], cellMark[MAXC];\n    int stampOwner = 1, stampVis = 1, stampCell = 1;\n\n    // Execution marks\n    int resMark[MAXC], usedMark[MAXC];\n    int stampRes = 1, stampUsed = 1;\n\n    // Lookahead removal marks\n    int rmSrcMark[MAXC], rmDstMark[MAXC];\n    int stampRmSrc = 1, stampRmDst = 1;\n\n    bool abortedTime = false;\n    bool abortedCutoff = false;\n\n    struct MR {\n        int cnt = 0;\n        int rmax = 0;\n    };\n\n    struct Cand {\n        bool ok = false;\n        int rid = -1;\n        int lp = 0, ld = 0;\n        int pick = 0, drop = 0, cnt = 0;\n        int turns = 1;\n        int dist = 0;\n        int pen = 0;\n        int fut = 0;\n        int util = 0;\n        int rnd = 0;\n    };\n\npublic:\n    Attempt(\n        int N_, int V_,\n        const vector<uint8_t>& srcInit,\n        const vector<uint8_t>& dstInit,\n        int remS0, int remD0,\n        long long sx0, long long sy0, long long tx0, long long ty0,\n        Config cfg_,\n        double deadlineMs_,\n        long long cutoffScore_\n    )\n        : N(N_), V(V_), K(V_ - 1), Vp(V_), C(N_ * N_),\n          cfg(cfg_), deadlineMs(deadlineMs_), cutoffScore(cutoffScore_),\n          src0(srcInit), dst0(dstInit),\n          remSrc0(remS0), remDst0(remD0),\n          sumSrcX0(sx0), sumSrcY0(sy0), sumDstX0(tx0), sumDstY0(ty0) {\n        memset(ownerStamp, 0, sizeof(ownerStamp));\n        memset(vis, 0, sizeof(vis));\n        memset(cellMark, 0, sizeof(cellMark));\n        memset(resMark, 0, sizeof(resMark));\n        memset(usedMark, 0, sizeof(usedMark));\n        memset(rmSrcMark, 0, sizeof(rmSrcMark));\n        memset(rmDstMark, 0, sizeof(rmDstMark));\n    }\n\n    AttemptResult run() {\n        initState();\n        buildRot();\n        buildArm();\n        precomputeReach();\n        chooseInitialRoot();\n        plan();\n\n        AttemptResult res;\n        bool success = (remDst == 0 && heldNow == 0);\n        res.success = success;\n\n        if (success) {\n            res.score = (long long)ops.size();\n        } else {\n            if (abortedCutoff && cutoffScore < INF_SCORE) {\n                res.score = cutoffScore + 1;\n            } else {\n                res.score = 100000LL + 1000LL * remDst;\n            }\n        }\n\n        res.len = len;\n        res.initX = initX;\n        res.initY = initY;\n        res.ops = std::move(ops);\n        return res;\n    }\n\nprivate:\n    inline bool timeUp() const {\n        return nowMsGlobal() > deadlineMs;\n    }\n\n    inline bool cutoffReached() const {\n        if (cutoffScore >= INF_SCORE) return false;\n        long long cur = (long long)ops.size();\n        if (cur >= cutoffScore) return true;\n\n        // Lower bound on remaining turns from mandatory actions:\n        // needDrop = remDst\n        // needPick = max(0, remDst - heldNow)\n        long long needDrop = remDst;\n        long long needPick = max(0, remDst - heldNow);\n        long long lb = (needDrop + needPick + K - 1) / K;\n\n        return cur + lb >= cutoffScore;\n    }\n\n    inline int man(int x1, int y1, int x2, int y2) const {\n        return abs(x1 - x2) + abs(y1 - y2);\n    }\n\n    inline int candRnd(int rid, int pick, int drop, int turns) const {\n        uint64_t z = cfg.seed;\n        z ^= (uint64_t)rid * 0x9e3779b97f4a7c15ULL;\n        z ^= (uint64_t)pick * 0xbf58476d1ce4e5b9ULL;\n        z ^= (uint64_t)drop * 0x94d049bb133111ebULL;\n        z ^= (uint64_t)turns * 0x2545F4914F6CDD1DULL;\n        z ^= (uint64_t)curX * 1315423911u;\n        z ^= (uint64_t)curY * 2654435761u;\n        z ^= (uint64_t)remSrc * 889523592379ull;\n        z ^= (uint64_t)remDst * 7046029254386353131ull;\n        return (int)(splitmix64(z) & 0xFFFF);\n    }\n\n    void initState() {\n        src = src0;\n        dst = dst0;\n        remSrc = remSrc0;\n        remDst = remDst0;\n        sumSrcX = sumSrcX0;\n        sumSrcY = sumSrcY0;\n        sumDstX = sumDstX0;\n        sumDstY = sumDstY0;\n\n        curX = curY = 0;\n        initX = initY = 0;\n\n        ops.clear();\n        ops.reserve(70000);\n\n        stampOwner = stampVis = stampCell = 1;\n        stampRes = stampUsed = 1;\n        stampRmSrc = stampRmDst = 1;\n\n        abortedTime = false;\n        abortedCutoff = false;\n    }\n\n    void buildRot() {\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                int d = (b - a + 4) % 4;\n                rotD[a][b] = min(d, 4 - d);\n            }\n        }\n    }\n\n    void buildArm() {\n        int maxLen = max(1, (N - 1) / 2);\n        int useMax = maxLen;\n\n        if (cfg.lenMode == 1) {\n            useMax = max(2, (2 * maxLen + 2) / 3);\n            useMax = min(useMax, maxLen);\n        } else if (cfg.lenMode == 2) {\n            useMax = max(2, (maxLen + 1) / 2);\n            useMax = min(useMax, maxLen);\n        }\n\n        len.assign(K, 1);\n        if (K <= useMax) {\n            if (K == 1) len[0] = 1;\n            else {\n                for (int i = 0; i < K; i++) {\n                    len[i] = 1 + (long long)i * (useMax - 1) / (K - 1);\n                }\n            }\n        } else {\n            for (int i = 0; i < K; i++) len[i] = 1 + (i % useMax);\n        }\n\n        if (cfg.lenMode == 2 && K >= 1) len[K - 1] = maxLen;\n\n        curDir.assign(K, 0);\n        hold.assign(K, 0);\n        heldNow = 0;\n\n        // tie rank\n        leafRank.assign(K, 0);\n        vector<pair<uint64_t, int>> vv;\n        vv.reserve(K);\n        for (int i = 0; i < K; i++) {\n            uint64_t key = (cfg.tieMode == 0 ? (uint64_t)i : splitmix64(cfg.seed ^ (uint64_t)(i + 1) * 0x9e3779b97f4a7c15ULL));\n            vv.push_back({key, i});\n        }\n        sort(vv.begin(), vv.end());\n        for (int r = 0; r < K; r++) leafRank[vv[r].second] = r;\n\n        // direction tie rank\n        array<pair<uint64_t, int>, 4> dd;\n        for (int d = 0; d < 4; d++) {\n            uint64_t key = (cfg.tieMode == 0 ? (uint64_t)d : splitmix64(cfg.seed ^ (uint64_t)(d + 11) * 0xbf58476d1ce4e5b9ULL));\n            dd[d] = {key, d};\n        }\n        sort(dd.begin(), dd.end());\n        for (int r = 0; r < 4; r++) dirRank[dd[r].second] = r;\n\n        leafPriority.resize(K);\n        iota(leafPriority.begin(), leafPriority.end(), 0);\n\n        if (cfg.oppMode == 0) {\n            sort(leafPriority.begin(), leafPriority.end(), [&](int a, int b) {\n                if (len[a] != len[b]) return len[a] > len[b];\n                return leafRank[a] < leafRank[b];\n            });\n        } else if (cfg.oppMode == 1) {\n            sort(leafPriority.begin(), leafPriority.end(), [&](int a, int b) {\n                if (len[a] != len[b]) return len[a] < len[b];\n                return leafRank[a] < leafRank[b];\n            });\n        } else {\n            sort(leafPriority.begin(), leafPriority.end(), [&](int a, int b) {\n                return leafRank[a] < leafRank[b];\n            });\n        }\n    }\n\n    void precomputeReach() {\n        rx.resize(C);\n        ry.resize(C);\n        for (int c = 0; c < C; c++) {\n            rx[c] = c / N;\n            ry[c] = c % N;\n        }\n\n        reach.assign(C * K * 4, -1);\n        for (int rid = 0; rid < C; rid++) {\n            int x = rx[rid], y = ry[rid];\n            for (int leaf = 0; leaf < K; leaf++) {\n                int L = len[leaf];\n                int base = ((rid * K + leaf) << 2);\n                for (int d = 0; d < 4; d++) {\n                    int nx = x + DX[d] * L;\n                    int ny = y + DY[d] * L;\n                    if (0 <= nx && nx < N && 0 <= ny && ny < N) reach[base + d] = nx * N + ny;\n                    else reach[base + d] = -1;\n                }\n            }\n        }\n    }\n\n    MR matchGroup(\n        int rid,\n        const int* leaves, int nLeaves,\n        const vector<uint8_t>& target,\n        int rotLimit,\n        int* outDir = nullptr,\n        int* outCell = nullptr\n    ) {\n        MR res;\n        if (nLeaves <= 0) return res;\n\n        int deg[MAXK];\n        int eCell[MAXK][4];\n        int eDir[MAXK][4];\n        uint8_t eRot[MAXK][4];\n\n        int candCells[4 * MAXK];\n        int candCnt = 0;\n        int cstamp = ++stampCell;\n\n        bool any = false;\n\n        for (int u = 0; u < nLeaves; u++) {\n            int leaf = leaves[u];\n            int base = ((rid * K + leaf) << 2);\n\n            int dcnt = 0;\n            for (int d = 0; d < 4; d++) {\n                int c = reach[base + d];\n                if (c < 0 || !target[c]) continue;\n\n                int rr = rotD[curDir[leaf]][d];\n                if (rr > rotLimit) continue;\n\n                eCell[u][dcnt] = c;\n                eDir[u][dcnt] = d;\n                eRot[u][dcnt] = (uint8_t)rr;\n                dcnt++;\n\n                if (cellMark[c] != cstamp) {\n                    cellMark[c] = cstamp;\n                    candCells[candCnt++] = c;\n                }\n            }\n\n            // sort by (rotation, dirRank)\n            for (int i = 0; i < dcnt; i++) {\n                for (int j = i + 1; j < dcnt; j++) {\n                    bool sw = false;\n                    if (eRot[u][j] < eRot[u][i]) sw = true;\n                    else if (eRot[u][j] == eRot[u][i] && dirRank[eDir[u][j]] < dirRank[eDir[u][i]]) sw = true;\n                    if (sw) {\n                        swap(eRot[u][i], eRot[u][j]);\n                        swap(eCell[u][i], eCell[u][j]);\n                        swap(eDir[u][i], eDir[u][j]);\n                    }\n                }\n            }\n\n            deg[u] = dcnt;\n            if (dcnt > 0) any = true;\n        }\n\n        if (!any) return res;\n\n        int ord[MAXK];\n        for (int i = 0; i < nLeaves; i++) ord[i] = i;\n        for (int i = 0; i < nLeaves; i++) {\n            int best = i;\n            for (int j = i + 1; j < nLeaves; j++) {\n                int a = ord[j], b = ord[best];\n                if (deg[a] < deg[b]) best = j;\n                else if (deg[a] == deg[b] && leafRank[leaves[a]] < leafRank[leaves[b]]) best = j;\n            }\n            if (best != i) swap(ord[i], ord[best]);\n        }\n\n        int myStamp = ++stampOwner;\n\n        auto dfs = [&](auto&& self, int u, int tag) -> bool {\n            for (int ei = 0; ei < deg[u]; ei++) {\n                int c = eCell[u][ei];\n                if (vis[c] == tag) continue;\n                vis[c] = tag;\n\n                if (ownerStamp[c] != myStamp || self(self, owner[c], tag)) {\n                    ownerStamp[c] = myStamp;\n                    owner[c] = u;\n                    ownerDir[c] = eDir[u][ei];\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        int cnt = 0;\n        for (int i = 0; i < nLeaves; i++) {\n            int u = ord[i];\n            int tag = ++stampVis;\n            if (dfs(dfs, u, tag)) cnt++;\n        }\n\n        res.cnt = cnt;\n        if (cnt == 0) return res;\n\n        int rmax = 0;\n        for (int i = 0; i < candCnt; i++) {\n            int c = candCells[i];\n            if (ownerStamp[c] != myStamp) continue;\n            int u = owner[c];\n            int leaf = leaves[u];\n            int d = ownerDir[c];\n\n            int rr = rotD[curDir[leaf]][d];\n            rmax = max(rmax, rr);\n\n            if (outDir) {\n                outDir[leaf] = d;\n                outCell[leaf] = c;\n            }\n        }\n\n        res.rmax = rmax;\n        return res;\n    }\n\n    int holdPenaltyAt(int rid, int held2, int scx, int scy, int dcx, int dcy) {\n        if (remSrc == 0 || remDst == 0) return held2;\n\n        int ds = man(rx[rid], ry[rid], scx, scy);\n        int dd = man(rx[rid], ry[rid], dcx, dcy);\n        int denom = ds + dd;\n        int targetHeld = (denom == 0) ? (K / 2) : (K * dd + denom / 2) / denom;\n        targetHeld = max(0, min(K, targetHeld));\n        return abs(held2 - targetHeld);\n    }\n\n    bool betterCand(const Cand& a, const Cand& b) {\n        if (!a.ok) return false;\n        if (!b.ok) return true;\n\n        long long lhs = 1LL * a.util * b.turns;\n        long long rhs = 1LL * b.util * a.turns;\n        if (lhs != rhs) return lhs > rhs;\n\n        lhs = 1LL * a.cnt * b.turns;\n        rhs = 1LL * b.cnt * a.turns;\n        if (lhs != rhs) return lhs > rhs;\n\n        if (a.fut != b.fut) return a.fut < b.fut;\n        if (a.pen != b.pen) return a.pen < b.pen;\n        if (a.turns != b.turns) return a.turns < b.turns;\n        if (a.drop != b.drop) return a.drop > b.drop;\n        if (a.dist != b.dist) return a.dist < b.dist;\n\n        int ra = max(a.lp, a.ld), rb = max(b.lp, b.ld);\n        if (ra != rb) return ra < rb;\n\n        return a.rnd < b.rnd;\n    }\n\n    void addTopCandidate(vector<Cand>& top, const Cand& c, int limit) {\n        if (!c.ok) return;\n        top.push_back(c);\n        int i = (int)top.size() - 1;\n        while (i > 0 && betterCand(top[i], top[i - 1])) {\n            swap(top[i], top[i - 1]);\n            --i;\n        }\n        if ((int)top.size() > limit) top.pop_back();\n    }\n\n    bool isCloseCandidate(const Cand& c, const Cand& base) {\n        if (cfg.lookaheadMode == 0) return false;\n\n        int utilPct = (cfg.lookaheadMode == 1 ? 98 : 96);\n        int cntPct  = (cfg.lookaheadMode == 1 ? 92 : 88);\n        int gapTurn = (cfg.lookaheadMode == 1 ? 2 : 3);\n\n        if (c.turns > base.turns + gapTurn) return false;\n\n        long long l1 = 1LL * c.util * base.turns * 100;\n        long long r1 = 1LL * base.util * c.turns * utilPct;\n        if (l1 < r1) return false;\n\n        long long l2 = 1LL * c.cnt * base.turns * 100;\n        long long r2 = 1LL * base.cnt * c.turns * cntPct;\n        if (l2 < r2) return false;\n\n        return true;\n    }\n\n    void chooseInitialRoot() {\n        if (remSrc == 0) {\n            initX = N / 2;\n            initY = N / 2;\n            curX = initX;\n            curY = initY;\n            return;\n        }\n\n        int allLeaves[MAXK];\n        for (int i = 0; i < K; i++) allLeaves[i] = i;\n\n        int scx = (int)(sumSrcX / remSrc);\n        int scy = (int)(sumSrcY / remSrc);\n        int mcx = (int)((sumSrcX + sumDstX) / max(1, remSrc + remDst));\n        int mcy = (int)((sumSrcY + sumDstY) / max(1, remSrc + remDst));\n\n        int bestRid = -1, bestCnt = -1, bestTurns = (int)1e9;\n        int bestD1 = (int)1e9, bestD2 = (int)1e9;\n\n        for (int rid = 0; rid < C; rid++) {\n            MR mr = matchGroup(rid, allLeaves, K, src, 2);\n            if (mr.cnt == 0) continue;\n\n            int turns = max(1, mr.rmax);\n            int dSrc = man(rx[rid], ry[rid], scx, scy);\n            int dMix = man(rx[rid], ry[rid], mcx, mcy);\n\n            bool better = false;\n            if (bestRid < 0) better = true;\n            else {\n                long long l = 1LL * mr.cnt * bestTurns;\n                long long r = 1LL * bestCnt * turns;\n                if (l != r) better = l > r;\n                else if (mr.cnt != bestCnt) better = mr.cnt > bestCnt;\n                else if (turns != bestTurns) better = turns < bestTurns;\n                else {\n                    int curD1 = (cfg.initMode == 0 ? dSrc : dMix);\n                    int curD2 = (cfg.initMode == 0 ? dMix : dSrc);\n                    if (curD1 != bestD1) better = curD1 < bestD1;\n                    else if (curD2 != bestD2) better = curD2 < bestD2;\n                }\n            }\n\n            if (better) {\n                bestRid = rid;\n                bestCnt = mr.cnt;\n                bestTurns = turns;\n                bestD1 = (cfg.initMode == 0 ? dSrc : dMix);\n                bestD2 = (cfg.initMode == 0 ? dMix : dSrc);\n            }\n        }\n\n        if (bestRid < 0) bestRid = (N / 2) * N + (N / 2);\n        initX = rx[bestRid];\n        initY = ry[bestRid];\n        curX = initX;\n        curY = initY;\n    }\n\n    bool buildAssignmentsFromCand(\n        const Cand& cand,\n        const int* emptyLeaves, int nE,\n        const int* holdLeaves, int nH,\n        bool hasP, bool hasD,\n        vector<int>& assignDir,\n        vector<int>& assignCell,\n        int& acts\n    ) {\n        assignDir.assign(K, -1);\n        assignCell.assign(K, -1);\n\n        if (hasP && cand.pick > 0) {\n            int lp = cand.lp;\n            for (int l = 0; l < lp; l++) {\n                if (matchGroup(cand.rid, emptyLeaves, nE, src, l).cnt == cand.pick) {\n                    lp = l;\n                    break;\n                }\n            }\n            matchGroup(cand.rid, emptyLeaves, nE, src, lp, assignDir.data(), assignCell.data());\n        }\n\n        if (hasD && cand.drop > 0) {\n            int ld = cand.ld;\n            for (int l = 0; l < ld; l++) {\n                if (matchGroup(cand.rid, holdLeaves, nH, dst, l).cnt == cand.drop) {\n                    ld = l;\n                    break;\n                }\n            }\n            matchGroup(cand.rid, holdLeaves, nH, dst, ld, assignDir.data(), assignCell.data());\n        }\n\n        acts = 0;\n        for (int i = 0; i < K; i++) if (assignDir[i] >= 0) acts++;\n        return acts > 0;\n    }\n\n    int estimateNextSingleCost(\n        int postRid,\n        const vector<int>& assignDir,\n        const vector<int>& assignCell,\n        const vector<int>& srcList,\n        const vector<int>& dstList\n    ) {\n        int postX = rx[postRid], postY = ry[postRid];\n\n        int postDir[MAXK];\n        char postHold[MAXK];\n        for (int i = 0; i < K; i++) {\n            postDir[i] = curDir[i];\n            postHold[i] = hold[i];\n        }\n\n        int postHeld = heldNow;\n        int postRemSrc = remSrc;\n        int postRemDst = remDst;\n\n        int sm = ++stampRmSrc;\n        int dm = ++stampRmDst;\n\n        for (int i = 0; i < K; i++) {\n            if (assignDir[i] < 0) continue;\n            postDir[i] = assignDir[i];\n            int c = assignCell[i];\n\n            if (hold[i]) {\n                postHold[i] = 0;\n                postHeld--;\n                if (c >= 0 && dst[c] && rmDstMark[c] != dm) {\n                    rmDstMark[c] = dm;\n                    postRemDst--;\n                }\n            } else {\n                postHold[i] = 1;\n                postHeld++;\n                if (c >= 0 && src[c] && rmSrcMark[c] != sm) {\n                    rmSrcMark[c] = sm;\n                    postRemSrc--;\n                }\n            }\n        }\n\n        postRemSrc = max(0, postRemSrc);\n        postRemDst = max(0, postRemDst);\n        if (postRemSrc == 0 && postRemDst == 0) return 0;\n\n        const int INF = 1e9;\n        int bestPick = INF, bestDrop = INF;\n\n        if (postRemSrc > 0) {\n            for (int leaf = 0; leaf < K; leaf++) {\n                if (postHold[leaf]) continue;\n                int L = len[leaf], d0 = postDir[leaf];\n\n                for (int c : srcList) {\n                    if (rmSrcMark[c] == sm) continue;\n                    int tx = rx[c], ty = ry[c];\n\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n                        int cost = max(man(postX, postY, rr, cc), rotD[d0][d]);\n                        bestPick = min(bestPick, max(1, cost));\n                    }\n                }\n            }\n        }\n\n        if (postRemDst > 0) {\n            for (int leaf = 0; leaf < K; leaf++) {\n                if (!postHold[leaf]) continue;\n                int L = len[leaf], d0 = postDir[leaf];\n\n                for (int c : dstList) {\n                    if (rmDstMark[c] == dm) continue;\n                    int tx = rx[c], ty = ry[c];\n\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n                        int cost = max(man(postX, postY, rr, cc), rotD[d0][d]);\n                        bestDrop = min(bestDrop, max(1, cost));\n                    }\n                }\n            }\n        }\n\n        int ans = INF;\n        if (postHeld == 0) {\n            if (postRemSrc > 0 && bestPick < INF) ans = min(ans, bestPick);\n            else if (postRemDst > 0 && bestDrop < INF) ans = min(ans, bestDrop);\n        } else {\n            if (postRemDst > 0 && bestDrop < INF) ans = min(ans, bestDrop);\n            if (postHeld < K && postRemSrc > 0 && bestPick < INF) ans = min(ans, bestPick + 1);\n        }\n\n        if (ans == INF) {\n            if (bestDrop < INF) ans = bestDrop;\n            else if (bestPick < INF) ans = bestPick;\n            else ans = 50;\n        }\n        return min(ans, 50);\n    }\n\n    void executeMove(int rid, const vector<int>& assignDir, const vector<int>& assignCell) {\n        if (abortedTime || abortedCutoff) return;\n        if (timeUp()) { abortedTime = true; return; }\n        if (cutoffReached()) { abortedCutoff = true; return; }\n\n        int bx = rx[rid], by = ry[rid];\n\n        bool activeWanted[MAXK] = {};\n        bool fixed[MAXK] = {};\n        bool plannedDone[MAXK] = {};\n\n        for (int i = 0; i < K; i++) activeWanted[i] = (assignDir[i] >= 0);\n\n        int D = man(curX, curY, bx, by);\n        int Ract = 0;\n        for (int i = 0; i < K; i++) if (activeWanted[i]) {\n            int diff = (assignDir[i] - curDir[i] + 4) % 4;\n            int rr = (diff == 0 ? 0 : (diff == 2 ? 2 : 1));\n            Ract = max(Ract, rr);\n        }\n\n        int turns = max(D, Ract);\n        if (turns == 0) turns = 1;\n\n        int remainAll = 100000 - (int)ops.size();\n        if (remainAll <= 0) return;\n\n        bool doAction = true;\n        if (turns > remainAll) {\n            turns = remainAll;\n            doAction = false;\n        }\n\n        if (cutoffScore < INF_SCORE) {\n            long long remCut = cutoffScore - (long long)ops.size();\n            if (remCut <= 0) {\n                abortedCutoff = true;\n                return;\n            }\n            if ((long long)turns > remCut) {\n                turns = (int)remCut;\n                doAction = false;\n            }\n        }\n\n        if (turns <= 0) return;\n\n        for (int i = 0; i < K; i++) fixed[i] = (doAction && activeWanted[i]);\n\n        int rstamp = 0;\n        if (doAction) {\n            rstamp = ++stampRes;\n            for (int i = 0; i < K; i++) {\n                if (fixed[i] && assignCell[i] >= 0) resMark[assignCell[i]] = rstamp;\n            }\n        }\n\n        static const int MDX[5] = {0, -1, 1, 0, 0};\n        static const int MDY[5] = {0, 0, 0, -1, 1};\n        static const char MCH[5] = {'.', 'U', 'D', 'L', 'R'};\n        static const int ROPT[3] = {0, 1, -1};\n\n        int oppBonus = (cfg.moveMode == 0 ? 180 : (cfg.moveMode == 1 ? 230 : 280));\n\n        for (int t = 0; t < turns; t++) {\n            if ((t & 15) == 0) {\n                if (timeUp()) { abortedTime = true; break; }\n                if (cutoffReached()) { abortedCutoff = true; break; }\n            }\n\n            int rem = turns - t;\n\n            int scx = remSrc ? (int)(sumSrcX / remSrc) : curX;\n            int scy = remSrc ? (int)(sumSrcY / remSrc) : curY;\n            int dcx = remDst ? (int)(sumDstX / remDst) : curX;\n            int dcy = remDst ? (int)(sumDstY / remDst) : curY;\n\n            int bestM = 0, bestScore = INT_MIN, bestDist2 = INT_MAX;\n            bool found = false;\n\n            for (int m = 0; m < 5; m++) {\n                int nx = curX + MDX[m];\n                int ny = curY + MDY[m];\n                if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n\n                int d2 = man(nx, ny, bx, by);\n                if (d2 > rem - 1) continue;\n                found = true;\n\n                int score = -20 * d2;\n\n                for (int i = 0; i < K; i++) {\n                    if (fixed[i] && !plannedDone[i]) continue;\n\n                    bool canAct = false;\n                    int bestNear = INT_MAX;\n\n                    for (int oi = 0; oi < 3; oi++) {\n                        int opt = ROPT[oi];\n                        int nd = (curDir[i] + opt + 4) & 3;\n                        int tx = nx + DX[nd] * len[i];\n                        int ty = ny + DY[nd] * len[i];\n                        if (tx < 0 || tx >= N || ty < 0 || ty >= N) continue;\n                        int c = tx * N + ty;\n\n                        if (doAction && resMark[c] == rstamp) continue;\n\n                        if (hold[i]) {\n                            if (dst[c]) canAct = true;\n                            if (remDst > 0) bestNear = min(bestNear, man(tx, ty, dcx, dcy));\n                        } else {\n                            if (src[c]) canAct = true;\n                            if (remSrc > 0) bestNear = min(bestNear, man(tx, ty, scx, scy));\n                        }\n                    }\n\n                    if (canAct) score += oppBonus;\n                    else if (bestNear != INT_MAX) score -= bestNear / 4;\n                }\n\n                int mixx, mixy;\n                if (heldNow > 0 && remDst > 0) {\n                    mixx = dcx; mixy = dcy;\n                } else if (remSrc > 0) {\n                    mixx = scx; mixy = scy;\n                } else {\n                    mixx = bx; mixy = by;\n                }\n                score -= man(nx, ny, mixx, mixy);\n\n                if (score > bestScore || (score == bestScore && d2 < bestDist2)) {\n                    bestScore = score;\n                    bestDist2 = d2;\n                    bestM = m;\n                }\n            }\n\n            if (!found) {\n                bestM = 0;\n                bestDist2 = man(curX, curY, bx, by);\n                for (int m = 0; m < 5; m++) {\n                    int nx = curX + MDX[m], ny = curY + MDY[m];\n                    if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;\n                    int d2 = man(nx, ny, bx, by);\n                    if (d2 < bestDist2) {\n                        bestDist2 = d2;\n                        bestM = m;\n                    }\n                }\n            }\n\n            curX += MDX[bestM];\n            curY += MDY[bestM];\n\n            string line(2 * Vp, '.');\n            line[0] = MCH[bestM];\n\n            int ustamp = ++stampUsed;\n\n            // Rotations\n            for (int i = 0; i < K; i++) {\n                int chosenOpt = 0;\n\n                if (fixed[i] && !plannedDone[i]) {\n                    int td = assignDir[i];\n                    bool ok = false;\n                    int bestCost = INT_MAX;\n\n                    for (int oi = 0; oi < 3; oi++) {\n                        int opt = ROPT[oi];\n                        int nd = (curDir[i] + opt + 4) & 3;\n                        int need = rotD[nd][td];\n                        if (need > rem - 1) continue;\n                        int cost = need * 10 + (opt != 0);\n                        if (cost < bestCost) {\n                            bestCost = cost;\n                            chosenOpt = opt;\n                            ok = true;\n                        }\n                    }\n\n                    if (!ok) {\n                        int bestNeed = INT_MAX;\n                        for (int oi = 0; oi < 3; oi++) {\n                            int opt = ROPT[oi];\n                            int nd = (curDir[i] + opt + 4) & 3;\n                            int need = rotD[nd][td];\n                            if (need < bestNeed) {\n                                bestNeed = need;\n                                chosenOpt = opt;\n                            }\n                        }\n                    }\n                } else {\n                    int bestVal = INT_MIN;\n\n                    for (int oi = 0; oi < 3; oi++) {\n                        int opt = ROPT[oi];\n                        int nd = (curDir[i] + opt + 4) & 3;\n                        int tx = curX + DX[nd] * len[i];\n                        int ty = curY + DY[nd] * len[i];\n\n                        int val = -1000000;\n                        if (0 <= tx && tx < N && 0 <= ty && ty < N) {\n                            int c = tx * N + ty;\n                            val = 0;\n\n                            if (!(doAction && resMark[c] == rstamp) && usedMark[c] != ustamp) {\n                                if (hold[i] && dst[c]) {\n                                    val += 100000;\n                                    if (heldNow * 3 >= 2 * K) val += 700;\n                                } else if (!hold[i] && src[c]) {\n                                    val += 100000;\n                                    if (heldNow * 3 <= K) val += 350;\n                                }\n                            }\n\n                            if (hold[i]) {\n                                if (remDst > 0) val -= man(tx, ty, dcx, dcy);\n                            } else {\n                                if (remSrc > 0) val -= man(tx, ty, scx, scy);\n                            }\n\n                            if (opt != 0) val -= 1;\n                        }\n\n                        if (val > bestVal) {\n                            bestVal = val;\n                            chosenOpt = opt;\n                        }\n                    }\n                }\n\n                if (chosenOpt == 1) {\n                    line[1 + i] = 'R';\n                    curDir[i] = (curDir[i] + 1) & 3;\n                } else if (chosenOpt == -1) {\n                    line[1 + i] = 'L';\n                    curDir[i] = (curDir[i] + 3) & 3;\n                }\n            }\n\n            int posCell[MAXK];\n            for (int i = 0; i < K; i++) {\n                int tx = curX + DX[curDir[i]] * len[i];\n                int ty = curY + DY[curDir[i]] * len[i];\n                if (0 <= tx && tx < N && 0 <= ty && ty < N) posCell[i] = tx * N + ty;\n                else posCell[i] = -1;\n            }\n\n            bool doP[MAXK] = {};\n\n            // 1) Early planned actions as soon as available\n            if (doAction) {\n                for (int i = 0; i < K; i++) {\n                    if (!(fixed[i] && !plannedDone[i])) continue;\n                    int c = posCell[i];\n                    if (c < 0) continue;\n                    if (assignCell[i] < 0) continue;\n                    if (c != assignCell[i]) continue;\n                    if (curDir[i] != assignDir[i]) continue;\n                    if (usedMark[c] == ustamp) continue;\n                    if (!((hold[i] && dst[c]) || (!hold[i] && src[c]))) continue;\n\n                    doP[i] = true;\n                    usedMark[c] = ustamp;\n                    plannedDone[i] = true;\n                }\n            }\n\n            // 2) Final mandatory planned actions if still pending\n            if (doAction && t == turns - 1) {\n                for (int i = 0; i < K; i++) {\n                    if (!(fixed[i] && !plannedDone[i])) continue;\n                    int c = posCell[i];\n                    if (c < 0) continue;\n                    if (assignCell[i] < 0) continue;\n                    if (c != assignCell[i]) continue;\n                    if (curDir[i] != assignDir[i]) continue;\n                    if (usedMark[c] == ustamp) continue;\n\n                    doP[i] = true;\n                    usedMark[c] = ustamp;\n                    plannedDone[i] = true;\n                }\n            }\n\n            // 3) Opportunistic actions with carry cap\n            int heldTmp = heldNow;\n            for (int i = 0; i < K; i++) {\n                if (!doP[i]) continue;\n                if (hold[i]) heldTmp = max(0, heldTmp - 1);\n                else heldTmp = min(K, heldTmp + 1);\n            }\n\n            int targetHeld = 0;\n            if (remSrc + remDst > 0) targetHeld = (int)((long long)K * remDst / (remSrc + remDst));\n            int pickCap = min(K, targetHeld + cfg.pickMargin);\n\n            auto tryOpp = [&](int i) {\n                if (fixed[i] && !plannedDone[i]) return;\n                int c = posCell[i];\n                if (c < 0) return;\n                if (doAction && resMark[c] == rstamp) return;\n                if (usedMark[c] == ustamp) return;\n\n                if (hold[i]) {\n                    if (dst[c]) {\n                        doP[i] = true;\n                        usedMark[c] = ustamp;\n                        heldTmp = max(0, heldTmp - 1);\n                    }\n                } else {\n                    if (src[c]) {\n                        if (heldTmp >= pickCap) return;\n                        doP[i] = true;\n                        usedMark[c] = ustamp;\n                        heldTmp = min(K, heldTmp + 1);\n                    }\n                }\n            };\n\n            if (heldNow * 3 >= 2 * K) {\n                for (int i : leafPriority) if (hold[i]) tryOpp(i);\n                for (int i : leafPriority) if (!hold[i]) tryOpp(i);\n            } else if (heldNow * 3 <= K) {\n                for (int i : leafPriority) if (!hold[i]) tryOpp(i);\n                for (int i : leafPriority) if (hold[i]) tryOpp(i);\n            } else {\n                for (int i : leafPriority) tryOpp(i);\n            }\n\n            for (int i = 0; i < K; i++) {\n                if (doP[i]) line[Vp + (i + 1)] = 'P';\n            }\n\n            ops.push_back(move(line));\n\n            // apply actions in leaf index order\n            for (int i = 0; i < K; i++) {\n                if (!doP[i]) continue;\n                int c = posCell[i];\n                if (c < 0) continue;\n\n                int x = c / N, y = c % N;\n\n                if (hold[i]) {\n                    if (dst[c]) {\n                        dst[c] = 0;\n                        remDst--;\n                        sumDstX -= x;\n                        sumDstY -= y;\n                        hold[i] = 0;\n                        heldNow--;\n                    }\n                } else {\n                    if (src[c]) {\n                        src[c] = 0;\n                        remSrc--;\n                        sumSrcX -= x;\n                        sumSrcY -= y;\n                        hold[i] = 1;\n                        heldNow++;\n                    }\n                }\n            }\n\n            for (int i = 0; i < K; i++) {\n                if (plannedDone[i]) fixed[i] = false;\n            }\n        }\n    }\n\n    bool emergencySingleAction() {\n        if (abortedTime || abortedCutoff) return false;\n        if (timeUp()) { abortedTime = true; return false; }\n        if (cutoffReached()) { abortedCutoff = true; return false; }\n\n        if ((int)ops.size() >= 100000) return false;\n\n        // drop first\n        if (heldNow > 0 && remDst > 0) {\n            int bestTurns = INT_MAX, bestDist = INT_MAX;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf : leafPriority) if (hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (dst[c]) {\n                    int tx = rx[c], ty = ry[c];\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int dist = man(curX, curY, rr, cc);\n                        int rot = rotD[curDir[leaf]][d];\n                        int turns = max(dist, rot);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && dist < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = dist;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf >= 0) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        // then pick\n        if (remSrc > 0) {\n            int bestTurns = INT_MAX, bestDist = INT_MAX;\n            int bestLeaf = -1, bestDir = -1, bestCell = -1, bestRid = -1;\n\n            for (int leaf : leafPriority) if (!hold[leaf]) {\n                int L = len[leaf];\n                for (int c = 0; c < C; c++) if (src[c]) {\n                    int tx = rx[c], ty = ry[c];\n                    for (int d = 0; d < 4; d++) {\n                        int rr = tx - DX[d] * L;\n                        int cc = ty - DY[d] * L;\n                        if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;\n\n                        int dist = man(curX, curY, rr, cc);\n                        int rot = rotD[curDir[leaf]][d];\n                        int turns = max(dist, rot);\n                        if (turns == 0) turns = 1;\n\n                        if (turns < bestTurns || (turns == bestTurns && dist < bestDist)) {\n                            bestTurns = turns;\n                            bestDist = dist;\n                            bestLeaf = leaf;\n                            bestDir = d;\n                            bestCell = c;\n                            bestRid = rr * N + cc;\n                        }\n                    }\n                }\n            }\n\n            if (bestLeaf >= 0) {\n                vector<int> ad(K, -1), ac(K, -1);\n                ad[bestLeaf] = bestDir;\n                ac[bestLeaf] = bestCell;\n                executeMove(bestRid, ad, ac);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void plan() {\n        int safety = 0;\n        const int TOPK = (cfg.lookaheadMode ? 8 : 6);\n\n        while (!abortedTime && !abortedCutoff &&\n               (remDst > 0 || heldNow > 0) &&\n               (int)ops.size() < 100000 &&\n               safety < 250000) {\n            safety++;\n\n            if ((safety & 31) == 0) {\n                if (timeUp()) { abortedTime = true; break; }\n                if (cutoffReached()) { abortedCutoff = true; break; }\n            }\n\n            int emptyLeaves[MAXK], holdLeaves[MAXK];\n            int nE = 0, nH = 0;\n            for (int i = 0; i < K; i++) {\n                if (hold[i]) holdLeaves[nH++] = i;\n                else emptyLeaves[nE++] = i;\n            }\n\n            bool hasP = (remSrc > 0 && nE > 0);\n            bool hasD = (remDst > 0 && nH > 0);\n\n            if (!hasP && !hasD) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            int scx = remSrc ? (int)(sumSrcX / remSrc) : curX;\n            int scy = remSrc ? (int)(sumSrcY / remSrc) : curY;\n            int dcx = remDst ? (int)(sumDstX / remDst) : curX;\n            int dcy = remDst ? (int)(sumDstY / remDst) : curY;\n\n            // dynamic utility weights\n            int wPick = 100, wDrop = 100;\n            if (cfg.weightMode == 0) {\n                if (remSrc == 0) { wPick = 0; wDrop = 140; }\n                else if (remDst == 0) { wDrop = 0; wPick = 140; }\n                else {\n                    int targetHeld = (int)((long long)K * remDst / (remSrc + remDst));\n                    int diff = heldNow - targetHeld;\n                    if (diff > 0) wDrop += min(40, diff * 8);\n                    else wPick += min(40, (-diff) * 8);\n                    if (heldNow == 0) wPick += 10;\n                    if (heldNow == K) wDrop += 10;\n                }\n            } else if (cfg.weightMode == 1) {\n                if (remSrc == 0) { wPick = 0; wDrop = 150; }\n                else if (remDst == 0) { wDrop = 0; wPick = 135; }\n                else {\n                    int targetHeld = (int)((long long)K * remDst / (remSrc + remDst));\n                    int diff = heldNow - targetHeld;\n                    if (diff > 0) {\n                        wDrop += min(60, diff * 12);\n                        wPick -= min(20, diff * 4);\n                    } else {\n                        wPick += min(45, (-diff) * 10);\n                    }\n                    if (remDst < remSrc) wDrop += 10;\n                }\n                wPick = max(1, wPick);\n                wDrop = max(1, wDrop);\n            } else {\n                if (remSrc == 0) { wPick = 0; wDrop = 130; }\n                else if (remDst == 0) { wDrop = 0; wPick = 160; }\n                else {\n                    int targetHeld = (int)((long long)K * remDst / (remSrc + remDst));\n                    int diff = heldNow - targetHeld;\n                    if (diff < 0) {\n                        wPick += min(65, (-diff) * 12);\n                        wDrop -= min(15, (-diff) * 3);\n                    } else {\n                        wDrop += min(35, diff * 8);\n                    }\n                    if (remSrc > remDst) wPick += 10;\n                }\n                wPick = max(1, wPick);\n                wDrop = max(1, wDrop);\n            }\n\n            vector<Cand> top;\n            top.reserve(TOPK);\n            Cand immediateBest;\n\n            for (int rid = 0; rid < C; rid++) {\n                if ((rid & 127) == 0) {\n                    if (timeUp()) { abortedTime = true; break; }\n                    if (cutoffReached()) { abortedCutoff = true; break; }\n                }\n\n                int dist = man(curX, curY, rx[rid], ry[rid]);\n\n                if (dist <= 2) {\n                    MR p[3]{}, d[3]{};\n                    for (int l = 0; l <= 2; l++) {\n                        if (hasP) p[l] = matchGroup(rid, emptyLeaves, nE, src, l);\n                        if (hasD) d[l] = matchGroup(rid, holdLeaves, nH, dst, l);\n                    }\n\n                    int lpMax = hasP ? 2 : 0;\n                    int ldMax = hasD ? 2 : 0;\n\n                    for (int lp = 0; lp <= lpMax; lp++) {\n                        for (int ld = 0; ld <= ldMax; ld++) {\n                            int pick = hasP ? p[lp].cnt : 0;\n                            int drop = hasD ? d[ld].cnt : 0;\n                            int cnt = pick + drop;\n                            if (cnt == 0) continue;\n\n                            int R = max(hasP ? p[lp].rmax : 0, hasD ? d[ld].rmax : 0);\n                            int turns = max(dist, R);\n                            if (turns == 0) turns = 1;\n\n                            int held2 = heldNow + pick - drop;\n                            int pen = holdPenaltyAt(rid, held2, scx, scy, dcx, dcy);\n\n                            int rs2 = remSrc - pick;\n                            int rd2 = remDst - drop;\n                            int fut = 0;\n                            if (rd2 > 0 && held2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                            else if (rs2 > 0 && held2 < K) fut = man(rx[rid], ry[rid], scx, scy);\n                            else if (rd2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                            else if (rs2 > 0) fut = man(rx[rid], ry[rid], scx, scy);\n\n                            Cand c;\n                            c.ok = true;\n                            c.rid = rid;\n                            c.lp = lp;\n                            c.ld = ld;\n                            c.pick = pick;\n                            c.drop = drop;\n                            c.cnt = cnt;\n                            c.turns = turns;\n                            c.dist = dist;\n                            c.pen = pen;\n                            c.fut = fut;\n                            c.util = pick * wPick + drop * wDrop;\n                            c.rnd = candRnd(rid, pick, drop, turns);\n\n                            if (betterCand(c, immediateBest)) immediateBest = c;\n                            addTopCandidate(top, c, TOPK);\n                        }\n                    }\n                } else {\n                    MR pp{}, dd{};\n                    if (hasP) pp = matchGroup(rid, emptyLeaves, nE, src, 2);\n                    if (hasD) dd = matchGroup(rid, holdLeaves, nH, dst, 2);\n\n                    int pick = pp.cnt;\n                    int drop = dd.cnt;\n                    int cnt = pick + drop;\n                    if (cnt == 0) continue;\n\n                    int R = max(pp.rmax, dd.rmax);\n                    int turns = max(dist, R);\n                    if (turns == 0) turns = 1;\n\n                    int held2 = heldNow + pick - drop;\n                    int pen = holdPenaltyAt(rid, held2, scx, scy, dcx, dcy);\n\n                    int rs2 = remSrc - pick;\n                    int rd2 = remDst - drop;\n                    int fut = 0;\n                    if (rd2 > 0 && held2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                    else if (rs2 > 0 && held2 < K) fut = man(rx[rid], ry[rid], scx, scy);\n                    else if (rd2 > 0) fut = man(rx[rid], ry[rid], dcx, dcy);\n                    else if (rs2 > 0) fut = man(rx[rid], ry[rid], scx, scy);\n\n                    Cand c;\n                    c.ok = true;\n                    c.rid = rid;\n                    c.lp = hasP ? 2 : 0;\n                    c.ld = hasD ? 2 : 0;\n                    c.pick = pick;\n                    c.drop = drop;\n                    c.cnt = cnt;\n                    c.turns = turns;\n                    c.dist = dist;\n                    c.pen = pen;\n                    c.fut = fut;\n                    c.util = pick * wPick + drop * wDrop;\n                    c.rnd = candRnd(rid, pick, drop, turns);\n\n                    if (betterCand(c, immediateBest)) immediateBest = c;\n                    addTopCandidate(top, c, TOPK);\n                }\n            }\n\n            if (abortedTime || abortedCutoff) break;\n\n            if (!immediateBest.ok || top.empty()) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            Cand chosen = top[0];\n            vector<int> chosenDir, chosenCell;\n            int chosenActs = 0;\n            if (!buildAssignmentsFromCand(\n                    chosen, emptyLeaves, nE, holdLeaves, nH, hasP, hasD,\n                    chosenDir, chosenCell, chosenActs\n                )) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            if (cfg.lookaheadMode > 0 && (int)top.size() > 1) {\n                bool needLA = false;\n                for (int i = 1; i < (int)top.size(); i++) {\n                    if (isCloseCandidate(top[i], top[0])) {\n                        needLA = true;\n                        break;\n                    }\n                }\n\n                if (needLA) {\n                    vector<int> srcList, dstList;\n                    srcList.reserve(remSrc);\n                    dstList.reserve(remDst);\n                    for (int c = 0; c < C; c++) {\n                        if (src[c]) srcList.push_back(c);\n                        if (dst[c]) dstList.push_back(c);\n                    }\n\n                    int nextChosen = estimateNextSingleCost(\n                        chosen.rid, chosenDir, chosenCell, srcList, dstList\n                    );\n\n                    int laCoef = (cfg.lookaheadMode == 1 ? 10 : 14);\n\n                    for (int i = 1; i < (int)top.size(); i++) {\n                        const Cand& cand = top[i];\n                        if (!isCloseCandidate(cand, top[0])) continue;\n\n                        vector<int> ad, ac;\n                        int acts = 0;\n                        if (!buildAssignmentsFromCand(\n                                cand, emptyLeaves, nE, holdLeaves, nH, hasP, hasD,\n                                ad, ac, acts\n                            )) continue;\n\n                        int next = estimateNextSingleCost(\n                            cand.rid, ad, ac, srcList, dstList\n                        );\n\n                        long long lhs = 1LL * cand.util * (100LL * chosen.turns + 1LL * laCoef * nextChosen);\n                        long long rhs = 1LL * chosen.util * (100LL * cand.turns + 1LL * laCoef * next);\n\n                        bool better = false;\n                        if (lhs != rhs) better = lhs > rhs;\n                        else {\n                            if (betterCand(cand, chosen)) better = true;\n                            else if (!betterCand(chosen, cand) && next < nextChosen) better = true;\n                        }\n\n                        if (better) {\n                            chosen = cand;\n                            chosenDir.swap(ad);\n                            chosenCell.swap(ac);\n                            chosenActs = acts;\n                            nextChosen = next;\n                        }\n                    }\n                }\n            }\n\n            if (chosenActs <= 0) {\n                if (!emergencySingleAction()) break;\n                continue;\n            }\n\n            executeMove(chosen.rid, chosenDir, chosenCell);\n        }\n\n        while (!abortedTime && !abortedCutoff &&\n               (remDst > 0 || heldNow > 0) &&\n               (int)ops.size() < 100000) {\n            if (timeUp()) { abortedTime = true; break; }\n            if (cutoffReached()) { abortedCutoff = true; break; }\n            if (!emergencySingleAction()) break;\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> S(N), T(N);\n    for (int i = 0; i < N; i++) cin >> S[i];\n    for (int i = 0; i < N; i++) cin >> T[i];\n\n    int C = N * N;\n    vector<uint8_t> src0(C, 0), dst0(C, 0);\n    int remSrc0 = 0, remDst0 = 0;\n    long long sumSrcX0 = 0, sumSrcY0 = 0, sumDstX0 = 0, sumDstY0 = 0;\n\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y < N; y++) {\n            int c = x * N + y;\n            bool sv = (S[x][y] == '1');\n            bool tv = (T[x][y] == '1');\n            if (sv && !tv) {\n                src0[c] = 1;\n                remSrc0++;\n                sumSrcX0 += x;\n                sumSrcY0 += y;\n            } else if (!sv && tv) {\n                dst0[c] = 1;\n                remDst0++;\n                sumDstX0 += x;\n                sumDstY0 += y;\n            }\n        }\n    }\n\n    // input-based deterministic base seed\n    uint64_t baseSeed = 1469598103934665603ULL;\n    baseSeed = splitmix64(baseSeed ^ (uint64_t)N * 1315423911u ^ (uint64_t)V * 2654435761u);\n    for (int i = 0; i < N; i++) {\n        for (char ch : S[i]) baseSeed = splitmix64(baseSeed ^ (uint64_t)ch);\n        for (char ch : T[i]) baseSeed = splitmix64(baseSeed ^ (uint64_t)(ch + 131));\n    }\n\n    double t0 = nowMsGlobal();\n    const double SOFT_LIMIT_MS = 2620.0;\n    const double HARD_LIMIT_MS = 2860.0;\n    const long long INF = (1LL << 60);\n\n    vector<Config> cfgs = {\n        {0,0,0,1,1,2,0,0,0}, // baseline\n        {0,0,0,0,1,2,0,0,0}, // no lookahead\n        {0,1,0,0,1,2,0,0,0}, // drop-biased\n        {1,0,0,0,1,2,0,0,0}, // shorter spread\n        {0,0,1,1,1,2,0,0,0}, // short-first opportunistic\n        {2,0,0,0,1,2,0,0,0}, // mostly short + one long\n        {0,2,0,0,1,2,0,0,0}, // pick-biased\n        {1,1,0,1,1,2,0,0,0}, // shorter + drop + LA\n        {0,0,0,2,2,2,0,0,0}, // stronger LA + aggressive move\n        {0,1,0,1,1,1,0,0,0}, // drop-biased tighter pick cap\n        {0,0,0,0,0,3,1,0,0}, // conservative move + mixed init\n        {1,0,2,1,2,2,1,0,0}, // index opp + mixed init\n        {2,1,1,0,1,1,1,0,0}, // alt combo\n        {1,2,0,0,1,3,0,0,0}, // pick-biased + short spread\n        {0,1,1,0,2,1,1,0,0}, // drop + short-first + aggressive\n        {2,0,2,0,2,3,1,0,0}, // long+index+aggressive\n        {0,0,2,1,1,1,0,0,0}, // index opp + LA\n        {1,1,1,2,1,2,1,0,0}, // mixed\n        // tie-randomized variants\n        {0,0,0,1,1,2,0,1,0},\n        {0,1,0,0,1,2,0,1,0},\n        {1,0,1,1,1,2,1,1,0},\n        {2,0,2,0,2,2,1,1,0},\n    };\n\n    // deterministic random extras\n    uint64_t rng = splitmix64(baseSeed ^ 0x123456789abcdefULL);\n    for (int i = 0; i < 12; i++) {\n        rng = splitmix64(rng + i * 0x9e3779b97f4a7c15ULL);\n        Config c;\n        c.lenMode = (int)(rng % 3); rng = splitmix64(rng);\n        c.weightMode = (int)(rng % 3); rng = splitmix64(rng);\n        c.oppMode = (int)(rng % 3); rng = splitmix64(rng);\n        int rla = (int)(rng % 100); rng = splitmix64(rng);\n        c.lookaheadMode = (rla < 45 ? 0 : (rla < 85 ? 1 : 2));\n        c.moveMode = (int)(rng % 3); rng = splitmix64(rng);\n        c.pickMargin = 1 + (int)(rng % 3); rng = splitmix64(rng);\n        c.initMode = (int)(rng % 2); rng = splitmix64(rng);\n        c.tieMode = (int)(rng % 2); rng = splitmix64(rng);\n        c.seed = 0;\n        cfgs.push_back(c);\n    }\n\n    AttemptResult best;\n    double avgAttemptMs = 0.0;\n    int done = 0;\n\n    for (int i = 0; i < (int)cfgs.size(); i++) {\n        double elapsed = nowMsGlobal() - t0;\n        if (i > 0) {\n            double pred = (done > 0 ? avgAttemptMs : 230.0);\n            if (elapsed + pred * 1.12 > SOFT_LIMIT_MS) break;\n        }\n\n        Config cfg = cfgs[i];\n        if (cfg.seed == 0) cfg.seed = splitmix64(baseSeed ^ (uint64_t)(i + 1) * 0x9e3779b97f4a7c15ULL);\n\n        long long cutoff = best.score;\n\n        double s = nowMsGlobal();\n        Attempt solver(\n            N, V,\n            src0, dst0,\n            remSrc0, remDst0,\n            sumSrcX0, sumSrcY0, sumDstX0, sumDstY0,\n            cfg,\n            t0 + HARD_LIMIT_MS,\n            cutoff\n        );\n        AttemptResult cur = solver.run();\n        double e = nowMsGlobal();\n\n        double dt = e - s;\n        done++;\n        avgAttemptMs = (avgAttemptMs * (done - 1) + dt) / done;\n\n        if (cur.score < best.score) best = std::move(cur);\n\n        if (e - t0 > SOFT_LIMIT_MS) break;\n    }\n\n    // Fallback safety\n    if (best.score >= INF / 2) {\n        Config fallback{0,0,0,0,1,2,0,0,splitmix64(baseSeed ^ 0xabcddcbaULL)};\n        Attempt solver(\n            N, V,\n            src0, dst0,\n            remSrc0, remDst0,\n            sumSrcX0, sumSrcY0, sumDstX0, sumDstY0,\n            fallback,\n            t0 + HARD_LIMIT_MS,\n            INF\n        );\n        best = solver.run();\n    }\n\n    // Output best attempt\n    cout << V << '\\n';\n    for (int i = 0; i < V - 1; i++) {\n        cout << 0 << ' ' << best.len[i] << '\\n';\n    }\n    cout << best.initX << ' ' << best.initY << '\\n';\n    for (const string& s : best.ops) cout << s << '\\n';\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing atcoder::mf_graph;\nusing ll = long long;\n\nstruct Point {\n    int x, y;\n};\n\nstruct RectCand {\n    int val, x1, x2, y1, y2;\n};\n\nstruct Component {\n    vector<int> cells;\n    int score = 0;\n    int perim = 0;\n    int minx = INT_MAX, maxx = -1;\n    int miny = INT_MAX, maxy = -1;\n};\n\nclass Solver {\n    static constexpr int COORD_MAX = 100000;\n    static constexpr int PERIM_LIMIT = 400000;\n    static constexpr double SOFT_LIMIT = 1.82;\n    static constexpr int KEEP_CANDS = 18;\n\n    int N;\n    vector<Point> pts;\n    vector<int> wt; // +1 mackerel, -1 sardine\n\n    // grid state\n    int STEP = 500;\n    int W = 0, H = 0, C = 0;\n    int PmaxUnits = 0;\n\n    vector<int> raw;\n    vector<int> outsideSides;\n    vector<pair<int, int>> adjPairs;\n    vector<int> prefix;\n    vector<vector<int>> pointCandCells; // point -> candidate cells\n    vector<vector<int>> cellPoints;     // cell -> points influenced\n\n    struct PolyCand {\n        int estDiff;\n        uint64_t h;\n        vector<Point> poly;\n    };\n    vector<PolyCand> cands;\n\n    chrono::steady_clock::time_point st;\n\n    inline int id(int x, int y) const { return y * W + x; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    double remaining() const { return SOFT_LIMIT - elapsed(); }\n    bool time_over() const { return elapsed() >= SOFT_LIMIT; }\n\n    // ---------- hash ----------\n    static uint64_t splitmix64(uint64_t x) {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        return x ^ (x >> 31);\n    }\n\n    static ll area2(const vector<Point>& poly) {\n        ll s = 0;\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            s += 1LL * poly[i].x * poly[j].y - 1LL * poly[i].y * poly[j].x;\n        }\n        return s;\n    }\n\n    uint64_t hash_poly(const vector<Point>& poly) const {\n        uint64_t h1 = 0x123456789abcdefULL;\n        uint64_t h2 = 0xfedcba987654321ULL;\n\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            const Point& A = poly[i];\n            const Point& B = poly[(i + 1) % m];\n\n            uint64_t u = ((uint64_t)A.x << 17) | (uint64_t)A.y;\n            uint64_t v = ((uint64_t)B.x << 17) | (uint64_t)B.y;\n            if (u > v) swap(u, v);\n\n            uint64_t e = splitmix64(u * 0x9e3779b97f4a7c15ULL ^ v * 0xbf58476d1ce4e5b9ULL);\n            h1 ^= e;\n            h2 ^= splitmix64(e + 0x94d049bb133111ebULL + (h2 << 6) + (h2 >> 2));\n        }\n\n        uint64_t a = (uint64_t)llabs(area2(poly));\n        return splitmix64(h1 ^ (h2 << 1) ^ (uint64_t)m * 0x94d049bb133111ebULL ^ a);\n    }\n\n    int poly_quantum(const vector<Point>& poly) const {\n        int g = 0;\n        int m = (int)poly.size();\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            int len = abs(poly[i].x - poly[j].x) + abs(poly[i].y - poly[j].y);\n            g = std::gcd(g, len);\n        }\n        if (g <= 0) g = 1;\n        return g;\n    }\n\n    vector<int> shift_values(int q, bool rich) const {\n        vector<int> s = {0};\n        auto add = [&](int v) {\n            if (v <= 0) return;\n            s.push_back(v);\n            s.push_back(-v);\n        };\n\n        add(max(1, q / 2));\n        add(max(1, q / 4));\n        add(1);\n        add(2);\n        if (rich) {\n            add(max(1, q / 8));\n            add(3);\n        }\n\n        sort(s.begin(), s.end());\n        s.erase(unique(s.begin(), s.end()), s.end());\n\n        vector<pair<int, int>> tmp;\n        tmp.reserve(s.size());\n        for (int v : s) tmp.push_back({abs(v), v});\n        sort(tmp.begin(), tmp.end());\n\n        vector<int> out;\n        for (auto &kv : tmp) {\n            out.push_back(kv.second);\n            if ((int)out.size() >= 7) break;\n        }\n\n        bool has0 = false;\n        for (int v : out) if (v == 0) has0 = true;\n        if (!has0) {\n            out.push_back(0);\n            sort(out.begin(), out.end());\n            out.erase(unique(out.begin(), out.end()), out.end());\n        }\n        return out;\n    }\n\n    // ---------- Input ----------\n    void read_input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N;\n        pts.resize(2 * N);\n        wt.resize(2 * N);\n\n        for (int i = 0; i < 2 * N; i++) {\n            cin >> pts[i].x >> pts[i].y;\n            wt[i] = (i < N ? +1 : -1);\n        }\n    }\n\n    // ---------- Grid ----------\n    void build_grid(int step) {\n        STEP = step;\n        W = COORD_MAX / STEP;\n        H = COORD_MAX / STEP;\n        C = W * H;\n        PmaxUnits = PERIM_LIMIT / STEP;\n\n        raw.assign(C, 0);\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x / STEP;\n            int y = pts[i].y / STEP;\n            if (x >= W) x = W - 1;\n            if (y >= H) y = H - 1;\n            raw[id(x, y)] += wt[i];\n        }\n\n        outsideSides.assign(C, 0);\n        adjPairs.clear();\n        adjPairs.reserve(C * 2);\n\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int v = id(x, y);\n\n                int out = 0;\n                if (x == 0) out++;\n                if (x + 1 == W) out++;\n                if (y == 0) out++;\n                if (y + 1 == H) out++;\n                outsideSides[v] = out;\n\n                if (x + 1 < W) adjPairs.push_back({v, id(x + 1, y)});\n                if (y + 1 < H) adjPairs.push_back({v, id(x, y + 1)});\n            }\n        }\n\n        // prefix sum over raw\n        prefix.assign((W + 1) * (H + 1), 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int cur = raw[id(x, y)];\n                int A = prefix[y * (W + 1) + (x + 1)];\n                int B = prefix[(y + 1) * (W + 1) + x];\n                int D = prefix[y * (W + 1) + x];\n                prefix[(y + 1) * (W + 1) + (x + 1)] = cur + A + B - D;\n            }\n        }\n\n        // exact inclusion candidate cells for each point (boundary inclusive)\n        pointCandCells.assign(2 * N, {});\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            int qx = x / STEP, qy = y / STEP;\n\n            vector<int> xs, ys;\n            if (qx >= W) xs = {W - 1};\n            else if (x % STEP == 0 && qx > 0) xs = {qx - 1, qx};\n            else xs = {qx};\n\n            if (qy >= H) ys = {H - 1};\n            else if (y % STEP == 0 && qy > 0) ys = {qy - 1, qy};\n            else ys = {qy};\n\n            vector<int> cand;\n            cand.reserve(4);\n            for (int xx : xs) for (int yy : ys) {\n                int v = id(xx, yy);\n                bool dup = false;\n                for (int z : cand) if (z == v) { dup = true; break; }\n                if (!dup) cand.push_back(v);\n            }\n            pointCandCells[i] = move(cand);\n        }\n\n        // inverse map: cell -> points that this cell can affect\n        cellPoints.assign(C, {});\n        for (int i = 0; i < 2 * N; i++) {\n            for (int c : pointCandCells[i]) cellPoints[c].push_back(i);\n        }\n    }\n\n    int rect_sum(int x1, int y1, int x2, int y2) const {\n        if (x1 > x2 || y1 > y2) return 0;\n        x1 = max(x1, 0);\n        y1 = max(y1, 0);\n        x2 = min(x2, W - 1);\n        y2 = min(y2, H - 1);\n        if (x1 > x2 || y1 > y2) return 0;\n\n        int A = prefix[(y2 + 1) * (W + 1) + (x2 + 1)];\n        int B = prefix[y1 * (W + 1) + (x2 + 1)];\n        int Cc = prefix[(y2 + 1) * (W + 1) + x1];\n        int D = prefix[y1 * (W + 1) + x1];\n        return A - B - Cc + D;\n    }\n\n    vector<int> build_profit(int r) const {\n        vector<int> p(C, 0);\n        for (int y = 0; y < H; y++) {\n            for (int x = 0; x < W; x++) {\n                int v = id(x, y);\n                int s = rect_sum(x - r, y - r, x + r, y + r);\n                if (r == 0) p[v] = raw[v] * 20;\n                else p[v] = s * 8 + raw[v] * 4;\n            }\n        }\n        return p;\n    }\n\n    // ---------- Segmentation ----------\n    vector<char> segment_cut(const vector<int>& profit, int lambda) const {\n        vector<char> sel(C, 0);\n\n        if (lambda == 0) {\n            for (int i = 0; i < C; i++) sel[i] = (profit[i] > 0);\n            return sel;\n        }\n\n        int S = C, T = C + 1;\n        mf_graph<int> g(C + 2);\n\n        for (int v = 0; v < C; v++) {\n            int c1 = -profit[v] + lambda * outsideSides[v];\n            if (c1 >= 0) g.add_edge(v, T, c1);\n            else g.add_edge(S, v, -c1);\n        }\n\n        for (auto [u, v] : adjPairs) {\n            g.add_edge(u, v, lambda);\n            g.add_edge(v, u, lambda);\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n        for (int i = 0; i < C; i++) sel[i] = cut[i] ? 1 : 0;\n        return sel;\n    }\n\n    vector<Component> top_components(const vector<char>& sel, int K) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n        vector<Component> comps;\n        comps.reserve(64);\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n\n            Component cp;\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cp.cells.push_back(v);\n                cp.score += raw[v];\n\n                int x = v % W, y = v / W;\n                cp.minx = min(cp.minx, x);\n                cp.maxx = max(cp.maxx, x);\n                cp.miny = min(cp.miny, y);\n                cp.maxy = max(cp.maxy, y);\n\n                if (x == 0 || !sel[v - 1]) cp.perim++;\n                else if (!vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n\n                if (x + 1 == W || !sel[v + 1]) cp.perim++;\n                else if (!vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n\n                if (y == 0 || !sel[v - W]) cp.perim++;\n                else if (!vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n\n                if (y + 1 == H || !sel[v + W]) cp.perim++;\n                else if (!vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (cp.score > 0) comps.push_back(move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [&](const Component& a, const Component& b) {\n            if (a.score != b.score) return a.score > b.score;\n            if (a.perim != b.perim) return a.perim < b.perim;\n            return a.cells.size() > b.cells.size();\n        });\n\n        if ((int)comps.size() > K) comps.resize(K);\n        return comps;\n    }\n\n    int bbox_dist(const Component& a, const Component& b) const {\n        int dx = 0, dy = 0;\n        if (a.maxx < b.minx) dx = b.minx - a.maxx - 1;\n        else if (b.maxx < a.minx) dx = a.minx - b.maxx - 1;\n\n        if (a.maxy < b.miny) dy = b.miny - a.maxy - 1;\n        else if (b.maxy < a.miny) dy = a.miny - b.maxy - 1;\n\n        return dx + dy;\n    }\n\n    bool connect_components_fast(const Component& A, const Component& B, vector<char>& outSel) const {\n        outSel.assign(C, 0);\n\n        vector<char> inB(C, 0);\n        vector<int> parent(C, -1);\n        queue<int> q;\n\n        for (int v : A.cells) {\n            outSel[v] = 1;\n            parent[v] = -2;\n            q.push(v);\n        }\n        for (int v : B.cells) {\n            outSel[v] = 1;\n            inB[v] = 1;\n        }\n\n        int target = -1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (inB[v]) { target = v; break; }\n\n            int x = v % W, y = v / W;\n            auto relax = [&](int to) {\n                if (parent[to] == -1) {\n                    parent[to] = v;\n                    q.push(to);\n                }\n            };\n\n            if (x > 0) relax(v - 1);\n            if (x + 1 < W) relax(v + 1);\n            if (y > 0) relax(v - W);\n            if (y + 1 < H) relax(v + W);\n        }\n\n        if (target == -1) return false;\n\n        int cur = target;\n        while (parent[cur] != -2) {\n            outSel[cur] = 1;\n            cur = parent[cur];\n            if (cur < 0) return false;\n        }\n        outSel[cur] = 1;\n        return true;\n    }\n\n    bool connect_components_weighted(const Component& A, const Component& B, vector<char>& outSel) const {\n        outSel.assign(C, 0);\n        vector<char> inA(C, 0), inB(C, 0);\n\n        for (int v : A.cells) {\n            outSel[v] = 1;\n            inA[v] = 1;\n        }\n        for (int v : B.cells) {\n            outSel[v] = 1;\n            inB[v] = 1;\n        }\n\n        const int INF = 1e9;\n        vector<int> dist(C, INF), par(C, -1);\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n        for (int v : A.cells) {\n            dist[v] = 0;\n            par[v] = -2;\n            pq.push({0, v});\n        }\n\n        int HARD = PmaxUnits * 8 + 220;\n        int target = -1;\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            if (d > HARD) break;\n            if (inB[v]) { target = v; break; }\n\n            int x = v % W, y = v / W;\n            auto relax = [&](int to) {\n                int add = 0;\n                if (!(inA[to] || inB[to])) {\n                    int neg = max(0, -raw[to]);\n                    add = 1 + 3 * neg;\n                }\n                int nd = d + add;\n                if (nd < dist[to] && nd <= HARD) {\n                    dist[to] = nd;\n                    par[to] = v;\n                    pq.push({nd, to});\n                }\n            };\n\n            if (x > 0) relax(v - 1);\n            if (x + 1 < W) relax(v + 1);\n            if (y > 0) relax(v - W);\n            if (y + 1 < H) relax(v + W);\n        }\n\n        if (target == -1) return false;\n\n        int cur = target;\n        while (par[cur] != -2) {\n            outSel[cur] = 1;\n            cur = par[cur];\n            if (cur < 0) return false;\n        }\n        outSel[cur] = 1;\n        return true;\n    }\n\n    // ---------- region utilities ----------\n    int count_nb(const vector<char>& sel, int v) const {\n        int x = v % W, y = v / W;\n        int c = 0;\n        if (x > 0 && sel[v - 1]) c++;\n        if (x + 1 < W && sel[v + 1]) c++;\n        if (y > 0 && sel[v - W]) c++;\n        if (y + 1 < H && sel[v + W]) c++;\n        return c;\n    }\n\n    pair<int, int> score_perim(const vector<char>& sel) const {\n        int sc = 0, per = 0;\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            sc += raw[v];\n            int x = v % W, y = v / W;\n            if (x == 0 || !sel[v - 1]) per++;\n            if (x + 1 == W || !sel[v + 1]) per++;\n            if (y == 0 || !sel[v - W]) per++;\n            if (y + 1 == H || !sel[v + W]) per++;\n        }\n        return {sc, per};\n    }\n\n    void enforce_single_component_basic(vector<char>& sel) const {\n        vector<char> vis(C, 0);\n        queue<int> q;\n\n        int compCnt = 0;\n        int bestSc = INT_MIN;\n        vector<int> bestCells;\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n            compCnt++;\n\n            vector<int> cells;\n            int sc = 0;\n\n            vis[s] = 1;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                cells.push_back(v);\n                sc += raw[v];\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && !vis[v - 1]) { vis[v - 1] = 1; q.push(v - 1); }\n                if (x + 1 < W && sel[v + 1] && !vis[v + 1]) { vis[v + 1] = 1; q.push(v + 1); }\n                if (y > 0 && sel[v - W] && !vis[v - W]) { vis[v - W] = 1; q.push(v - W); }\n                if (y + 1 < H && sel[v + W] && !vis[v + W]) { vis[v + W] = 1; q.push(v + W); }\n            }\n\n            if (sc > bestSc) {\n                bestSc = sc;\n                bestCells = move(cells);\n            }\n        }\n\n        if (compCnt <= 1) return;\n        fill(sel.begin(), sel.end(), 0);\n        for (int v : bestCells) sel[v] = 1;\n    }\n\n    // smarter selection: exact point-based component score + optional merge\n    void enforce_single_component_smart(vector<char>& sel) const {\n        if (remaining() < 0.03) {\n            enforce_single_component_basic(sel);\n            return;\n        }\n\n        vector<char> vis(C, 0);\n        vector<int> cid(C, -1);\n        queue<int> q;\n        vector<Component> comps;\n        comps.reserve(16);\n\n        for (int s = 0; s < C; s++) {\n            if (!sel[s] || vis[s]) continue;\n\n            int cc = (int)comps.size();\n            comps.push_back(Component());\n\n            vis[s] = 1;\n            cid[s] = cc;\n            q.push(s);\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                auto &cp = comps[cc];\n                cp.cells.push_back(v);\n                cp.score += raw[v];\n\n                int x = v % W, y = v / W;\n                cp.minx = min(cp.minx, x);\n                cp.maxx = max(cp.maxx, x);\n                cp.miny = min(cp.miny, y);\n                cp.maxy = max(cp.maxy, y);\n\n                auto relax = [&](int to) {\n                    if (sel[to] && !vis[to]) {\n                        vis[to] = 1;\n                        cid[to] = cc;\n                        q.push(to);\n                    }\n                };\n\n                if (x > 0) relax(v - 1);\n                if (x + 1 < W) relax(v + 1);\n                if (y > 0) relax(v - W);\n                if (y + 1 < H) relax(v + W);\n            }\n        }\n\n        int compCnt = (int)comps.size();\n        if (compCnt <= 1) return;\n\n        // exact per-component score\n        vector<int> compExact(compCnt, 0);\n        vector<int> mark(compCnt, 0);\n        int token = 1;\n\n        for (int i = 0; i < 2 * N; i++) {\n            token++;\n            if (token == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                token = 1;\n            }\n\n            for (int c : pointCandCells[i]) {\n                if (!sel[c]) continue;\n                int cc = cid[c];\n                if (cc >= 0 && mark[cc] != token) {\n                    mark[cc] = token;\n                    compExact[cc] += wt[i];\n                }\n            }\n        }\n\n        vector<int> ord(compCnt);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (compExact[a] != compExact[b]) return compExact[a] > compExact[b];\n            if (comps[a].score != comps[b].score) return comps[a].score > comps[b].score;\n            return (int)comps[a].cells.size() > (int)comps[b].cells.size();\n        });\n\n        int a = ord[0];\n        vector<char> bestSel(C, 0);\n        for (int v : comps[a].cells) bestSel[v] = 1;\n        int bestD = compExact[a];\n\n        // optional merge with next best components\n        if (remaining() > 0.055 && compCnt <= 6) {\n            int trials = min(2, compCnt - 1);\n            for (int t = 1; t <= trials; t++) {\n                int b = ord[t];\n                if (compExact[b] <= 0) continue;\n\n                int d = bbox_dist(comps[a], comps[b]);\n                if (d > max(4, PmaxUnits / 3)) continue;\n\n                vector<char> merged;\n                bool ok = false;\n                if (remaining() > 0.10) ok = connect_components_weighted(comps[a], comps[b], merged);\n                if (!ok) ok = connect_components_fast(comps[a], comps[b], merged);\n                if (!ok) continue;\n\n                auto [sc, per] = score_perim(merged);\n                (void)sc;\n                if (per > PmaxUnits) continue;\n\n                int ex = exact_diff(merged);\n                if (ex > bestD) {\n                    bestD = ex;\n                    bestSel.swap(merged);\n                }\n            }\n        }\n\n        sel.swap(bestSel);\n    }\n\n    void fill_holes(vector<char>& sel) const {\n        int minx = W, miny = H, maxx = -1, maxy = -1;\n        for (int v = 0; v < C; v++) if (sel[v]) {\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        if (maxx < minx) return;\n\n        int bw = maxx - minx + 1;\n        int bh = maxy - miny + 1;\n        int LW = bw + 2;\n        int LH = bh + 2;\n\n        vector<char> blocked(LW * LH, 0), vis(LW * LH, 0);\n\n        for (int y = miny; y <= maxy; y++) {\n            for (int x = minx; x <= maxx; x++) {\n                int gv = id(x, y);\n                if (sel[gv]) {\n                    int lx = (x - minx) + 1;\n                    int ly = (y - miny) + 1;\n                    blocked[ly * LW + lx] = 1;\n                }\n            }\n        }\n\n        queue<int> q;\n        auto push_if = [&](int lx, int ly) {\n            int t = ly * LW + lx;\n            if (!blocked[t] && !vis[t]) {\n                vis[t] = 1;\n                q.push(t);\n            }\n        };\n\n        for (int x = 0; x < LW; x++) {\n            push_if(x, 0);\n            push_if(x, LH - 1);\n        }\n        for (int y = 0; y < LH; y++) {\n            push_if(0, y);\n            push_if(LW - 1, y);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            int x = v % LW, y = v / LW;\n            if (x > 0) push_if(x - 1, y);\n            if (x + 1 < LW) push_if(x + 1, y);\n            if (y > 0) push_if(x, y - 1);\n            if (y + 1 < LH) push_if(x, y + 1);\n        }\n\n        for (int ly = 1; ly <= bh; ly++) {\n            for (int lx = 1; lx <= bw; lx++) {\n                int t = ly * LW + lx;\n                if (!blocked[t] && !vis[t]) {\n                    int gx = minx + (lx - 1);\n                    int gy = miny + (ly - 1);\n                    sel[id(gx, gy)] = 1;\n                }\n            }\n        }\n    }\n\n    void resolve_diagonal_crosses(vector<char>& sel) const {\n        for (int it = 0; it < 2; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < H; y++) {\n                for (int x = 0; x + 1 < W; x++) {\n                    int a = id(x, y);\n                    int b = id(x + 1, y);\n                    int c = id(x, y + 1);\n                    int d = id(x + 1, y + 1);\n\n                    if (sel[a] && sel[d] && !sel[b] && !sel[c]) {\n                        sel[(raw[b] >= raw[c]) ? b : c] = 1;\n                        changed = true;\n                    } else if (!sel[a] && !sel[d] && sel[b] && sel[c]) {\n                        sel[(raw[a] >= raw[d]) ? a : d] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void refine(vector<char>& sel) const {\n        auto sp = score_perim(sel);\n        int perim = sp.second;\n\n        // remove non-positive leaves\n        queue<int> q;\n        for (int v = 0; v < C; v++) {\n            if (sel[v] && raw[v] <= 0 && count_nb(sel, v) <= 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            if (!sel[v]) continue;\n\n            int deg = count_nb(sel, v);\n            if (raw[v] <= 0 && deg <= 1) {\n                sel[v] = 0;\n                perim += (-4 + 2 * deg);\n\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1] && raw[v - 1] <= 0 && count_nb(sel, v - 1) <= 1) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1] && raw[v + 1] <= 0 && count_nb(sel, v + 1) <= 1) q.push(v + 1);\n                if (y > 0 && sel[v - W] && raw[v - W] <= 0 && count_nb(sel, v - W) <= 1) q.push(v - W);\n                if (y + 1 < H && sel[v + W] && raw[v + W] <= 0 && count_nb(sel, v + W) <= 1) q.push(v + W);\n            }\n        }\n\n        // if perimeter too high, remove leaves with least loss\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> leafPQ;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) {\n            leafPQ.push({raw[v], v});\n        }\n\n        while (perim > PmaxUnits && !leafPQ.empty()) {\n            auto [rw, v] = leafPQ.top();\n            leafPQ.pop();\n            (void)rw;\n\n            if (!sel[v]) continue;\n            int deg = count_nb(sel, v);\n            if (deg > 1) continue;\n\n            sel[v] = 0;\n            perim += (-4 + 2 * deg);\n\n            int x = v % W, y = v / W;\n            if (x > 0 && sel[v - 1] && count_nb(sel, v - 1) <= 1) leafPQ.push({raw[v - 1], v - 1});\n            if (x + 1 < W && sel[v + 1] && count_nb(sel, v + 1) <= 1) leafPQ.push({raw[v + 1], v + 1});\n            if (y > 0 && sel[v - W] && count_nb(sel, v - W) <= 1) leafPQ.push({raw[v - W], v - W});\n            if (y + 1 < H && sel[v + W] && count_nb(sel, v + W) <= 1) leafPQ.push({raw[v + W], v + W});\n        }\n\n        // frontier growth\n        priority_queue<pair<int, int>> pq;\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty()) {\n            int v = pq.top().second;\n            pq.pop();\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            bool take = false;\n            if (raw[v] > 0) take = true;\n            else if (raw[v] == 0 && dP <= 0) take = true;\n            else if (raw[v] >= -1 && dP <= -2) take = true;\n\n            if (!take) continue;\n\n            sel[v] = 1;\n            perim += dP;\n\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n    }\n\n    // ---------- exact diff on selected cells ----------\n    int exact_diff(const vector<char>& sel) const {\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            bool inside = false;\n            for (int c : pointCandCells[i]) {\n                if (sel[c]) { inside = true; break; }\n            }\n            if (inside) diff += wt[i];\n        }\n        return diff;\n    }\n\n    int delta_add_cell(int v, const vector<int>& cov) const {\n        int d = 0;\n        for (int pi : cellPoints[v]) if (cov[pi] == 0) d += wt[pi];\n        return d;\n    }\n\n    int delta_remove_cell(int v, const vector<int>& cov) const {\n        int d = 0;\n        for (int pi : cellPoints[v]) if (cov[pi] == 1) d -= wt[pi];\n        return d;\n    }\n\n    void apply_add_cell(int v, vector<int>& cov) const {\n        for (int pi : cellPoints[v]) cov[pi]++;\n    }\n\n    void apply_remove_cell(int v, vector<int>& cov) const {\n        for (int pi : cellPoints[v]) cov[pi]--;\n    }\n\n    // local exact polish\n    void exact_polish(vector<char>& sel) const {\n        if (remaining() < 0.055) return;\n\n        vector<int> cov(2 * N, 0);\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            for (int pi : cellPoints[v]) cov[pi]++;\n        }\n\n        auto sp = score_perim(sel);\n        int perim = sp.second;\n\n        int maxMoves = (STEP <= 500 ? 320 : 220);\n        if (remaining() > 0.30) maxMoves += 120;\n        if (remaining() < 0.12) maxMoves = max(120, maxMoves / 2);\n\n        int moves = 0;\n\n        queue<int> q;\n        for (int v = 0; v < C; v++) if (sel[v] && count_nb(sel, v) <= 1) q.push(v);\n\n        auto try_remove = [&](int v) -> bool {\n            if (!sel[v]) return false;\n            int deg = count_nb(sel, v);\n            if (deg > 1) return false;\n\n            int dP = -4 + 2 * deg;\n            int d = delta_remove_cell(v, cov);\n\n            bool take = false;\n            if (d > 0) take = true;\n            else if (d == 0 && dP < 0) take = true;\n            else if (perim > PmaxUnits && d >= -1) take = true;\n\n            if (!take) return false;\n\n            sel[v] = 0;\n            perim += dP;\n            apply_remove_cell(v, cov);\n            moves++;\n            return true;\n        };\n\n        while (!q.empty() && moves < maxMoves && remaining() > 0.02) {\n            int v = q.front(); q.pop();\n            if (try_remove(v)) {\n                int x = v % W, y = v / W;\n                if (x > 0 && sel[v - 1]) q.push(v - 1);\n                if (x + 1 < W && sel[v + 1]) q.push(v + 1);\n                if (y > 0 && sel[v - W]) q.push(v - W);\n                if (y + 1 < H && sel[v + W]) q.push(v + W);\n            }\n        }\n\n        priority_queue<pair<int, int>> pq;\n        auto push_frontier = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n\n        while (!pq.empty() && moves < maxMoves && remaining() > 0.02) {\n            int v = pq.top().second;\n            pq.pop();\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            int d = delta_add_cell(v, cov);\n\n            bool take = false;\n            if (d > 0) take = true;\n            else if (d == 0 && dP < 0) take = true;\n            else if (d >= -1 && dP <= -4 && remaining() > 0.12) take = true;\n\n            if (!take) continue;\n\n            sel[v] = 1;\n            perim += dP;\n            apply_add_cell(v, cov);\n            moves++;\n\n            int x = v % W, y = v / W;\n            if (x > 0) push_frontier(v - 1);\n            if (x + 1 < W) push_frontier(v + 1);\n            if (y > 0) push_frontier(v - W);\n            if (y + 1 < H) push_frontier(v + W);\n        }\n    }\n\n    vector<Point> cells_to_polygon(const vector<char>& sel) const {\n        const int SHIFT = 20;\n        auto key = [&](int x, int y) -> ll { return (ll(x) << SHIFT) | ll(y); };\n        auto decode = [&](ll k) -> Point {\n            return Point{int(k >> SHIFT), int(k & ((1LL << SHIFT) - 1))};\n        };\n\n        unordered_map<ll, ll> nxt;\n        unordered_map<ll, int> indeg;\n        nxt.reserve(12000);\n        indeg.reserve(12000);\n\n        bool bad = false;\n        auto add_edge = [&](ll a, ll b) {\n            auto it = nxt.find(a);\n            if (it != nxt.end() && it->second != b) {\n                bad = true;\n                return;\n            }\n            nxt[a] = b;\n            indeg[b]++;\n        };\n\n        for (int v = 0; v < C; v++) if (sel[v]) {\n            int cx = v % W, cy = v / W;\n            int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n            int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n\n            if (cy == 0 || !sel[v - W]) add_edge(key(x0, y0), key(x1, y0));\n            if (cx + 1 == W || !sel[v + 1]) add_edge(key(x1, y0), key(x1, y1));\n            if (cy + 1 == H || !sel[v + W]) add_edge(key(x1, y1), key(x0, y1));\n            if (cx == 0 || !sel[v - 1]) add_edge(key(x0, y1), key(x0, y0));\n\n            if (bad) return {};\n        }\n\n        if (nxt.empty()) return {};\n\n        for (auto &kv : nxt) {\n            ll a = kv.first;\n            if (indeg[a] != 1) return {};\n        }\n        for (auto &kv : indeg) {\n            if (kv.second != 1) return {};\n            if (!nxt.count(kv.first)) return {};\n        }\n\n        unordered_set<ll> used;\n        used.reserve(nxt.size() * 2 + 1);\n\n        vector<Point> best;\n        ll bestA = -1;\n\n        for (auto &kv : nxt) {\n            ll start = kv.first;\n            if (used.count(start)) continue;\n\n            unordered_set<ll> local;\n            local.reserve(nxt.size() * 2 + 1);\n\n            vector<Point> cyc;\n            ll cur = start;\n            bool ok = true;\n\n            while (true) {\n                if (local.count(cur)) {\n                    if (cur == start) break;\n                    ok = false;\n                    break;\n                }\n\n                local.insert(cur);\n                used.insert(cur);\n\n                auto it = nxt.find(cur);\n                if (it == nxt.end()) { ok = false; break; }\n\n                cyc.push_back(decode(cur));\n                cur = it->second;\n\n                if ((int)cyc.size() > (int)nxt.size() + 5) {\n                    ok = false;\n                    break;\n                }\n            }\n\n            if (!ok || (int)cyc.size() < 4) continue;\n\n            ll a = llabs(area2(cyc));\n            if (a > bestA) {\n                bestA = a;\n                best = move(cyc);\n            }\n        }\n\n        if (best.empty()) return {};\n\n        // remove collinear vertices\n        bool changed = true;\n        while (changed && best.size() > 4) {\n            changed = false;\n            int m = (int)best.size();\n            vector<Point> np;\n            np.reserve(m);\n\n            for (int i = 0; i < m; i++) {\n                Point a = best[(i - 1 + m) % m];\n                Point b = best[i];\n                Point c = best[(i + 1) % m];\n\n                if ((a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y)) {\n                    changed = true;\n                    continue;\n                }\n                np.push_back(b);\n            }\n\n            if (np.size() < 4) break;\n            best.swap(np);\n        }\n\n        return best;\n    }\n\n    bool basic_valid(const vector<Point>& poly) const {\n        int m = (int)poly.size();\n        if (m < 4 || m > 1000) return false;\n\n        const int SHIFT = 20;\n        unordered_set<ll> seen;\n        seen.reserve(m * 2);\n\n        ll per = 0;\n        for (int i = 0; i < m; i++) {\n            int x = poly[i].x, y = poly[i].y;\n            if (x < 0 || x > COORD_MAX || y < 0 || y > COORD_MAX) return false;\n\n            ll k = (ll(x) << SHIFT) | ll(y);\n            if (seen.count(k)) return false;\n            seen.insert(k);\n\n            int j = (i + 1) % m;\n            int x2 = poly[j].x, y2 = poly[j].y;\n            if (x != x2 && y != y2) return false;\n\n            ll len = llabs((ll)x - x2) + llabs((ll)y - y2);\n            if (len <= 0) return false;\n            per += len;\n        }\n\n        if (per > PERIM_LIMIT) return false;\n        if (area2(poly) == 0) return false;\n        return true;\n    }\n\n    struct Seg {\n        int x1, y1, x2, y2;\n        bool vert;\n    };\n\n    static bool overlap1d(int a, int b, int c, int d) {\n        if (a > b) swap(a, b);\n        if (c > d) swap(c, d);\n        return max(a, c) <= min(b, d);\n    }\n\n    static bool seg_intersect(const Seg& A, const Seg& B) {\n        if (A.vert && B.vert) {\n            if (A.x1 != B.x1) return false;\n            return overlap1d(A.y1, A.y2, B.y1, B.y2);\n        }\n        if (!A.vert && !B.vert) {\n            if (A.y1 != B.y1) return false;\n            return overlap1d(A.x1, A.x2, B.x1, B.x2);\n        }\n\n        const Seg& V = A.vert ? A : B;\n        const Seg& Hs = A.vert ? B : A;\n\n        int vx = V.x1;\n        int hy = Hs.y1;\n        int hxL = min(Hs.x1, Hs.x2), hxR = max(Hs.x1, Hs.x2);\n        int vyL = min(V.y1, V.y2), vyR = max(V.y1, V.y2);\n\n        return (hxL <= vx && vx <= hxR && vyL <= hy && hy <= vyR);\n    }\n\n    bool final_valid(const vector<Point>& poly) const {\n        if (!basic_valid(poly)) return false;\n        int m = (int)poly.size();\n\n        vector<Seg> edges(m);\n        for (int i = 0; i < m; i++) {\n            int j = (i + 1) % m;\n            edges[i] = Seg{\n                poly[i].x, poly[i].y,\n                poly[j].x, poly[j].y,\n                (poly[i].x == poly[j].x)\n            };\n        }\n\n        for (int i = 0; i < m; i++) {\n            for (int j = i + 1; j < m; j++) {\n                if ((i + 1) % m == j) continue;\n                if ((j + 1) % m == i) continue;\n                if (seg_intersect(edges[i], edges[j])) return false;\n            }\n        }\n        return true;\n    }\n\n    // ---------- Exact score on polygon ----------\n    bool point_in_poly_inclusive(int x, int y, const vector<Point>& poly) const {\n        bool inside = false;\n        int m = (int)poly.size();\n\n        for (int i = 0; i < m; i++) {\n            Point a = poly[i];\n            Point b = poly[(i + 1) % m];\n\n            if (a.y == b.y) { // horizontal\n                int lx = min(a.x, b.x), rx = max(a.x, b.x);\n                if (y == a.y && lx <= x && x <= rx) return true;\n            } else { // vertical\n                int xv = a.x;\n                int ly = min(a.y, b.y), ry = max(a.y, b.y);\n\n                if (x == xv && ly <= y && y <= ry) return true; // boundary\n                if (ly <= y && y < ry && x < xv) inside = !inside;\n            }\n        }\n        return inside;\n    }\n\n    int exact_diff_polygon(const vector<Point>& poly) const {\n        int minx = COORD_MAX, miny = COORD_MAX, maxx = 0, maxy = 0;\n        for (auto &p : poly) {\n            minx = min(minx, p.x);\n            maxx = max(maxx, p.x);\n            miny = min(miny, p.y);\n            maxy = max(maxy, p.y);\n        }\n\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x < minx || x > maxx || y < miny || y > maxy) continue;\n            if (point_in_poly_inclusive(x, y, poly)) diff += wt[i];\n        }\n        return diff;\n    }\n\n    int exact_diff_polygon_shifted(const vector<Point>& poly, int dx, int dy,\n                                   int minx, int maxx, int miny, int maxy) const {\n        int bx0 = minx + dx, bx1 = maxx + dx;\n        int by0 = miny + dy, by1 = maxy + dy;\n\n        int diff = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x < bx0 || x > bx1 || y < by0 || y > by1) continue;\n            if (point_in_poly_inclusive(x - dx, y - dy, poly)) diff += wt[i];\n        }\n        return diff;\n    }\n\n    // ---------- candidate management ----------\n    int worst_kept_diff() const {\n        if ((int)cands.size() < KEEP_CANDS) return INT_MIN / 2;\n        return cands.back().estDiff;\n    }\n\n    void add_poly_candidate(int diff, vector<Point> poly) {\n        if (!basic_valid(poly)) return;\n        uint64_t h = hash_poly(poly);\n\n        for (auto &cd : cands) {\n            if (cd.h == h) {\n                if (cd.estDiff >= diff - 1) return;\n                cd.estDiff = diff;\n                cd.poly = move(poly);\n                sort(cands.begin(), cands.end(), [](const PolyCand& a, const PolyCand& b) {\n                    if (a.estDiff != b.estDiff) return a.estDiff > b.estDiff;\n                    return a.poly.size() < b.poly.size();\n                });\n                return;\n            }\n        }\n\n        cands.push_back({diff, h, move(poly)});\n        sort(cands.begin(), cands.end(), [](const PolyCand& a, const PolyCand& b) {\n            if (a.estDiff != b.estDiff) return a.estDiff > b.estDiff;\n            return a.poly.size() < b.poly.size();\n        });\n        if ((int)cands.size() > KEEP_CANDS) cands.resize(KEEP_CANDS);\n    }\n\n    // ---------- generators ----------\n    vector<int> top_seed_cells(int K) const {\n        vector<int> idx(C);\n        iota(idx.begin(), idx.end(), 0);\n        sort(idx.begin(), idx.end(), [&](int a, int b) {\n            return raw[a] > raw[b];\n        });\n\n        vector<int> seeds;\n        seeds.reserve(K);\n\n        for (int v : idx) {\n            if (raw[v] <= 0) break;\n            int x = v % W, y = v / W;\n            bool ok = true;\n            for (int s : seeds) {\n                int sx = s % W, sy = s / W;\n                if (abs(x - sx) + abs(y - sy) < 4) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) seeds.push_back(v);\n            if ((int)seeds.size() >= K) break;\n        }\n\n        if (seeds.empty()) {\n            int best = (int)(max_element(raw.begin(), raw.end()) - raw.begin());\n            seeds.push_back(best);\n        }\n        return seeds;\n    }\n\n    vector<char> grow_from_seed(int seed, int mode) const {\n        vector<char> sel(C, 0);\n        sel[seed] = 1;\n        int perim = 4;\n\n        priority_queue<pair<int, int>> pq;\n        auto push_if = [&](int v) {\n            if (v < 0 || v >= C || sel[v]) return;\n            if (count_nb(sel, v) > 0) pq.push({raw[v], v});\n        };\n\n        int x = seed % W, y = seed / W;\n        if (x > 0) push_if(seed - 1);\n        if (x + 1 < W) push_if(seed + 1);\n        if (y > 0) push_if(seed - W);\n        if (y + 1 < H) push_if(seed + W);\n\n        while (!pq.empty()) {\n            int v = pq.top().second;\n            pq.pop();\n            if (sel[v]) continue;\n\n            int adj = count_nb(sel, v);\n            if (adj == 0) continue;\n\n            int dP = 4 - 2 * adj;\n            if (perim + dP > PmaxUnits) continue;\n\n            bool take = false;\n            if (raw[v] > 0) take = true;\n            else if (raw[v] == 0 && dP <= 0) take = true;\n            else if (mode == 1 && raw[v] >= -1 && dP <= -2) take = true;\n\n            if (!take) continue;\n\n            sel[v] = 1;\n            perim += dP;\n\n            int cx = v % W, cy = v / W;\n            if (cx > 0) push_if(v - 1);\n            if (cx + 1 < W) push_if(v + 1);\n            if (cy > 0) push_if(v - W);\n            if (cy + 1 < H) push_if(v + W);\n        }\n\n        return sel;\n    }\n\n    vector<RectCand> best_rectangles(int K, double breakRemain) const {\n        struct CmpMin {\n            bool operator()(const RectCand& a, const RectCand& b) const {\n                return a.val > b.val;\n            }\n        };\n\n        priority_queue<RectCand, vector<RectCand>, CmpMin> pq;\n        vector<int> acc(H, 0), ps(H + 1, 0);\n\n        for (int x1 = 0; x1 < W; x1++) {\n            if ((x1 & 7) == 0 && remaining() < breakRemain) break;\n\n            fill(acc.begin(), acc.end(), 0);\n\n            for (int x2 = x1; x2 < W; x2++) {\n                for (int y = 0; y < H; y++) acc[y] += raw[id(x2, y)];\n\n                int wcell = x2 - x1 + 1;\n                int L = PmaxUnits / 2 - wcell;\n                if (L < 1) break;\n\n                ps[0] = 0;\n                for (int y = 0; y < H; y++) ps[y + 1] = ps[y] + acc[y];\n\n                deque<int> dq;\n                int best = INT_MIN;\n                int bl = 0, br = 0;\n\n                for (int j = 1; j <= H; j++) {\n                    int add = j - 1;\n                    while (!dq.empty() && ps[dq.back()] >= ps[add]) dq.pop_back();\n                    dq.push_back(add);\n\n                    int lim = j - L;\n                    while (!dq.empty() && dq.front() < lim) dq.pop_front();\n\n                    if (!dq.empty()) {\n                        int val = ps[j] - ps[dq.front()];\n                        if (val > best) {\n                            best = val;\n                            bl = dq.front();\n                            br = j;\n                        }\n                    }\n                }\n\n                if (best <= 0 || br <= bl) continue;\n                RectCand rc{best, x1, x2, bl, br - 1};\n\n                if ((int)pq.size() < K) pq.push(rc);\n                else if (rc.val > pq.top().val) {\n                    pq.pop();\n                    pq.push(rc);\n                }\n            }\n        }\n\n        vector<RectCand> out;\n        while (!pq.empty()) {\n            out.push_back(pq.top());\n            pq.pop();\n        }\n        sort(out.begin(), out.end(), [](const RectCand& a, const RectCand& b) {\n            return a.val > b.val;\n        });\n        return out;\n    }\n\n    // ---------- fallback ----------\n    int rect_diff(int x0, int x1, int y0, int y1) const {\n        int d = 0;\n        for (int i = 0; i < 2 * N; i++) {\n            int x = pts[i].x, y = pts[i].y;\n            if (x0 <= x && x <= x1 && y0 <= y && y <= y1) d += wt[i];\n        }\n        return d;\n    }\n\n    vector<Point> cell_rect_poly(int v) const {\n        int cx = v % W, cy = v / W;\n        int x0 = cx * STEP, x1 = (cx + 1) * STEP;\n        int y0 = cy * STEP, y1 = (cy + 1) * STEP;\n        return {{x0, y0}, {x1, y0}, {x1, y1}, {x0, y1}};\n    }\n\n    pair<vector<Point>, int> best_tiny_fallback() const {\n        const int SHIFT = 20;\n        auto key = [&](int x, int y) -> ll {\n            return (ll(x) << SHIFT) | ll(y);\n        };\n\n        unordered_map<ll, int> mp;\n        mp.reserve(30000);\n        for (int i = 0; i < 2 * N; i++) {\n            mp[key(pts[i].x, pts[i].y)] += wt[i];\n        }\n\n        auto getw = [&](int x, int y) -> int {\n            auto it = mp.find(key(x, y));\n            return (it == mp.end() ? 0 : it->second);\n        };\n\n        int best = -1e9;\n        vector<Point> poly;\n\n        for (int i = 0; i < N; i++) {\n            int x = pts[i].x;\n            int y = pts[i].y;\n\n            for (int x0 : {x - 1, x}) {\n                if (x0 < 0 || x0 + 1 > COORD_MAX) continue;\n                for (int y0 : {y - 1, y}) {\n                    if (y0 < 0 || y0 + 1 > COORD_MAX) continue;\n\n                    int d = 0;\n                    d += getw(x0, y0);\n                    d += getw(x0 + 1, y0);\n                    d += getw(x0, y0 + 1);\n                    d += getw(x0 + 1, y0 + 1);\n\n                    if (d > best) {\n                        best = d;\n                        poly = {\n                            {x0, y0},\n                            {x0 + 1, y0},\n                            {x0 + 1, y0 + 1},\n                            {x0, y0 + 1}\n                        };\n                    }\n                }\n            }\n        }\n\n        if (poly.empty()) {\n            poly = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n            best = 0;\n        }\n        return {poly, best};\n    }\n\n    // ---------- new seed-pair candidates ----------\n    vector<int> seed_block_cells(int seed, int rad) const {\n        int cx = seed % W, cy = seed / W;\n        int x1 = max(0, cx - rad), x2 = min(W - 1, cx + rad);\n        int y1 = max(0, cy - rad), y2 = min(H - 1, cy + rad);\n\n        vector<int> cells;\n        cells.reserve((x2 - x1 + 1) * (y2 - y1 + 1));\n        for (int y = y1; y <= y2; y++) {\n            for (int x = x1; x <= x2; x++) {\n                cells.push_back(id(x, y));\n            }\n        }\n        return cells;\n    }\n\n    Component build_component_from_cells(const vector<int>& cells) const {\n        Component cp;\n        cp.cells = cells;\n        cp.score = 0;\n        cp.minx = INT_MAX; cp.maxx = -1;\n        cp.miny = INT_MAX; cp.maxy = -1;\n\n        for (int v : cells) {\n            cp.score += raw[v];\n            int x = v % W, y = v / W;\n            cp.minx = min(cp.minx, x);\n            cp.maxx = max(cp.maxx, x);\n            cp.miny = min(cp.miny, y);\n            cp.maxy = max(cp.maxy, y);\n        }\n        return cp;\n    }\n\n    void add_pair_seed_candidates(const vector<int>& seeds, bool rich) {\n        if ((int)seeds.size() < 2) return;\n\n        int k = min((int)seeds.size(), rich ? 4 : 3);\n        for (int i = 0; i < k; i++) {\n            for (int j = i + 1; j < k; j++) {\n                if (remaining() < 0.03) return;\n\n                int s1 = seeds[i], s2 = seeds[j];\n                int x1 = s1 % W, y1 = s1 / W;\n                int x2 = s2 % W, y2 = s2 / W;\n\n                if (abs(x1 - x2) + abs(y1 - y2) < 4) continue;\n\n                int rad = rich ? 1 : 0;\n                auto c1 = seed_block_cells(s1, rad);\n                auto c2 = seed_block_cells(s2, rad);\n\n                vector<char> used(C, 0);\n                for (int v : c1) used[v] = 1;\n\n                vector<int> c2u;\n                c2u.reserve(c2.size());\n                for (int v : c2) if (!used[v]) c2u.push_back(v);\n\n                if (c2u.empty()) continue;\n\n                Component A = build_component_from_cells(c1);\n                Component B = build_component_from_cells(c2u);\n                if (A.score <= 0 || B.score <= 0) continue;\n\n                int d = bbox_dist(A, B);\n                if (d > max(4, PmaxUnits / 2)) continue;\n\n                vector<char> merged;\n                bool ok = false;\n                if (remaining() > 0.08) ok = connect_components_weighted(A, B, merged);\n                if (!ok) ok = connect_components_fast(A, B, merged);\n                if (!ok) continue;\n\n                consider_candidate(merged);\n\n                if (rich && remaining() > 0.05) {\n                    vector<char> plus = merged;\n                    auto add_block = [&](int s, int rr) {\n                        int cx = s % W, cy = s / W;\n                        int xx1 = max(0, cx - rr), xx2 = min(W - 1, cx + rr);\n                        int yy1 = max(0, cy - rr), yy2 = min(H - 1, cy + rr);\n                        for (int y = yy1; y <= yy2; y++) {\n                            for (int x = xx1; x <= xx2; x++) plus[id(x, y)] = 1;\n                        }\n                    };\n                    add_block(s1, 2);\n                    add_block(s2, 2);\n                    consider_candidate(move(plus));\n                }\n            }\n        }\n    }\n\n    // ---------- candidate pipeline ----------\n    void consider_candidate(vector<char> sel) {\n        if (time_over()) return;\n\n        bool any = false;\n        for (char b : sel) if (b) { any = true; break; }\n        if (!any) return;\n\n        // IMPORTANT: use smart selection early (when time allows),\n        // so we don't discard potentially good merge opportunities.\n        if (remaining() > 0.085) enforce_single_component_smart(sel);\n        else enforce_single_component_basic(sel);\n\n        resolve_diagonal_crosses(sel);\n        refine(sel);\n\n        if (remaining() > 0.02) fill_holes(sel);\n        resolve_diagonal_crosses(sel);\n\n        if (remaining() > 0.065) enforce_single_component_smart(sel);\n        else enforce_single_component_basic(sel);\n\n        if (remaining() > 0.03) refine(sel);\n\n        auto sp0 = score_perim(sel);\n        int sc0 = sp0.first, per0 = sp0.second;\n        if (per0 <= 0 || per0 > PmaxUnits) return;\n\n        if (remaining() > 0.060 && C <= 50000 &&\n            ((int)cands.size() < KEEP_CANDS || sc0 >= worst_kept_diff() - 80)) {\n            exact_polish(sel);\n            if (remaining() > 0.02) fill_holes(sel);\n            resolve_diagonal_crosses(sel);\n            if (remaining() > 0.04) enforce_single_component_smart(sel);\n            else enforce_single_component_basic(sel);\n        }\n\n        auto sp = score_perim(sel);\n        int per = sp.second;\n        if (per <= 0 || per > PmaxUnits) return;\n        if (remaining() < 0.010) return;\n\n        int diff = exact_diff(sel);\n        if ((int)cands.size() >= KEEP_CANDS && diff < worst_kept_diff() - 4) return;\n\n        auto poly = cells_to_polygon(sel);\n        if (poly.empty()) return;\n        add_poly_candidate(diff, move(poly));\n    }\n\n    void run_search_on_current_grid(bool mainMode, bool allowCut, bool quickMode) {\n        if (time_over()) return;\n\n        vector<int> seeds;\n        if (remaining() > 0.05) seeds = top_seed_cells(mainMode ? 5 : 4);\n\n        int bestCell = 0;\n        for (int i = 1; i < C; i++) if (raw[i] > raw[bestCell]) bestCell = i;\n        if (raw[bestCell] > 0) {\n            vector<char> sel(C, 0);\n            sel[bestCell] = 1;\n            consider_candidate(move(sel));\n        }\n\n        // single-cell seeds\n        if (!seeds.empty()) {\n            int lim = min((int)seeds.size(), mainMode ? 3 : 2);\n            for (int i = 0; i < lim; i++) {\n                if (remaining() < 0.03) break;\n                if (raw[seeds[i]] <= 0) continue;\n                vector<char> sel(C, 0);\n                sel[seeds[i]] = 1;\n                consider_candidate(move(sel));\n            }\n        }\n\n        // new pair-seed corridor candidates\n        if ((int)seeds.size() >= 2 && remaining() > (quickMode ? 0.06 : 0.08)) {\n            add_pair_seed_candidates(seeds, mainMode && !quickMode);\n        }\n\n        // raw-threshold dense components\n        {\n            vector<int> ths;\n            if (quickMode) ths = {2};\n            else ths = (mainMode ? vector<int>{3, 2} : vector<int>{2});\n\n            for (int th : ths) {\n                if (remaining() < 0.05) break;\n\n                vector<char> hi(C, 0);\n                bool any = false;\n                for (int v = 0; v < C; v++) {\n                    if (raw[v] >= th) {\n                        hi[v] = 1;\n                        any = true;\n                    }\n                }\n                if (!any) continue;\n\n                auto comps = top_components(hi, mainMode ? 3 : 2);\n                for (auto &cp : comps) {\n                    if (remaining() < 0.03) break;\n                    vector<char> sel(C, 0);\n                    for (int v : cp.cells) sel[v] = 1;\n                    consider_candidate(move(sel));\n                }\n\n                if ((int)comps.size() >= 2 && remaining() > 0.10) {\n                    int d = bbox_dist(comps[0], comps[1]);\n                    if (d <= max(3, PmaxUnits / 4)) {\n                        vector<char> merged;\n                        bool ok = false;\n                        if (remaining() > 0.14) ok = connect_components_weighted(comps[0], comps[1], merged);\n                        if (!ok) ok = connect_components_fast(comps[0], comps[1], merged);\n                        if (ok) consider_candidate(move(merged));\n                    }\n                }\n            }\n        }\n\n        // local blocks around seeds\n        if (!seeds.empty() && remaining() > 0.06) {\n            int lim = min((int)seeds.size(), mainMode ? 3 : 2);\n            for (int i = 0; i < lim; i++) {\n                if (remaining() < 0.03) break;\n                int s = seeds[i];\n                int cx = s % W, cy = s / W;\n\n                int rad = 1;\n                int x1 = max(0, cx - rad), x2 = min(W - 1, cx + rad);\n                int y1 = max(0, cy - rad), y2 = min(H - 1, cy + rad);\n\n                vector<char> sel(C, 0);\n                for (int y = y1; y <= y2; y++) {\n                    for (int x = x1; x <= x2; x++) sel[id(x, y)] = 1;\n                }\n                consider_candidate(move(sel));\n\n                if (mainMode && !quickMode && i == 0 && remaining() > 0.08) {\n                    int r2 = 2;\n                    int xx1 = max(0, cx - r2), xx2 = min(W - 1, cx + r2);\n                    int yy1 = max(0, cy - r2), yy2 = min(H - 1, cy + r2);\n\n                    vector<char> sel2(C, 0);\n                    for (int y = yy1; y <= yy2; y++) {\n                        for (int x = xx1; x <= xx2; x++) sel2[id(x, y)] = 1;\n                    }\n                    consider_candidate(move(sel2));\n                }\n            }\n        }\n\n        // seed growth\n        if (!seeds.empty() && remaining() > (mainMode ? 0.10 : 0.07)) {\n            int lim = min((int)seeds.size(), mainMode ? 4 : 3);\n            if (quickMode) lim = min(lim, 2);\n\n            for (int i = 0; i < lim; i++) {\n                if (remaining() < 0.04) break;\n                auto a = grow_from_seed(seeds[i], 0);\n                consider_candidate(move(a));\n\n                bool doMode1 = false;\n                if (!quickMode) {\n                    if (mainMode && remaining() > 0.13) doMode1 = true;\n                    if (!mainMode && i == 0 && remaining() > 0.10) doMode1 = true;\n                } else {\n                    if (i == 0 && remaining() > 0.11) doMode1 = true;\n                }\n\n                if (doMode1) {\n                    auto b = grow_from_seed(seeds[i], 1);\n                    consider_candidate(move(b));\n                }\n            }\n        }\n\n        if (quickMode) {\n            // cheap extra diversity: lam=0-like smoothed masks (no maxflow)\n            if (remaining() > 0.045) {\n                int MR = (C > 120000 ? 1 : 2);\n                if (remaining() > 0.16) MR = 2;\n                for (int r = 0; r <= MR; r++) {\n                    if (remaining() < 0.02) break;\n                    auto pr = build_profit(r);\n\n                    vector<char> s(C, 0);\n                    for (int v = 0; v < C; v++) if (pr[v] > 0) s[v] = 1;\n                    auto c1 = top_components(s, 2);\n                    for (auto &cp : c1) {\n                        if (remaining() < 0.02) break;\n                        vector<char> cs(C, 0);\n                        for (int v : cp.cells) cs[v] = 1;\n                        consider_candidate(move(cs));\n                    }\n\n                    int thr = (r == 0 ? 20 : (r == 1 ? 28 : 40));\n                    vector<char> s2(C, 0);\n                    bool any = false;\n                    for (int v = 0; v < C; v++) {\n                        if (pr[v] > thr) {\n                            s2[v] = 1;\n                            any = true;\n                        }\n                    }\n                    if (any) {\n                        auto c2 = top_components(s2, 2);\n                        for (auto &cp : c2) {\n                            if (remaining() < 0.02) break;\n                            vector<char> cs(C, 0);\n                            for (int v : cp.cells) cs[v] = 1;\n                            consider_candidate(move(cs));\n                        }\n                    }\n                }\n            }\n            return;\n        }\n\n        // graph-cut family\n        if (allowCut && remaining() > 0.10) {\n            vector<pair<int, int>> params;\n            if (mainMode && STEP == 500) {\n                params = {\n                    {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0},\n                    {0, 4}, {1, 8}, {2, 12}, {0, 10}, {2, 16}\n                };\n                if (remaining() > 0.48) params.push_back({1, 14});\n                if (remaining() > 0.62) params.push_back({3, 18});\n            } else if (STEP == 625) {\n                params = {\n                    {0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0},\n                    {0, 5}, {1, 9}\n                };\n                if (remaining() > 0.36) params.push_back({2, 12});\n            } else { // 1000\n                params = {\n                    {0, 0}, {1, 0}, {2, 0}, {3, 0},\n                    {0, 4}\n                };\n            }\n\n            int maxR = 0;\n            for (auto [r, _] : params) maxR = max(maxR, r);\n            vector<vector<int>> profits(maxR + 1);\n            vector<char> built(maxR + 1, 0);\n\n            for (auto [r, lam] : params) {\n                if (time_over()) break;\n                if (lam > 0) {\n                    double need = (STEP <= 500 ? 0.11 : (STEP <= 625 ? 0.08 : 0.06));\n                    if (remaining() < need) break;\n                } else {\n                    if (remaining() < 0.02) break;\n                }\n\n                if (!built[r]) {\n                    profits[r] = build_profit(r);\n                    built[r] = 1;\n                }\n\n                auto sel = segment_cut(profits[r], lam);\n                auto comps = top_components(sel, mainMode ? 4 : 3);\n\n                int take = min((mainMode ? 3 : 2), (int)comps.size());\n                for (int i = 0; i < take; i++) {\n                    if (remaining() < 0.03) break;\n                    vector<char> cs(C, 0);\n                    for (int v : comps[i].cells) cs[v] = 1;\n                    consider_candidate(move(cs));\n                }\n\n                // lam=0 thresholded selections\n                if (lam == 0 && mainMode && r >= 2 && remaining() > 0.05) {\n                    vector<int> ths = {20, 40};\n                    if (r >= 3) ths.push_back(60);\n\n                    for (int thr : ths) {\n                        vector<char> s2(C, 0);\n                        bool any = false;\n                        for (int v = 0; v < C; v++) {\n                            if (profits[r][v] > thr) {\n                                s2[v] = 1;\n                                any = true;\n                            }\n                        }\n                        if (!any) continue;\n\n                        auto c2 = top_components(s2, 2);\n                        for (auto &cp : c2) {\n                            if (remaining() < 0.03) break;\n                            vector<char> cs2(C, 0);\n                            for (int v : cp.cells) cs2[v] = 1;\n                            consider_candidate(move(cs2));\n                        }\n                    }\n                }\n\n                auto try_merge = [&](const Component& A, const Component& B) {\n                    vector<char> merged;\n                    bool ok = false;\n                    if (remaining() > (mainMode ? 0.16 : 0.12)) ok = connect_components_weighted(A, B, merged);\n                    if (!ok) ok = connect_components_fast(A, B, merged);\n                    if (ok) consider_candidate(move(merged));\n                };\n\n                if ((int)comps.size() >= 2 && remaining() > (mainMode ? 0.11 : 0.09)) {\n                    bool tryJoin = (lam == 0 || lam >= 8);\n                    if (tryJoin) {\n                        int d = bbox_dist(comps[0], comps[1]);\n                        int lim = max(3, PmaxUnits / (mainMode ? 3 : 4));\n                        if (d <= lim) try_merge(comps[0], comps[1]);\n                    }\n                }\n\n                if (mainMode && (int)comps.size() >= 3 && lam >= 12 && remaining() > 0.14) {\n                    int d = bbox_dist(comps[0], comps[2]);\n                    if (d <= max(4, PmaxUnits / 4)) try_merge(comps[0], comps[2]);\n                }\n            }\n        }\n\n        // rectangles\n        if (remaining() > (mainMode ? 0.11 : 0.08)) {\n            int K = mainMode ? (remaining() > 0.45 ? 7 : 6) : 3;\n            double br = mainMode ? 0.10 : 0.07;\n            auto rects = best_rectangles(K, br);\n\n            for (auto &rc : rects) {\n                if (remaining() < 0.035) break;\n\n                vector<char> sel(C, 0);\n                for (int y = rc.y1; y <= rc.y2; y++) {\n                    for (int x = rc.x1; x <= rc.x2; x++) sel[id(x, y)] = 1;\n                }\n                consider_candidate(move(sel));\n            }\n        }\n    }\n\n    void translation_hillclimb(vector<Point>& poly, int& curScore) {\n        if (remaining() < 0.012) return;\n        if (!basic_valid(poly)) return;\n\n        int q = poly_quantum(poly);\n        vector<int> steps = {max(1, q / 4), max(1, q / 8), max(1, q / 16), 2, 1};\n        sort(steps.begin(), steps.end());\n        steps.erase(unique(steps.begin(), steps.end()), steps.end());\n        sort(steps.rbegin(), steps.rend());\n\n        int budget = 20;\n        if (remaining() > 0.15) budget = 48;\n        else if (remaining() > 0.08) budget = 32;\n        int evals = 0;\n\n        const int DX[8] = {1,-1,0,0,1,1,-1,-1};\n        const int DY[8] = {0,0,1,-1,1,-1,1,-1};\n\n        for (int stp : steps) {\n            int iter = 0;\n            while (iter < 5 && evals < budget && remaining() > 0.004) {\n                iter++;\n\n                int minx = COORD_MAX, miny = COORD_MAX, maxx = 0, maxy = 0;\n                for (auto &p : poly) {\n                    minx = min(minx, p.x);\n                    maxx = max(maxx, p.x);\n                    miny = min(miny, p.y);\n                    maxy = max(maxy, p.y);\n                }\n\n                int localBest = curScore;\n                int bdx = 0, bdy = 0;\n\n                for (int k = 0; k < 8; k++) {\n                    if (evals >= budget || remaining() < 0.004) break;\n                    int dx = DX[k] * stp;\n                    int dy = DY[k] * stp;\n\n                    if (minx + dx < 0 || maxx + dx > COORD_MAX) continue;\n                    if (miny + dy < 0 || maxy + dy > COORD_MAX) continue;\n\n                    evals++;\n                    int sc = exact_diff_polygon_shifted(poly, dx, dy, minx, maxx, miny, maxy);\n                    if (sc > localBest) {\n                        localBest = sc;\n                        bdx = dx;\n                        bdy = dy;\n                    }\n                }\n\n                if (localBest > curScore) {\n                    curScore = localBest;\n                    for (auto &p : poly) {\n                        p.x += bdx;\n                        p.y += bdy;\n                    }\n                } else {\n                    break;\n                }\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        st = chrono::steady_clock::now();\n\n        read_input();\n\n        // main grid first\n        build_grid(500);\n\n        auto [tinyPoly, tinyDiff] = best_tiny_fallback();\n\n        int bestCell = (int)(max_element(raw.begin(), raw.end()) - raw.begin());\n        auto cellPoly = cell_rect_poly(bestCell);\n        int cellDiff = rect_diff(cellPoly[0].x, cellPoly[1].x, cellPoly[0].y, cellPoly[2].y);\n\n        add_poly_candidate(tinyDiff, tinyPoly);\n        add_poly_candidate(cellDiff, cellPoly);\n\n        run_search_on_current_grid(true, true, false);\n\n        if (remaining() > 0.30) {\n            build_grid(625);\n            run_search_on_current_grid(false, true, false);\n        }\n\n        // fine quick passes\n        bool ran400 = false;\n        if (remaining() > 0.36) {\n            build_grid(400);\n            run_search_on_current_grid(false, false, true);\n            ran400 = true;\n        }\n        if (remaining() > 0.24) {\n            build_grid(250);\n            run_search_on_current_grid(false, false, true);\n        } else if (!ran400 && remaining() > 0.18) {\n            build_grid(400);\n            run_search_on_current_grid(false, false, true);\n        }\n\n        if (remaining() > 0.13) {\n            build_grid(1000);\n            bool cut1000 = (remaining() > 0.22);\n            run_search_on_current_grid(false, cut1000, false);\n        }\n\n        // final choose by true polygon score + translation refinement\n        vector<Point> ans = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n        int bestTrue = -1e9;\n\n        vector<pair<int, vector<Point>>> bases;\n        bases.reserve(2 + cands.size());\n        bases.push_back({tinyDiff, tinyPoly});\n        bases.push_back({cellDiff, cellPoly});\n        for (auto &cd : cands) bases.push_back({cd.estDiff, cd.poly});\n\n        sort(bases.begin(), bases.end(), [](auto &a, auto &b) {\n            return a.first > b.first;\n        });\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(bases.size() * 2 + 1);\n\n        auto refine_translation = [&](const vector<Point>& base, int baseScore,\n                                      int& gBest, vector<Point>& gAns) {\n            if (remaining() < 0.03) return;\n            if ((int)base.size() > 400) return;\n\n            int minx = COORD_MAX, miny = COORD_MAX, maxx = 0, maxy = 0;\n            for (auto &p : base) {\n                minx = min(minx, p.x);\n                maxx = max(maxx, p.x);\n                miny = min(miny, p.y);\n                maxy = max(maxy, p.y);\n            }\n\n            auto in_bounds = [&](int dx, int dy) -> bool {\n                if (minx + dx < 0 || maxx + dx > COORD_MAX) return false;\n                if (miny + dy < 0 || maxy + dy > COORD_MAX) return false;\n                return true;\n            };\n\n            int q = poly_quantum(base);\n            bool rich = (remaining() > 0.09);\n            auto shifts = shift_values(q, rich);\n\n            int evalBudget = 28;\n            if (remaining() > 0.16) evalBudget = 48;\n            else if (remaining() > 0.10) evalBudget = 36;\n            int evals = 0;\n\n            auto eval_shift = [&](int dx, int dy) -> int {\n                if (!in_bounds(dx, dy)) return INT_MIN / 4;\n                if (evals >= evalBudget) return INT_MIN / 4;\n                if (remaining() < 0.008) return INT_MIN / 4;\n                evals++;\n                return exact_diff_polygon_shifted(base, dx, dy, minx, maxx, miny, maxy);\n            };\n\n            int bestDx = 0, bestDy = 0;\n            int bestSc = baseScore;\n\n            // coarse around zero\n            for (int dx : shifts) {\n                if (remaining() < 0.01 || evals >= evalBudget) break;\n                for (int dy : shifts) {\n                    if (dx == 0 && dy == 0) continue;\n                    int sc = eval_shift(dx, dy);\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestDx = dx;\n                        bestDy = dy;\n                    }\n                    if (evals >= evalBudget || remaining() < 0.01) break;\n                }\n            }\n\n            // local hill around best\n            vector<int> steps;\n            auto add_step = [&](int s) { if (s > 0) steps.push_back(s); };\n            add_step(q / 8);\n            add_step(q / 16);\n            add_step(q / 32);\n            add_step(2);\n            add_step(1);\n            sort(steps.begin(), steps.end());\n            steps.erase(unique(steps.begin(), steps.end()), steps.end());\n            sort(steps.rbegin(), steps.rend());\n\n            const int DX[8] = {1,-1,0,0,1,1,-1,-1};\n            const int DY[8] = {0,0,1,-1,1,-1,1,-1};\n\n            for (int stp : steps) {\n                if (evals >= evalBudget || remaining() < 0.01) break;\n\n                for (int iter = 0; iter < 2; iter++) {\n                    int localBest = bestSc;\n                    int ndx = bestDx, ndy = bestDy;\n\n                    for (int k = 0; k < 8; k++) {\n                        int dx = bestDx + DX[k] * stp;\n                        int dy = bestDy + DY[k] * stp;\n                        int sc = eval_shift(dx, dy);\n                        if (sc > localBest) {\n                            localBest = sc;\n                            ndx = dx;\n                            ndy = dy;\n                        }\n                        if (evals >= evalBudget || remaining() < 0.01) break;\n                    }\n\n                    if (localBest > bestSc) {\n                        bestSc = localBest;\n                        bestDx = ndx;\n                        bestDy = ndy;\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (bestSc > gBest) {\n                vector<Point> tp = base;\n                for (auto &p : tp) {\n                    p.x += bestDx;\n                    p.y += bestDy;\n                }\n                gBest = bestSc;\n                gAns = move(tp);\n            }\n        };\n\n        int transLimit = (remaining() > 0.20 ? 6 : (remaining() > 0.12 ? 4 : 3));\n        int transUsed = 0;\n\n        for (auto &bp : bases) {\n            if (remaining() < 0.004) break;\n\n            const vector<Point>& poly = bp.second;\n            if (!basic_valid(poly)) continue;\n\n            uint64_t h = hash_poly(poly);\n            if (!seen.insert(h).second) continue;\n\n            if (!final_valid(poly)) continue;\n\n            int td = exact_diff_polygon(poly);\n            if (td > bestTrue) {\n                bestTrue = td;\n                ans = poly;\n            }\n\n            if (transUsed < transLimit) {\n                refine_translation(poly, td, bestTrue, ans);\n                transUsed++;\n            }\n        }\n\n        // final local hill-climb on chosen answer\n        if (final_valid(ans) && remaining() > 0.012) {\n            translation_hillclimb(ans, bestTrue);\n        }\n\n        if (!final_valid(ans)) {\n            if (final_valid(tinyPoly)) ans = tinyPoly;\n            else ans = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n        }\n\n        cout << ans.size() << '\\n';\n        for (auto &p : ans) {\n            cout << p.x << ' ' << p.y << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconstexpr int MAXN = 105;\nconstexpr ll INF64 = (1LL << 60);\n\nconstexpr ll TRUE_MIN = 10000;\nconstexpr ll TRUE_MAX = 100000;\nconstexpr ll L_MAX = 50000;\n\nconstexpr double INV_SQRT2 = 0.70710678118654752440;\nconstexpr double INV_SQRT_2PI = 0.39894228040143267794;\n\nstatic inline uint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nstruct FastRNG {\n    uint64_t x;\n    bool has_spare = false;\n    double spare = 0.0;\n\n    explicit FastRNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next_u64() {\n        return splitmix64(x += 0x9e3779b97f4a7c15ULL);\n    }\n\n    double uniform01() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next_u64() % (uint64_t)(r - l + 1));\n    }\n\n    double normal01() {\n        if (has_spare) {\n            has_spare = false;\n            return spare;\n        }\n        double u, v, s;\n        do {\n            u = uniform01() * 2.0 - 1.0;\n            v = uniform01() * 2.0 - 1.0;\n            s = u * u + v * v;\n        } while (s >= 1.0 || s == 0.0);\n        double m = sqrt(-2.0 * log(s) / s);\n        spare = v * m;\n        has_spare = true;\n        return u * m;\n    }\n};\n\ninline ll clamp_ll(ll v, ll lo, ll hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\ninline bool overlap(ll l1, ll r1, ll l2, ll r2) {\n    return (l1 < r2) && (l2 < r1);\n}\n\ninline double normal_pdf(double z) {\n    return INV_SQRT_2PI * exp(-0.5 * z * z);\n}\n\ninline double normal_cdf(double z) {\n    return 0.5 * erfc(-z * INV_SQRT2);\n}\n\n// Mean of N(mu,sd^2) truncated to [a,b]\ndouble trunc_normal_mean(double mu, double sd, double a, double b) {\n    if (sd <= 1e-12) return min(max(mu, a), b);\n    double alpha = (a - mu) / sd;\n    double beta  = (b - mu) / sd;\n    double Za = normal_cdf(alpha);\n    double Zb = normal_cdf(beta);\n    double Z = Zb - Za;\n    if (Z < 1e-14) return min(max(mu, a), b);\n    double m = mu + sd * (normal_pdf(alpha) - normal_pdf(beta)) / Z;\n    if (m < a) m = a;\n    if (m > b) m = b;\n    return m;\n}\n\nstruct Operation {\n    uint8_t r = 0; // rotate\n    uint8_t d = 0; // 0:U, 1:L\n    int b = -1;\n};\n\nstruct GreedyParam {\n    double gap_w = 0.35;\n    double bal_w = 0.006;\n    double noise_w = 0.0;\n};\n\nstruct BeamParam {\n    int beam_width = 32;\n    int keep_leaves = 12;\n    double gap_w = 0.35;\n    double bal_w = 0.006;\n    double noise_w = 0.0;\n};\n\nstruct Scenario {\n    vector<ll> w, h;\n};\n\nstruct Candidate {\n    vector<Operation> ops;\n    vector<ll> predW, predH, predS;\n    double avg = 1e100;\n    double spread = 0.0;\n    uint64_t hash = 0;\n};\n\ndouble lower_bound_wh(ll curW, ll curH, double totalA, double sqrtA) {\n    double w = (double)curW, h = (double)curH;\n    if (w * h >= totalA) return w + h;\n    double c1 = w + max(h, totalA / max(1.0, w));\n    double c2 = h + max(w, totalA / max(1.0, h));\n    double c3 = 1e100;\n    if (w <= sqrtA && h <= sqrtA) c3 = 2.0 * sqrtA;\n    return min(c1, min(c2, c3));\n}\n\npair<ll, ll> simulate_layout(\n    const vector<ll>& baseW, const vector<ll>& baseH, const vector<Operation>& ops\n) {\n    int N = (int)ops.size();\n    ll x[MAXN] = {}, y[MAXN] = {}, w[MAXN] = {}, h[MAXN] = {};\n    ll BW = 0, BH = 0;\n\n    for (int i = 0; i < N; i++) {\n        const auto& op = ops[i];\n        ll wi = op.r ? baseH[i] : baseW[i];\n        ll hi = op.r ? baseW[i] : baseH[i];\n\n        ll xi = 0, yi = 0;\n        if (op.d == 0) { // U\n            xi = (op.b == -1) ? 0 : (x[op.b] + w[op.b]);\n            ll xr = xi + wi;\n            yi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(xi, xr, x[j], x[j] + w[j])) yi = max(yi, y[j] + h[j]);\n            }\n        } else { // L\n            yi = (op.b == -1) ? 0 : (y[op.b] + h[op.b]);\n            ll yb = yi + hi;\n            xi = 0;\n            for (int j = 0; j < i; j++) {\n                if (overlap(yi, yb, y[j], y[j] + h[j])) xi = max(xi, x[j] + w[j]);\n            }\n        }\n\n        x[i] = xi; y[i] = yi; w[i] = wi; h[i] = hi;\n        BW = max(BW, xi + wi);\n        BH = max(BH, yi + hi);\n    }\n\n    return {BW, BH};\n}\n\ninline ll score_on_base(const vector<ll>& w, const vector<ll>& h, const vector<Operation>& ops) {\n    auto [W, H] = simulate_layout(w, h, ops);\n    return W + H;\n}\n\nvector<Operation> build_linear_chain(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal, bool minimize_cross\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (minimize_cross) {\n            if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n            else r = (h[i] < w[i]) ? 1 : 0;\n        }\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 0 : 1), (i == 0 ? -1 : i - 1)};\n    }\n    return ops;\n}\n\nvector<Operation> build_single_stack(\n    const vector<ll>& w, const vector<ll>& h, bool horizontal\n) {\n    int N = (int)w.size();\n    vector<Operation> ops(N);\n    for (int i = 0; i < N; i++) {\n        int r = 0;\n        if (horizontal) r = (w[i] < h[i]) ? 1 : 0;\n        else r = (h[i] < w[i]) ? 1 : 0;\n        ops[i] = Operation{(uint8_t)r, (uint8_t)(horizontal ? 1 : 0), -1};\n    }\n    return ops;\n}\n\nvector<Operation> build_greedy(\n    const vector<ll>& baseW, const vector<ll>& baseH, const GreedyParam& param, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n    vector<Operation> ops(N);\n\n    ll x[MAXN] = {}, y[MAXN] = {}, w[MAXN] = {}, h[MAXN] = {};\n    ll curW = 0, curH = 0;\n    double usedA = 0.0;\n\n    double totalA = 0.0;\n    for (int i = 0; i < N; i++) totalA += (double)baseW[i] * (double)baseH[i];\n    double sqrtA = sqrt(max(1.0, totalA));\n    double norm = sqrtA + 1.0;\n\n    for (int i = 0; i < N; i++) {\n        double bestScore = 1e300;\n        ll bestPerim = INF64;\n        Operation bestOp{};\n        ll bestX = 0, bestY = 0, bestWi = 0, bestHi = 0, nextW = 0, nextH = 0;\n\n        for (int rot = 0; rot < 2; rot++) {\n            ll wi = rot ? baseH[i] : baseW[i];\n            ll hi = rot ? baseW[i] : baseH[i];\n\n            for (int dir = 0; dir < 2; dir++) {\n                for (int b = -1; b < i; b++) {\n                    ll xi = 0, yi = 0;\n\n                    if (dir == 0) {\n                        xi = (b == -1) ? 0 : (x[b] + w[b]);\n                        ll xr = xi + wi;\n                        yi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(xi, xr, x[j], x[j] + w[j])) yi = max(yi, y[j] + h[j]);\n                        }\n                    } else {\n                        yi = (b == -1) ? 0 : (y[b] + h[b]);\n                        ll yb = yi + hi;\n                        xi = 0;\n                        for (int j = 0; j < i; j++) {\n                            if (overlap(yi, yb, y[j], y[j] + h[j])) xi = max(xi, x[j] + w[j]);\n                        }\n                    }\n\n                    ll nW = max(curW, xi + wi);\n                    ll nH = max(curH, yi + hi);\n\n                    double usedA2 = usedA + (double)wi * (double)hi;\n                    double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                    double gap = (double)nW * (double)nH - usedA2;\n                    if (gap < 0) gap = 0;\n\n                    double sc = lb + param.gap_w * (gap / norm) + param.bal_w * (double)llabs(nW - nH);\n                    if (param.noise_w > 0.0) sc += param.noise_w * rng.uniform01();\n\n                    ll perim = nW + nH;\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) <= 1e-12 && perim < bestPerim)) {\n                        bestScore = sc;\n                        bestPerim = perim;\n                        bestOp = Operation{(uint8_t)rot, (uint8_t)dir, b};\n                        bestX = xi; bestY = yi; bestWi = wi; bestHi = hi;\n                        nextW = nW; nextH = nH;\n                    }\n                }\n            }\n        }\n\n        ops[i] = bestOp;\n        x[i] = bestX; y[i] = bestY; w[i] = bestWi; h[i] = bestHi;\n        curW = nextW; curH = nextH;\n        usedA += (double)bestWi * (double)bestHi;\n    }\n\n    return ops;\n}\n\nuint64_t hash_ops(const vector<Operation>& ops) {\n    uint64_t h = 0xcbf29ce484222325ULL;\n    for (size_t i = 0; i < ops.size(); i++) {\n        uint64_t v = (uint64_t)(ops[i].r + 1);\n        v = v * 3ULL + (uint64_t)(ops[i].d + 1);\n        v = v * 1315423911ULL + (uint64_t)(ops[i].b + 3);\n        h ^= splitmix64(v + 0x9e3779b97f4a7c15ULL * (i + 1));\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvector<vector<Operation>> beam_generate(\n    const vector<ll>& baseW, const vector<ll>& baseH, const BeamParam& prm, FastRNG& rng\n) {\n    int N = (int)baseW.size();\n\n    struct State {\n        array<ll, MAXN> x{}, y{}, w{}, h{};\n        array<Operation, MAXN> ops{};\n        ll W = 0, H = 0;\n        double usedA = 0.0;\n        double eval = 0.0;\n    };\n    struct Child {\n        double eval;\n        int parent;\n        Operation op;\n        ll x, y, w, h, W, H;\n        double usedA;\n    };\n\n    double totalA = 0.0;\n    for (int i = 0; i < N; i++) totalA += (double)baseW[i] * (double)baseH[i];\n    double sqrtA = sqrt(max(1.0, totalA));\n    double norm = sqrtA + 1.0;\n\n    vector<State> beam(1);\n\n    auto cmpChild = [](const Child& a, const Child& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        ll pa = a.W + a.H, pb = b.W + b.H;\n        return pa < pb;\n    };\n\n    for (int i = 0; i < N; i++) {\n        vector<Child> children;\n        children.reserve((int)beam.size() * 4 * (i + 1));\n\n        for (int si = 0; si < (int)beam.size(); si++) {\n            const State& st = beam[si];\n\n            for (int rot = 0; rot < 2; rot++) {\n                ll wi = rot ? baseH[i] : baseW[i];\n                ll hi = rot ? baseW[i] : baseH[i];\n\n                for (int dir = 0; dir < 2; dir++) {\n                    for (int b = -1; b < i; b++) {\n                        ll xi = 0, yi = 0;\n\n                        if (dir == 0) {\n                            xi = (b == -1) ? 0 : (st.x[b] + st.w[b]);\n                            ll xr = xi + wi;\n                            yi = 0;\n                            for (int j = 0; j < i; j++) {\n                                if (overlap(xi, xr, st.x[j], st.x[j] + st.w[j])) yi = max(yi, st.y[j] + st.h[j]);\n                            }\n                        } else {\n                            yi = (b == -1) ? 0 : (st.y[b] + st.h[b]);\n                            ll yb = yi + hi;\n                            xi = 0;\n                            for (int j = 0; j < i; j++) {\n                                if (overlap(yi, yb, st.y[j], st.y[j] + st.h[j])) xi = max(xi, st.x[j] + st.w[j]);\n                            }\n                        }\n\n                        ll nW = max(st.W, xi + wi);\n                        ll nH = max(st.H, yi + hi);\n\n                        double usedA2 = st.usedA + (double)wi * (double)hi;\n                        double lb = lower_bound_wh(nW, nH, totalA, sqrtA);\n                        double gap = (double)nW * (double)nH - usedA2;\n                        if (gap < 0) gap = 0;\n\n                        double sc = lb + prm.gap_w * (gap / norm) + prm.bal_w * (double)llabs(nW - nH);\n                        if (prm.noise_w > 0.0) sc += prm.noise_w * rng.uniform01();\n\n                        children.push_back(Child{\n                            sc, si, Operation{(uint8_t)rot, (uint8_t)dir, b},\n                            xi, yi, wi, hi, nW, nH, usedA2\n                        });\n                    }\n                }\n            }\n        }\n\n        if (children.empty()) break;\n        int B = min(prm.beam_width, (int)children.size());\n        int limit = min((int)children.size(), max(B, B * 3));\n\n        if ((int)children.size() > limit) {\n            nth_element(children.begin(), children.begin() + limit, children.end(), cmpChild);\n        }\n        sort(children.begin(), children.begin() + limit, cmpChild);\n\n        vector<State> next;\n        next.reserve(B);\n\n        vector<int> parentCnt(beam.size(), 0);\n        int parentCap = 3;\n        vector<char> used(limit, 0);\n\n        for (int k = 0; k < limit && (int)next.size() < B; k++) {\n            int p = children[k].parent;\n            if (parentCnt[p] >= parentCap) continue;\n            const Child& ch = children[k];\n            State ns = beam[ch.parent];\n            ns.ops[i] = ch.op;\n            ns.x[i] = ch.x; ns.y[i] = ch.y; ns.w[i] = ch.w; ns.h[i] = ch.h;\n            ns.W = ch.W; ns.H = ch.H; ns.usedA = ch.usedA; ns.eval = ch.eval;\n            next.push_back(std::move(ns));\n            parentCnt[p]++;\n            used[k] = 1;\n        }\n        for (int k = 0; k < limit && (int)next.size() < B; k++) {\n            if (used[k]) continue;\n            const Child& ch = children[k];\n            State ns = beam[ch.parent];\n            ns.ops[i] = ch.op;\n            ns.x[i] = ch.x; ns.y[i] = ch.y; ns.w[i] = ch.w; ns.h[i] = ch.h;\n            ns.W = ch.W; ns.H = ch.H; ns.usedA = ch.usedA; ns.eval = ch.eval;\n            next.push_back(std::move(ns));\n        }\n\n        beam.swap(next);\n        if (beam.empty()) break;\n    }\n\n    sort(beam.begin(), beam.end(), [](const State& a, const State& b) {\n        ll pa = a.W + a.H, pb = b.W + b.H;\n        if (pa != pb) return pa < pb;\n        return a.eval < b.eval;\n    });\n\n    int M = min(prm.keep_leaves, (int)beam.size());\n    vector<vector<Operation>> out;\n    out.reserve(M);\n    for (int k = 0; k < M; k++) {\n        vector<Operation> ops(N);\n        for (int i = 0; i < N; i++) ops[i] = beam[k].ops[i];\n        out.push_back(std::move(ops));\n    }\n    return out;\n}\n\nvoid oriented_dims(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot,\n    vector<ll>& ow, vector<ll>& oh\n) {\n    int N = (int)bw.size();\n    ow.resize(N);\n    oh.resize(N);\n    for (int i = 0; i < N; i++) {\n        if (!rot[i]) { ow[i] = bw[i]; oh[i] = bh[i]; }\n        else { ow[i] = bh[i]; oh[i] = bw[i]; }\n    }\n}\n\nvector<int> balanced_cuts_from_prefix(const vector<ll>& pref, int K) {\n    int N = (int)pref.size() - 1;\n    K = max(1, min(K, N));\n\n    vector<int> cuts;\n    cuts.reserve(K + 1);\n    cuts.push_back(0);\n    int prev = 0;\n\n    for (int t = 1; t < K; t++) {\n        int remain = K - t;\n        int lo = prev + 1;\n        int hi = N - remain;\n        if (lo > hi) lo = hi;\n\n        long double target = (long double)pref[N] * (long double)t / (long double)K;\n        int best = lo;\n        long double bestd = fabsl((long double)pref[lo] - target);\n\n        for (int c = lo + 1; c <= hi; c++) {\n            long double d = fabsl((long double)pref[c] - target);\n            if (d < bestd) {\n                bestd = d;\n                best = c;\n            }\n        }\n        cuts.push_back(best);\n        prev = best;\n    }\n    cuts.push_back(N);\n    return cuts;\n}\n\nvector<Operation> build_row_ops_from_cuts(\n    const vector<uint8_t>& rot, const vector<ll>& oh, const vector<int>& cuts\n) {\n    int N = (int)rot.size();\n    vector<Operation> ops(N);\n\n    int prevRef = -1;\n    for (int s = 0; s + 1 < (int)cuts.size(); s++) {\n        int l = cuts[s], r = cuts[s + 1];\n        int b = (s == 0 ? -1 : prevRef);\n\n        int ref = l;\n        ll mxh = oh[l];\n        for (int i = l; i < r; i++) {\n            ops[i] = Operation{rot[i], (uint8_t)1, b};\n            if (oh[i] > mxh) {\n                mxh = oh[i];\n                ref = i;\n            }\n        }\n        prevRef = ref;\n    }\n\n    return ops;\n}\n\nvector<Operation> build_col_ops_from_cuts(\n    const vector<uint8_t>& rot, const vector<ll>& ow, const vector<int>& cuts\n) {\n    int N = (int)rot.size();\n    vector<Operation> ops(N);\n\n    int prevRef = -1;\n    for (int s = 0; s + 1 < (int)cuts.size(); s++) {\n        int l = cuts[s], r = cuts[s + 1];\n        int b = (s == 0 ? -1 : prevRef);\n\n        int ref = l;\n        ll mxw = ow[l];\n        for (int i = l; i < r; i++) {\n            ops[i] = Operation{rot[i], (uint8_t)0, b};\n            if (ow[i] > mxw) {\n                mxw = ow[i];\n                ref = i;\n            }\n        }\n        prevRef = ref;\n    }\n\n    return ops;\n}\n\nvector<Operation> build_row_shelf_opt(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot\n) {\n    int N = (int)bw.size();\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    static ll segW[MAXN][MAXN], segH[MAXN][MAXN];\n    vector<ll> prefW(N + 1, 0);\n    for (int i = 0; i < N; i++) prefW[i + 1] = prefW[i] + ow[i];\n\n    vector<ll> cand;\n    cand.reserve(N * (N + 1) / 2);\n\n    for (int l = 0; l < N; l++) {\n        ll mxh = 0;\n        for (int r = l + 1; r <= N; r++) {\n            mxh = max(mxh, oh[r - 1]);\n            segW[l][r] = prefW[r] - prefW[l];\n            segH[l][r] = mxh;\n            cand.push_back(segW[l][r]);\n        }\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    ll bestObj = INF64;\n    vector<int> bestPrev(N + 1, -1), prev(N + 1, -1);\n    ll dp[MAXN];\n\n    for (ll Wlim : cand) {\n        for (int i = 0; i <= N; i++) dp[i] = INF64, prev[i] = -1;\n        dp[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            ll best = INF64;\n            int bi = -1;\n            for (int i = j - 1; i >= 0; i--) {\n                if (segW[i][j] > Wlim) break;\n                if (dp[i] == INF64) continue;\n                ll v = dp[i] + segH[i][j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                }\n            }\n            dp[j] = best;\n            prev[j] = bi;\n        }\n\n        if (dp[N] == INF64) continue;\n        ll obj = Wlim + dp[N];\n        if (obj < bestObj) {\n            bestObj = obj;\n            bestPrev = prev;\n        }\n    }\n\n    if (bestObj >= INF64 / 2) return {};\n\n    vector<int> cuts_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = bestPrev[cur];\n        if (p < 0) return {};\n        cuts_rev.push_back(cur);\n        cur = p;\n    }\n    cuts_rev.push_back(0);\n    reverse(cuts_rev.begin(), cuts_rev.end());\n\n    return build_row_ops_from_cuts(rot, oh, cuts_rev);\n}\n\nvector<Operation> build_col_shelf_opt(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot\n) {\n    int N = (int)bw.size();\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    static ll segH[MAXN][MAXN], segW[MAXN][MAXN];\n    vector<ll> prefH(N + 1, 0);\n    for (int i = 0; i < N; i++) prefH[i + 1] = prefH[i] + oh[i];\n\n    vector<ll> cand;\n    cand.reserve(N * (N + 1) / 2);\n\n    for (int l = 0; l < N; l++) {\n        ll mxw = 0;\n        for (int r = l + 1; r <= N; r++) {\n            mxw = max(mxw, ow[r - 1]);\n            segH[l][r] = prefH[r] - prefH[l];\n            segW[l][r] = mxw;\n            cand.push_back(segH[l][r]);\n        }\n    }\n\n    sort(cand.begin(), cand.end());\n    cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n    ll bestObj = INF64;\n    vector<int> bestPrev(N + 1, -1), prev(N + 1, -1);\n    ll dp[MAXN];\n\n    for (ll Hlim : cand) {\n        for (int i = 0; i <= N; i++) dp[i] = INF64, prev[i] = -1;\n        dp[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            ll best = INF64;\n            int bi = -1;\n            for (int i = j - 1; i >= 0; i--) {\n                if (segH[i][j] > Hlim) break;\n                if (dp[i] == INF64) continue;\n                ll v = dp[i] + segW[i][j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                }\n            }\n            dp[j] = best;\n            prev[j] = bi;\n        }\n\n        if (dp[N] == INF64) continue;\n        ll obj = Hlim + dp[N];\n        if (obj < bestObj) {\n            bestObj = obj;\n            bestPrev = prev;\n        }\n    }\n\n    if (bestObj >= INF64 / 2) return {};\n\n    vector<int> cuts_rev;\n    int cur = N;\n    while (cur > 0) {\n        int p = bestPrev[cur];\n        if (p < 0) return {};\n        cuts_rev.push_back(cur);\n        cur = p;\n    }\n    cuts_rev.push_back(0);\n    reverse(cuts_rev.begin(), cuts_rev.end());\n\n    return build_col_ops_from_cuts(rot, ow, cuts_rev);\n}\n\nvector<Operation> build_row_shelf_greedyK(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot, int K\n) {\n    int N = (int)bw.size();\n    K = max(1, min(K, N));\n\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    vector<ll> prefW(N + 1, 0);\n    for (int i = 0; i < N; i++) prefW[i + 1] = prefW[i] + ow[i];\n    auto cuts = balanced_cuts_from_prefix(prefW, K);\n\n    return build_row_ops_from_cuts(rot, oh, cuts);\n}\n\nvector<Operation> build_col_shelf_greedyK(\n    const vector<ll>& bw, const vector<ll>& bh, const vector<uint8_t>& rot, int K\n) {\n    int N = (int)bw.size();\n    K = max(1, min(K, N));\n\n    vector<ll> ow, oh;\n    oriented_dims(bw, bh, rot, ow, oh);\n\n    vector<ll> prefH(N + 1, 0);\n    for (int i = 0; i < N; i++) prefH[i + 1] = prefH[i] + oh[i];\n    auto cuts = balanced_cuts_from_prefix(prefH, K);\n\n    return build_col_ops_from_cuts(rot, ow, cuts);\n}\n\nvector<uint8_t> make_rot_row_lambda(const vector<ll>& bw, const vector<ll>& bh, double lam) {\n    int N = (int)bw.size();\n    vector<uint8_t> r(N);\n    for (int i = 0; i < N; i++) {\n        double c0 = (double)bh[i] + lam * (double)bw[i];\n        double c1 = (double)bw[i] + lam * (double)bh[i];\n        r[i] = (c1 < c0 ? 1 : 0);\n    }\n    return r;\n}\n\nvector<uint8_t> make_rot_col_lambda(const vector<ll>& bw, const vector<ll>& bh, double lam) {\n    int N = (int)bw.size();\n    vector<uint8_t> r(N);\n    for (int i = 0; i < N; i++) {\n        double c0 = (double)bw[i] + lam * (double)bh[i];\n        double c1 = (double)bh[i] + lam * (double)bw[i];\n        r[i] = (c1 < c0 ? 1 : 0);\n    }\n    return r;\n}\n\nOperation mutate_op(\n    const Operation& old, int i, const vector<ll>& bw, const vector<ll>& bh, FastRNG& rng\n) {\n    Operation nw = old;\n    int mode = rng.randint(0, 7);\n\n    if (mode == 0) nw.r ^= 1;\n    else if (mode == 1) nw.d ^= 1;\n    else if (mode == 2) nw.b = (i == 0 ? -1 : rng.randint(-1, i - 1));\n    else if (mode == 3) { nw.r ^= 1; nw.d ^= 1; }\n    else if (mode == 4) {\n        nw.r = rng.randint(0, 1);\n        nw.d = rng.randint(0, 1);\n        nw.b = (i == 0 ? -1 : rng.randint(-1, i - 1));\n    } else if (mode == 5) {\n        nw.b = (i == 0 ? -1 : (rng.uniform01() < 0.5 ? -1 : i - 1));\n    } else if (mode == 6) {\n        if (nw.d == 0) nw.r = (bh[i] < bw[i]) ? 1 : 0;\n        else nw.r = (bw[i] < bh[i]) ? 1 : 0;\n    } else {\n        if (i > 0) {\n            int nb = old.b + rng.randint(-3, 3);\n            nw.b = max(-1, min(i - 1, nb));\n        } else nw.b = -1;\n        if (rng.uniform01() < 0.35) nw.r ^= 1;\n    }\n\n    if (i == 0) nw.b = -1;\n    else nw.b = max(-1, min(i - 1, nw.b));\n    return nw;\n}\n\nvector<Operation> hill_climb(\n    const vector<ll>& bw, const vector<ll>& bh, vector<Operation> ops, int iterations, FastRNG& rng\n) {\n    int N = (int)ops.size();\n    ll cur = score_on_base(bw, bh, ops);\n\n    for (int it = 0; it < iterations; it++) {\n        int i = rng.randint(0, N - 1);\n        Operation old = ops[i];\n        Operation nw = mutate_op(old, i, bw, bh, rng);\n        ops[i] = nw;\n\n        ll nxt = score_on_base(bw, bh, ops);\n        if (nxt <= cur) cur = nxt;\n        else ops[i] = old;\n    }\n    return ops;\n}\n\nvector<Operation> anneal_optimize(\n    const vector<ll>& bw, const vector<ll>& bh, vector<Operation> ops, int iterations, FastRNG& rng\n) {\n    int N = (int)ops.size();\n    ll cur = score_on_base(bw, bh, ops);\n    ll best = cur;\n    vector<Operation> bestOps = ops;\n\n    double T0 = max(1000.0, 0.014 * (double)cur);\n    double T1 = 20.0;\n\n    for (int it = 0; it < iterations; it++) {\n        int i = rng.randint(0, N - 1);\n        Operation old = ops[i];\n        Operation nw = mutate_op(old, i, bw, bh, rng);\n        ops[i] = nw;\n\n        ll nxt = score_on_base(bw, bh, ops);\n        ll diff = nxt - cur;\n\n        double t = (double)it / max(1, iterations - 1);\n        double temp = exp(log(T0) * (1.0 - t) + log(T1) * t);\n\n        bool accept = false;\n        if (diff <= 0) accept = true;\n        else if (rng.uniform01() < exp(-(double)diff / temp)) accept = true;\n\n        if (accept) {\n            cur = nxt;\n            if (cur < best) {\n                best = cur;\n                bestOps = ops;\n            }\n        } else {\n            ops[i] = old;\n        }\n    }\n    return bestOps;\n}\n\nvoid compute_predictions(Candidate& c, const vector<Scenario>& scenarios) {\n    int S = (int)scenarios.size();\n    c.predW.resize(S);\n    c.predH.resize(S);\n    c.predS.resize(S);\n\n    long double sum = 0.0L;\n    for (int s = 0; s < S; s++) {\n        auto [W, H] = simulate_layout(scenarios[s].w, scenarios[s].h, c.ops);\n        c.predW[s] = W;\n        c.predH[s] = H;\n        c.predS[s] = W + H;\n        sum += (long double)(W + H);\n    }\n    c.avg = (double)(sum / (long double)S);\n\n    long double sq = 0.0L;\n    for (int s = 0; s < S; s++) {\n        long double d = (long double)c.predS[s] - (long double)c.avg;\n        sq += d * d;\n    }\n    c.spread = sqrt((double)(sq / (long double)max(1, S)));\n}\n\nvoid prune_dominated(vector<Candidate>& pool) {\n    if (pool.empty()) return;\n    int P = (int)pool.size();\n    int S = (int)pool[0].predS.size();\n    if (P < 80) return;\n\n    vector<char> dom(P, 0);\n\n    for (int i = 0; i < P; i++) {\n        if (dom[i]) continue;\n        for (int j = 0; j < P; j++) {\n            if (i == j) continue;\n            bool le = true;\n            int strictCnt = 0;\n            for (int s = 0; s < S; s++) {\n                if (pool[j].predS[s] > pool[i].predS[s]) {\n                    le = false;\n                    break;\n                }\n                if (pool[j].predS[s] < pool[i].predS[s]) strictCnt++;\n            }\n            if (!le) continue;\n            if (strictCnt >= 2 && pool[j].avg <= pool[i].avg + 1e-9) {\n                dom[i] = 1;\n                break;\n            }\n        }\n    }\n\n    vector<Candidate> out;\n    out.reserve(P);\n    for (int i = 0; i < P; i++) if (!dom[i]) out.push_back(std::move(pool[i]));\n    pool.swap(out);\n}\n\nvoid prune_identical_prediction(vector<Candidate>& pool) {\n    if (pool.empty()) return;\n    int P = (int)pool.size();\n    int S = (int)pool[0].predS.size();\n    vector<char> rem(P, 0);\n\n    for (int i = 0; i < P; i++) {\n        if (rem[i]) continue;\n        for (int j = i + 1; j < P; j++) {\n            if (rem[j]) continue;\n            bool same = true;\n            for (int s = 0; s < S; s++) {\n                if (pool[i].predS[s] != pool[j].predS[s]) {\n                    same = false;\n                    break;\n                }\n            }\n            if (same) {\n                if (pool[i].avg <= pool[j].avg) rem[j] = 1;\n                else {\n                    rem[i] = 1;\n                    break;\n                }\n            }\n        }\n    }\n\n    vector<Candidate> out;\n    out.reserve(P);\n    for (int i = 0; i < P; i++) if (!rem[i]) out.push_back(std::move(pool[i]));\n    pool.swap(out);\n}\n\nint sample_index(const vector<double>& w, FastRNG& rng) {\n    double r = rng.uniform01();\n    double acc = 0.0;\n    for (int i = 0; i < (int)w.size(); i++) {\n        acc += w[i];\n        if (r <= acc) return i;\n    }\n    return (int)w.size() - 1;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    ll sigma;\n    if (!(cin >> N >> T >> sigma)) return 0;\n\n    vector<ll> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) cin >> obsW[i] >> obsH[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    seed ^= splitmix64((uint64_t)N * 1000003ULL + (uint64_t)T * 10007ULL + (uint64_t)sigma * 911382323ULL);\n    for (int i = 0; i < N; i++) {\n        seed ^= splitmix64((uint64_t)obsW[i] * 1000003ULL + (uint64_t)obsH[i] + (uint64_t)(i + 1) * 19260817ULL);\n    }\n    FastRNG rng(seed);\n\n    auto start_time = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    };\n\n    // ===== denoising =====\n    long double sumObs = 0.0L;\n    for (int i = 0; i < N; i++) sumObs += (long double)obsW[i] + (long double)obsH[i];\n    double meanObs = (double)(sumObs / (long double)(2 * N));\n\n    ll Lhat = clamp_ll((ll)llround(2.0 * meanObs - (double)TRUE_MAX), TRUE_MIN, L_MAX);\n    ll Ltight = clamp_ll(Lhat - (ll)llround(0.55 * (double)sigma), TRUE_MIN, L_MAX);\n\n    vector<ll> obsCW(N), obsCH(N), baseTW(N), baseTH(N), baseUW(N), baseUH(N);\n    for (int i = 0; i < N; i++) {\n        obsCW[i] = clamp_ll(obsW[i], TRUE_MIN, TRUE_MAX);\n        obsCH[i] = clamp_ll(obsH[i], TRUE_MIN, TRUE_MAX);\n\n        baseTW[i] = (ll)llround(trunc_normal_mean((double)obsW[i], (double)sigma, (double)Ltight, (double)TRUE_MAX));\n        baseTH[i] = (ll)llround(trunc_normal_mean((double)obsH[i], (double)sigma, (double)Ltight, (double)TRUE_MAX));\n        baseTW[i] = clamp_ll(baseTW[i], Ltight, TRUE_MAX);\n        baseTH[i] = clamp_ll(baseTH[i], Ltight, TRUE_MAX);\n\n        baseUW[i] = (ll)llround(trunc_normal_mean((double)obsW[i], (double)sigma, (double)TRUE_MIN, (double)TRUE_MAX));\n        baseUH[i] = (ll)llround(trunc_normal_mean((double)obsH[i], (double)sigma, (double)TRUE_MIN, (double)TRUE_MAX));\n        baseUW[i] = clamp_ll(baseUW[i], TRUE_MIN, TRUE_MAX);\n        baseUH[i] = clamp_ll(baseUH[i], TRUE_MIN, TRUE_MAX);\n    }\n\n    // ===== scenarios =====\n    int S;\n    if (sigma <= 2500) S = 12;\n    else if (sigma <= 5000) S = 16;\n    else if (sigma <= 8000) S = 20;\n    else S = 24;\n\n    vector<Scenario> scenarios(S);\n    for (int s = 0; s < S; s++) {\n        scenarios[s].w.resize(N);\n        scenarios[s].h.resize(N);\n    }\n\n    int sid = 0;\n    auto add_scenario = [&](const vector<ll>& w, const vector<ll>& h) {\n        if (sid < S) {\n            scenarios[sid].w = w;\n            scenarios[sid].h = h;\n            sid++;\n        }\n    };\n\n    add_scenario(baseTW, baseTH);\n    add_scenario(baseUW, baseUH);\n    add_scenario(obsCW, obsCH);\n\n    ll gshift = (ll)llround(0.35 * (double)sigma);\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseTW[i] + gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseTH[i] + gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseTW[i] - gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseTH[i] - gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseUW[i] + gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseUH[i] + gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n    {\n        vector<ll> w(N), h(N);\n        for (int i = 0; i < N; i++) {\n            w[i] = clamp_ll(baseUW[i] - gshift, TRUE_MIN, TRUE_MAX);\n            h[i] = clamp_ll(baseUH[i] - gshift, TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w, h);\n    }\n\n    while (sid < S) {\n        vector<ll> w1(N), h1(N), w2(N), h2(N);\n        double g = 0.40 * (double)sigma * rng.normal01();\n        double lsd = 0.65 * (double)sigma;\n        for (int i = 0; i < N; i++) {\n            double lw = lsd * rng.normal01();\n            double lh = lsd * rng.normal01();\n\n            w1[i] = clamp_ll((ll)llround((double)obsW[i] + g + lw), TRUE_MIN, TRUE_MAX);\n            h1[i] = clamp_ll((ll)llround((double)obsH[i] + g + lh), TRUE_MIN, TRUE_MAX);\n\n            w2[i] = clamp_ll((ll)llround((double)obsW[i] - g - lw), TRUE_MIN, TRUE_MAX);\n            h2[i] = clamp_ll((ll)llround((double)obsH[i] - g - lh), TRUE_MIN, TRUE_MAX);\n        }\n        add_scenario(w1, h1);\n        add_scenario(w2, h2);\n    }\n\n    // ===== candidate generation =====\n    const int Pcap = 320;\n    int Ptarget = min(240, max(100, T + 80));\n\n    vector<Candidate> pool;\n    pool.reserve(Pcap + 16);\n    unordered_set<uint64_t> seen;\n    seen.reserve((Pcap + 16) * 4);\n\n    auto add_candidate = [&](vector<Operation>&& ops) -> bool {\n        if ((int)ops.size() != N) return false;\n        if ((int)pool.size() >= Pcap) return false;\n        uint64_t h = hash_ops(ops);\n        if (!seen.insert(h).second) return false;\n        Candidate c;\n        c.ops = move(ops);\n        c.hash = h;\n        pool.push_back(move(c));\n        return true;\n    };\n\n    // baselines\n    add_candidate(build_linear_chain(baseTW, baseTH, true, true));\n    add_candidate(build_linear_chain(baseTW, baseTH, false, true));\n    add_candidate(build_single_stack(baseTW, baseTH, true));\n    add_candidate(build_single_stack(baseTW, baseTH, false));\n    add_candidate(build_linear_chain(baseTW, baseTH, true, false));\n    add_candidate(build_linear_chain(baseTW, baseTH, false, false));\n    add_candidate(build_linear_chain(baseUW, baseUH, true, true));\n    add_candidate(build_linear_chain(baseUW, baseUH, false, true));\n\n    // shelf variants\n    vector<uint8_t> rotMinH(N), rotMinW(N);\n    for (int i = 0; i < N; i++) {\n        rotMinH[i] = (baseTW[i] < baseTH[i]) ? 1 : 0;\n        rotMinW[i] = (baseTH[i] < baseTW[i]) ? 1 : 0;\n    }\n\n    if (elapsed() < 0.25) {\n        auto op = build_row_shelf_opt(baseTW, baseTH, rotMinH);\n        if (!op.empty()) add_candidate(move(op));\n        op = build_col_shelf_opt(baseTW, baseTH, rotMinW);\n        if (!op.empty()) add_candidate(move(op));\n    }\n\n    // extra exact shelf (cheap enough for smaller N)\n    if (N <= 70 && elapsed() < 0.45) {\n        auto rr = make_rot_row_lambda(baseTW, baseTH, 0.35);\n        auto rc = make_rot_col_lambda(baseTW, baseTH, 0.35);\n        auto op = build_row_shelf_opt(baseTW, baseTH, rr);\n        if (!op.empty()) add_candidate(move(op));\n        op = build_col_shelf_opt(baseTW, baseTH, rc);\n        if (!op.empty()) add_candidate(move(op));\n    }\n\n    if (N <= 55 && elapsed() < 0.55) {\n        vector<uint8_t> rH2(N), rW2(N);\n        for (int i = 0; i < N; i++) {\n            rH2[i] = (baseUW[i] < baseUH[i]) ? 1 : 0;\n            rW2[i] = (baseUH[i] < baseUW[i]) ? 1 : 0;\n        }\n        auto op = build_row_shelf_opt(baseUW, baseUH, rH2);\n        if (!op.empty()) add_candidate(move(op));\n        op = build_col_shelf_opt(baseUW, baseUH, rW2);\n        if (!op.empty()) add_candidate(move(op));\n    }\n\n    for (double lam : {0.15, 0.35, 0.70}) {\n        auto rr = make_rot_row_lambda(baseTW, baseTH, lam);\n        auto rc = make_rot_col_lambda(baseTW, baseTH, lam);\n        for (int K : {3, 5, 7}) {\n            if (K <= N) {\n                add_candidate(build_row_shelf_greedyK(baseTW, baseTH, rr, K));\n                add_candidate(build_col_shelf_greedyK(baseTW, baseTH, rc, K));\n            }\n        }\n    }\n\n    // deterministic greedy\n    vector<GreedyParam> det = {\n        {0.30, 0.006, 0.0},\n        {0.55, 0.010, 0.0},\n        {0.80, 0.016, 0.0},\n        {0.12, 0.000, 0.0}\n    };\n    for (auto gp : det) add_candidate(build_greedy(baseTW, baseTH, gp, rng));\n    add_candidate(build_greedy(baseUW, baseUH, GreedyParam{0.45, 0.008, 0.0}, rng));\n    for (int s = 0; s < min(S, 4); s++) {\n        add_candidate(build_greedy(scenarios[s].w, scenarios[s].h, GreedyParam{0.45, 0.008, 0.0}, rng));\n    }\n\n    // beam\n    int Bmain = (N <= 40 ? 50 : (N <= 70 ? 42 : (N <= 90 ? 36 : 30)));\n    int Bsub = max(16, Bmain - 12);\n\n    BeamParam bp1{Bmain, min(16, Bmain), 0.35, 0.006, 0.0};\n    BeamParam bp2{Bmain, min(14, Bmain), 0.65, 0.012, 0.0};\n    BeamParam bp3{Bsub, min(9, Bsub), 0.42, 0.010, 70.0 + 0.020 * (double)sigma};\n\n    auto run_beam = [&](const vector<ll>& bw, const vector<ll>& bh, const BeamParam& bp) {\n        if ((int)pool.size() >= Ptarget) return;\n        auto sols = beam_generate(bw, bh, bp, rng);\n        for (auto& ops : sols) {\n            add_candidate(move(ops));\n            if ((int)pool.size() >= Ptarget) break;\n        }\n    };\n\n    double genBudget = (N <= 60 ? 1.15 : 1.00);\n    if (sigma >= 8000) genBudget += 0.10;\n\n    if (elapsed() < genBudget) run_beam(baseTW, baseTH, bp1);\n    if ((int)pool.size() < Ptarget && elapsed() < genBudget) run_beam(baseTW, baseTH, bp2);\n    if ((int)pool.size() < Ptarget && elapsed() < genBudget) run_beam(baseUW, baseUH, bp3);\n\n    // random greedy fill\n    int attempts = 0;\n    while ((int)pool.size() < Ptarget && elapsed() < genBudget && attempts < Ptarget * 55) {\n        int rs = rng.randint(0, S - 1);\n        GreedyParam gp;\n        gp.gap_w = 0.03 + 1.10 * rng.uniform01();\n        gp.bal_w = 0.03 * rng.uniform01();\n        gp.noise_w = (30.0 + 0.05 * (double)sigma) * rng.uniform01();\n        add_candidate(build_greedy(scenarios[rs].w, scenarios[rs].h, gp, rng));\n        attempts++;\n    }\n\n    // local refinement\n    if (!pool.empty() && elapsed() < genBudget + 0.45) {\n        vector<pair<ll, int>> ord;\n        ord.reserve(pool.size());\n        for (int i = 0; i < (int)pool.size(); i++) {\n            ord.emplace_back(score_on_base(baseTW, baseTH, pool[i].ops), i);\n        }\n        sort(ord.begin(), ord.end());\n\n        int topK = min(4, (int)ord.size());\n        for (int k = 0; k < topK && elapsed() < genBudget + 0.45; k++) {\n            int idx = ord[k].second;\n            auto sa = anneal_optimize(baseTW, baseTH, pool[idx].ops, 70 + N, rng);\n            add_candidate(move(sa));\n            if (elapsed() > genBudget + 0.50) break;\n            auto hc = hill_climb(baseTW, baseTH, pool[idx].ops, 55 + N / 2, rng);\n            add_candidate(move(hc));\n        }\n    }\n\n    if (pool.empty()) {\n        add_candidate(build_greedy(baseTW, baseTH, GreedyParam{0.40, 0.008, 0.0}, rng));\n    }\n\n    for (auto& c : pool) compute_predictions(c, scenarios);\n\n    prune_dominated(pool);\n    prune_identical_prediction(pool);\n\n    if (pool.empty()) {\n        Candidate c;\n        c.ops = build_greedy(baseTW, baseTH, GreedyParam{0.40, 0.008, 0.0}, rng);\n        c.hash = hash_ops(c.ops);\n        compute_predictions(c, scenarios);\n        pool.push_back(move(c));\n    }\n\n    // specialists\n    vector<int> specialists;\n    {\n        int P = (int)pool.size();\n        vector<char> usedSpec(P, 0);\n\n        for (int s = 0; s < S; s++) {\n            ll bestV = INF64;\n            int bestI = -1;\n            for (int i = 0; i < P; i++) {\n                if (pool[i].predS[s] < bestV) {\n                    bestV = pool[i].predS[s];\n                    bestI = i;\n                }\n            }\n            if (bestI >= 0 && !usedSpec[bestI]) {\n                specialists.push_back(bestI);\n                usedSpec[bestI] = 1;\n            }\n        }\n\n        vector<int> ids(P);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) { return pool[a].avg < pool[b].avg; });\n        for (int k = 0; k < min(3, P); k++) {\n            if (!usedSpec[ids[k]]) {\n                specialists.push_back(ids[k]);\n                usedSpec[ids[k]] = 1;\n            }\n        }\n    }\n\n    int exploreK = 0;\n    if (T >= 2) {\n        if (sigma <= 2500) exploreK = 0;\n        else if (sigma <= 6000) exploreK = 1;\n        else exploreK = 2;\n        exploreK = min(exploreK, T / 6);\n        exploreK = min(exploreK, (int)specialists.size());\n    }\n    int specPtr = 0;\n\n    // ===== online =====\n    vector<ll> bestScenario(S, INF64);\n    vector<double> logWeight(S, 0.0), post(S, 1.0 / S), weights(S, 1.0 / S);\n    vector<char> used(pool.size(), 0);\n    int usedCnt = 0;\n\n    // mild prior\n    vector<double> prior(S, 1.0);\n    if (S >= 1) prior[0] = 1.6;\n    if (S >= 2) prior[1] = 1.3;\n    if (S >= 3) prior[2] = 1.1;\n    double ps = 0.0;\n    for (double v : prior) ps += v;\n    for (int s = 0; s < S; s++) logWeight[s] = log(prior[s] / ps);\n\n    double scaleMul = (sigma >= 7000 ? 1.65 : 1.55);\n    double likeScale = max(800.0, (double)sigma * scaleMul);\n    double invScale2 = 1.0 / (likeScale * likeScale);\n    double forget = 0.993;\n\n    int warmup = min(T - 1, max(3, T / 6));\n    int regen1 = min(T - 1, max(2, T / 4));\n    int regen2 = (T >= 28 ? min(T - 1, max(regen1 + 1, (2 * T) / 3)) : -1);\n    bool regenDone1 = false, regenDone2 = false;\n\n    auto add_and_predict = [&](vector<Operation>&& ops) {\n        if ((int)ops.size() != N) return;\n        if ((int)pool.size() >= Pcap) return;\n        uint64_t h = hash_ops(ops);\n        if (!seen.insert(h).second) return;\n\n        Candidate c;\n        c.ops = move(ops);\n        c.hash = h;\n        compute_predictions(c, scenarios);\n        pool.push_back(move(c));\n        used.push_back(0);\n    };\n\n    auto regenerate_from_posterior = [&](const vector<double>& posterior) {\n        if (elapsed() > 2.55) return;\n        if ((int)pool.size() >= Pcap) return;\n\n        vector<ll> mw(N), mh(N);\n        for (int i = 0; i < N; i++) {\n            long double sw = 0.0L, sh = 0.0L;\n            for (int s = 0; s < S; s++) {\n                sw += (long double)posterior[s] * (long double)scenarios[s].w[i];\n                sh += (long double)posterior[s] * (long double)scenarios[s].h[i];\n            }\n            mw[i] = clamp_ll((ll)llround(sw), TRUE_MIN, TRUE_MAX);\n            mh[i] = clamp_ll((ll)llround(sh), TRUE_MIN, TRUE_MAX);\n        }\n\n        add_and_predict(build_greedy(mw, mh, GreedyParam{0.32, 0.006, 0.0}, rng));\n        add_and_predict(build_greedy(mw, mh, GreedyParam{0.60, 0.011, 0.0}, rng));\n        add_and_predict(build_greedy(mw, mh, GreedyParam{0.42, 0.009, 25.0 + 0.02 * (double)sigma}, rng));\n\n        auto rr = make_rot_row_lambda(mw, mh, 0.35);\n        auto rc = make_rot_col_lambda(mw, mh, 0.35);\n        add_and_predict(build_row_shelf_greedyK(mw, mh, rr, min(4, N)));\n        add_and_predict(build_col_shelf_greedyK(mw, mh, rc, min(4, N)));\n\n        int bestIdx = -1;\n        long double bestEv = 1e300L;\n        for (int i = 0; i < (int)pool.size(); i++) {\n            long double ev = 0.0L;\n            for (int s = 0; s < S; s++) ev += (long double)posterior[s] * (long double)pool[i].predS[s];\n            if (ev < bestEv) {\n                bestEv = ev;\n                bestIdx = i;\n            }\n        }\n        if (bestIdx >= 0) add_and_predict(hill_climb(mw, mh, pool[bestIdx].ops, 45 + N / 2, rng));\n\n        if (elapsed() < 2.45 && (int)pool.size() < Pcap) {\n            int Br = max(14, Bmain - 16);\n            BeamParam rb{Br, min(6, Br), 0.40, 0.009, 0.0};\n            auto sols = beam_generate(mw, mh, rb, rng);\n            for (auto& ops : sols) {\n                add_and_predict(move(ops));\n                if ((int)pool.size() >= Pcap) break;\n            }\n        }\n    };\n\n    int idxBestAvg = 0;\n    for (int i = 1; i < (int)pool.size(); i++) {\n        if (pool[i].avg < pool[idxBestAvg].avg) idxBestAvg = i;\n    }\n\n    for (int turn = 0; turn < T; turn++) {\n        double frac = (double)turn / max(1, T - 1);\n\n        // posterior\n        double gamma = 0.35 + 0.55 * frac;\n        double mx = *max_element(logWeight.begin(), logWeight.end());\n        double sp = 0.0;\n        for (int s = 0; s < S; s++) {\n            post[s] = exp((logWeight[s] - mx) * gamma);\n            sp += post[s];\n        }\n        if (sp <= 0.0) {\n            for (int s = 0; s < S; s++) post[s] = 1.0 / S;\n        } else {\n            for (int s = 0; s < S; s++) post[s] /= sp;\n        }\n\n        double beta = 0.0;\n        if (turn >= warmup) {\n            beta = 0.68 * (double)(turn - warmup + 1) / max(1, T - warmup);\n            if (beta > 0.68) beta = 0.68;\n        }\n        for (int s = 0; s < S; s++) {\n            weights[s] = (1.0 - beta) * (1.0 / S) + beta * post[s];\n        }\n\n        if (!regenDone1 && turn == regen1) {\n            regenerate_from_posterior(post);\n            regenDone1 = true;\n        }\n        if (!regenDone2 && regen2 >= 0 && turn == regen2) {\n            regenerate_from_posterior(post);\n            regenDone2 = true;\n        }\n\n        bool hasUnused = (usedCnt < (int)used.size());\n        int chosen = -1;\n\n        // safe first turn\n        if (turn == 0) {\n            chosen = idxBestAvg;\n            if (hasUnused && used[chosen]) chosen = -1;\n        }\n\n        // deterministic early exploration\n        if (chosen == -1 && turn < exploreK) {\n            while (specPtr < (int)specialists.size() && used[specialists[specPtr]]) specPtr++;\n            if (specPtr < (int)specialists.size()) chosen = specialists[specPtr++];\n        }\n\n        // tiny random probe\n        if (chosen == -1) {\n            double eps = 0.02 * max(0.0, 1.0 - frac * 2.0);\n            if (rng.uniform01() < eps) {\n                int s = sample_index(weights, rng);\n                ll bestV = INF64;\n                int bestI = -1;\n                for (int i = 0; i < (int)pool.size(); i++) {\n                    if (hasUnused && used[i]) continue;\n                    ll v = min(bestScenario[s], pool[i].predS[s]);\n                    if (v < bestV || (v == bestV && pool[i].avg < (bestI < 0 ? 1e100 : pool[bestI].avg))) {\n                        bestV = v;\n                        bestI = i;\n                    }\n                }\n                if (bestI >= 0) chosen = bestI;\n            }\n        }\n\n        if (chosen == -1) {\n            long double bestVal = 1e300L;\n\n            double riskMul = (sigma >= 7000 ? 1.20 : (sigma <= 3000 ? 0.85 : 1.0));\n            double lambda95 = 0.050 * riskMul * (1.0 - frac);\n            double lambda80 = 0.015 * riskMul * (1.0 - frac);\n\n            double eta_spread = 0.0;\n            if (turn <= warmup + 2) {\n                double f = (double)(warmup + 2 - turn) / (double)(warmup + 3);\n                eta_spread = (sigma >= 5000 ? 0.04 : 0.02) * f;\n            }\n\n            struct Node { ll v; double w; };\n            Node arr[24];\n\n            for (int ci = 0; ci < (int)pool.size(); ci++) {\n                if (hasUnused && used[ci]) continue;\n\n                long double ev = 0.0L;\n                for (int s = 0; s < S; s++) {\n                    ll cur = min(bestScenario[s], pool[ci].predS[s]);\n                    ev += (long double)weights[s] * (long double)cur;\n                    arr[s] = {cur, weights[s]};\n                }\n\n                sort(arr, arr + S, [](const Node& a, const Node& b) { return a.v < b.v; });\n                double cum = 0.0;\n                ll q80 = arr[S - 1].v;\n                ll q95 = arr[S - 1].v;\n                bool got80 = false, got95 = false;\n                for (int i = 0; i < S; i++) {\n                    cum += arr[i].w;\n                    if (!got80 && cum >= 0.80) {\n                        q80 = arr[i].v;\n                        got80 = true;\n                    }\n                    if (!got95 && cum >= 0.95) {\n                        q95 = arr[i].v;\n                        got95 = true;\n                        break;\n                    }\n                }\n\n                long double val = ev\n                                + lambda95 * (long double)q95\n                                + lambda80 * (long double)q80\n                                - eta_spread * (long double)pool[ci].spread;\n\n                if (chosen == -1 || val < bestVal - 1e-12L ||\n                    (fabsl(val - bestVal) <= 1e-12L && pool[ci].avg < pool[chosen].avg)) {\n                    bestVal = val;\n                    chosen = ci;\n                }\n            }\n        }\n\n        if (chosen == -1) chosen = 0;\n\n        if (!used[chosen]) {\n            used[chosen] = 1;\n            usedCnt++;\n        }\n\n        // output\n        cout << N << '\\n';\n        for (int i = 0; i < N; i++) {\n            const auto& op = pool[chosen].ops[i];\n            cout << i << ' ' << int(op.r) << ' ' << (op.d == 0 ? 'U' : 'L') << ' ' << op.b << '\\n';\n        }\n        cout.flush();\n\n        // input\n        ll Wm, Hm;\n        if (!(cin >> Wm >> Hm)) return 0;\n        if (Wm == -1 && Hm == -1) return 0;\n\n        for (int s = 0; s < S; s++) bestScenario[s] = min(bestScenario[s], pool[chosen].predS[s]);\n\n        // posterior update\n        for (int s = 0; s < S; s++) logWeight[s] *= forget;\n        double updCoef = 0.70 + 0.55 * frac;\n        for (int s = 0; s < S; s++) {\n            double dw = (double)Wm - (double)pool[chosen].predW[s];\n            double dh = (double)Hm - (double)pool[chosen].predH[s];\n            double d2 = (dw * dw + dh * dh) * invScale2;\n            logWeight[s] += -updCoef * log1p(d2);\n        }\n\n        double mx2 = *max_element(logWeight.begin(), logWeight.end());\n        for (int s = 0; s < S; s++) logWeight[s] -= mx2;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nclass Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<vector<int>> g;\n    vector<int> ordDesc, ordAsc;\n\n    XorShift64 rng;\n    chrono::steady_clock::time_point t0;\n\n    struct DState {\n        vector<int> d;\n        vector<int> cnt;\n        long long extra = 0; // sum d[v] * A[v]\n    };\n\n    struct Forest {\n        vector<int> p;             // parent (-1 = root)\n        vector<int> d;             // depth\n        vector<int> idx;           // index in parent's child list\n        vector<vector<int>> ch;    // children\n        long long extra = 0;       // sum d[v] * A[v]\n    };\n\npublic:\n    Solver() : rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    void solve() {\n        read_input();\n        prepare_orders();\n        t0 = chrono::steady_clock::now();\n\n        const double TOTAL  = 1.89;\n        const double D1_END = 0.84;\n        const double T1_END = 1.34;\n        const double D2_END = 1.52;\n        const double T2_END = 1.87;\n\n        vector<int> d0;\n        if (elapsed() < D1_END) d0 = optimize_depths_scratch(D1_END);\n        else d0.assign(N, 0);\n        repair_depth(d0);\n\n        Forest globalBest = build_forest_from_depth(d0, 0);\n\n        if (elapsed() < T1_END) {\n            Forest f1 = tree_optimize(d0, T1_END, nullptr);\n            if (f1.extra > globalBest.extra) globalBest = move(f1);\n        }\n\n        vector<int> dSeed = globalBest.d;\n        if (elapsed() < D2_END) {\n            dSeed = polish_depth_seed(dSeed, D2_END);\n            Forest f2 = build_forest_from_depth(dSeed, 0);\n            if (f2.extra > globalBest.extra) globalBest = move(f2);\n        }\n\n        vector<int> finalSeed = (depth_extra_value(dSeed) >= globalBest.extra ? dSeed : globalBest.d);\n\n        const Forest* warm = nullptr;\n        Forest warmHolder;\n        if (globalBest.d == finalSeed) {\n            warmHolder = globalBest;\n            warm = &warmHolder;\n        }\n\n        if (elapsed() < T2_END) {\n            Forest f3 = tree_optimize(finalSeed, T2_END, warm);\n            if (f3.extra > globalBest.extra) globalBest = move(f3);\n        }\n\n        // Final tiny safe depth harvest\n        if (elapsed() < TOTAL - 0.005) {\n            vector<int> dFinal = quick_depth_polish(globalBest.d, TOTAL - 0.001);\n            long long ex = depth_extra_value(dFinal);\n            if (ex > globalBest.extra) {\n                Forest f = build_forest_from_depth(dFinal, 0);\n                if (f.extra > globalBest.extra) globalBest = move(f);\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << globalBest.p[i];\n        }\n        cout << '\\n';\n    }\n\nprivate:\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n\n    void read_input() {\n        cin >> N >> M >> H;\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\n\n        g.assign(N, {});\n        for (int i = 0; i < M; i++) {\n            int u, v;\n            cin >> u >> v;\n            g[u].push_back(v);\n            g[v].push_back(u);\n        }\n\n        for (int i = 0; i < N; i++) {\n            int x, y;\n            cin >> x >> y;\n        }\n    }\n\n    void prepare_orders() {\n        ordDesc.resize(N);\n        iota(ordDesc.begin(), ordDesc.end(), 0);\n        sort(ordDesc.begin(), ordDesc.end(), [&](int a, int b) {\n            if (A[a] != A[b]) return A[a] > A[b];\n            if (g[a].size() != g[b].size()) return g[a].size() < g[b].size();\n            return a < b;\n        });\n        ordAsc = ordDesc;\n        reverse(ordAsc.begin(), ordAsc.end());\n    }\n\n    void shuffle_vec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i >= 1; --i) {\n            int j = rng.next_int(0, i);\n            swap(v[i], v[j]);\n        }\n    }\n\n    long long depth_extra_value(const vector<int>& d) const {\n        long long s = 0;\n        for (int v = 0; v < N; v++) s += 1LL * d[v] * A[v];\n        return s;\n    }\n\n    // -------------------------\n    // Depth-label optimization\n    // -------------------------\n    void rebuild(DState& st) const {\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n        for (int v = 0; v < N; v++) st.extra += 1LL * st.d[v] * A[v];\n\n        for (int v = 0; v < N; v++) {\n            if (st.d[v] == 0) continue;\n            int need = st.d[v] - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n    }\n\n    void repair_depth(vector<int>& d) const {\n        bool changed = true;\n        while (changed) {\n            changed = false;\n            for (int v = 0; v < N; v++) {\n                while (d[v] > 0) {\n                    int need = d[v] - 1;\n                    bool ok = false;\n                    for (int u : g[v]) {\n                        if (d[u] == need) { ok = true; break; }\n                    }\n                    if (ok) break;\n                    --d[v];\n                    changed = true;\n                }\n            }\n        }\n    }\n\n    inline bool feasible_change(const DState& st, int v, int nd) const {\n        int od = st.d[v];\n        if (nd == od || nd < 0 || nd > H) return false;\n\n        if (nd > 0) {\n            bool ok = false;\n            for (int u : g[v]) {\n                if (st.d[u] == nd - 1) { ok = true; break; }\n            }\n            if (!ok) return false;\n        }\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            int c = st.cnt[u];\n            if (od == need) --c;\n            if (nd == need) ++c;\n            if (c <= 0) return false;\n        }\n\n        return true;\n    }\n\n    inline void apply_change(DState& st, int v, int nd) const {\n        int od = st.d[v];\n        if (od == nd) return;\n\n        for (int u : g[v]) {\n            int du = st.d[u];\n            if (du == 0) continue;\n            int need = du - 1;\n            if (od == need) --st.cnt[u];\n            if (nd == need) ++st.cnt[u];\n        }\n\n        st.d[v] = nd;\n        if (nd == 0) st.cnt[v] = 0;\n        else {\n            int need = nd - 1;\n            int c = 0;\n            for (int u : g[v]) if (st.d[u] == need) ++c;\n            st.cnt[v] = c;\n        }\n\n        st.extra += 1LL * (nd - od) * A[v];\n    }\n\n    bool greedy_up_pass(DState& st, const vector<int>& order, bool stepwise) const {\n        bool changed = false;\n        for (int v : order) {\n            int cur = st.d[v];\n            if (stepwise) {\n                int nd = cur + 1;\n                if (nd <= H && feasible_change(st, v, nd)) {\n                    apply_change(st, v, nd);\n                    changed = true;\n                }\n            } else {\n                for (int nd = H; nd > cur; --nd) {\n                    if (feasible_change(st, v, nd)) {\n                        apply_change(st, v, nd);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n        return changed;\n    }\n\n    DState construct_initial_variant(int variant) {\n        DState st;\n        st.d.assign(N, 0);\n        st.cnt.assign(N, 0);\n        st.extra = 0;\n\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) key[v] = A[v] * 2048 + rng.next_int(0, 2047);\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 1) {\n            order = ordDesc;\n            int sw = N / 4;\n            for (int i = 0; i < sw; i++) {\n                int x = rng.next_int(0, N - 1), y = rng.next_int(0, N - 1);\n                swap(order[x], order[y]);\n            }\n        } else if (variant == 2) {\n            vector<int> key(N);\n            for (int v = 0; v < N; v++) {\n                int deg = (int)g[v].size();\n                key[v] = (A[v] * 1200) / (deg + 1) + rng.next_int(0, 255);\n            }\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] > key[b];\n                return a < b;\n            });\n        } else if (variant == 3) {\n            order = ordDesc;\n            shuffle_vec(order);\n        } else {\n            order = ordDesc;\n        }\n\n        for (int pass = 0; pass < 24; pass++) {\n            bool step = (pass < 4);\n            bool changed = greedy_up_pass(st, order, step);\n\n            if (pass == 1 || pass == 4 || pass == 8) {\n                if (variant == 1 || variant == 3) shuffle_vec(order);\n            }\n            if (!changed && pass > 7) break;\n        }\n\n        for (int rep = 0; rep < 4; rep++) {\n            if (!greedy_up_pass(st, ordDesc, false)) break;\n        }\n\n        return st;\n    }\n\n    void short_sa_polish(DState& st, int iters, double T0, double T1, double timeLimit) {\n        int topK = min(N, 240);\n        vector<int> bestD = st.d;\n        long long bestE = st.extra;\n\n        for (int it = 0; it < iters; it++) {\n            if ((it & 127) == 0 && elapsed() >= timeLimit) break;\n\n            int v = (rng.next_double() < 0.70)\n                ? ordDesc[rng.next_int(0, topK - 1)]\n                : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = st.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != st.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.45) nd = cand[clen - 1];\n            else if (r < 0.57) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(st, v, nd)) continue;\n\n            int delta = (nd - st.d[v]) * A[v];\n            double p = (double)it / max(1, iters - 1);\n            double temp = T0 * pow(T1 / T0, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n            apply_change(st, v, nd);\n\n            if (st.extra > bestE) {\n                bestE = st.extra;\n                bestD = st.d;\n            }\n        }\n\n        if (bestE > st.extra) {\n            st.d = move(bestD);\n            rebuild(st);\n        }\n    }\n\n    void run_feasible_sa(DState& cur, DState& best, double timeLimit) {\n        double saStart = elapsed();\n        if (saStart >= timeLimit) return;\n\n        const double T0 = 55.0;\n        const double T1 = 0.18;\n        const double ratio = T1 / T0;\n        int topK = min(N, 300);\n\n        long long iter = 0;\n        while (true) {\n            if ((iter & 255LL) == 0 && elapsed() >= timeLimit) break;\n            ++iter;\n\n            int v = (rng.next_double() < 0.62)\n                ? ordDesc[rng.next_int(0, topK - 1)]\n                : rng.next_int(0, N - 1);\n\n            bool avail[16] = {};\n            avail[0] = true;\n            for (int u : g[v]) {\n                int nd = cur.d[u] + 1;\n                if (nd <= H) avail[nd] = true;\n            }\n\n            int cand[16], clen = 0;\n            for (int d = 0; d <= H; d++) if (avail[d] && d != cur.d[v]) cand[clen++] = d;\n            if (clen == 0) continue;\n\n            int nd;\n            double r = rng.next_double();\n            if (r < 0.48) nd = cand[clen - 1];\n            else if (r < 0.62) nd = cand[0];\n            else nd = cand[rng.next_int(0, clen - 1)];\n\n            if (!feasible_change(cur, v, nd)) continue;\n\n            int delta = (nd - cur.d[v]) * A[v];\n\n            double now = elapsed();\n            double p = (now - saStart) / max(1e-9, timeLimit - saStart);\n            p = max(0.0, min(1.0, p));\n            double temp = T0 * pow(ratio, p);\n\n            bool accept = false;\n            if (delta >= 0) accept = true;\n            else {\n                double x = (double)delta / temp;\n                if (x > -20.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n            apply_change(cur, v, nd);\n\n            if (cur.extra > best.extra) best = cur;\n            if ((iter & 65535LL) == 0 && cur.extra + 5000 < best.extra) cur = best;\n        }\n    }\n\n    void macro_perturb_search(DState& best, double timeLimit) {\n        int topHigh = min(N, 300);\n        int topLow = min(N, 420);\n        vector<int> order = ordDesc;\n\n        while (elapsed() < timeLimit) {\n            DState tmp = best;\n            int mode = rng.next_int(0, 4);\n\n            if (mode == 0) {\n                int k = rng.next_int(1, 4);\n                for (int i = 0; i < k; i++) {\n                    int v = ordDesc[rng.next_int(0, topHigh - 1)];\n                    tmp.d[v] = H;\n                }\n            } else if (mode == 1) {\n                int k = rng.next_int(2, 7);\n                for (int i = 0; i < k; i++) {\n                    int v = ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = 0;\n                }\n            } else if (mode == 2) {\n                int k = rng.next_int(18, 80);\n                for (int i = 0; i < k; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    tmp.d[v] = rng.next_int(0, H);\n                }\n            } else if (mode == 3) {\n                int k = rng.next_int(15, 50);\n                for (int i = 0; i < k; i++) {\n                    bool hi = (rng.next_double() < 0.62);\n                    int v = hi ? ordDesc[rng.next_int(0, topHigh - 1)]\n                               : ordAsc[rng.next_int(0, topLow - 1)];\n                    tmp.d[v] = hi ? H : 0;\n                }\n            } else {\n                int c = rng.next_int(0, N - 1);\n                tmp.d[c] = (rng.next_double() < 0.5 ? 0 : H);\n                for (int u : g[c]) if (rng.next_double() < 0.75) tmp.d[u] = rng.next_int(0, H);\n                int ex = rng.next_int(5, 20);\n                for (int i = 0; i < ex; i++) {\n                    int v = rng.next_int(0, N - 1);\n                    if (rng.next_double() < 0.55) tmp.d[v] = 0;\n                }\n            }\n\n            repair_depth(tmp.d);\n            rebuild(tmp);\n\n            order = ordDesc;\n            for (int pass = 0; pass < 7; pass++) {\n                if (pass == 1 || pass == 4) shuffle_vec(order);\n                else if (pass == 2 || pass == 5) order = ordDesc;\n\n                bool step = (pass < 2);\n                bool changed = greedy_up_pass(tmp, order, step);\n\n                if (!changed && pass >= 4) break;\n                if (elapsed() >= timeLimit) break;\n            }\n\n            if (elapsed() + 0.008 < timeLimit && rng.next_double() < 0.50) {\n                short_sa_polish(tmp, 520, 2.1, 0.4, timeLimit);\n            }\n\n            if (tmp.extra > best.extra) best = move(tmp);\n        }\n    }\n\n    vector<int> optimize_depths_scratch(double endTime) {\n        DState best;\n        best.extra = LLONG_MIN;\n\n        double initEnd = min(endTime, 0.24);\n        int restart = 0;\n        while (elapsed() < initEnd) {\n            DState st = construct_initial_variant(restart % 5);\n\n            if ((restart & 1) == 0 && elapsed() + 0.008 < initEnd) {\n                short_sa_polish(st, 420, 4.5, 0.9, initEnd);\n            }\n\n            if (st.extra > best.extra) best = move(st);\n            ++restart;\n        }\n\n        if (best.extra == LLONG_MIN) {\n            best.d.assign(N, 0);\n            best.cnt.assign(N, 0);\n            best.extra = 0;\n        }\n\n        DState cur = best;\n\n        double saEnd = min(endTime, initEnd + (endTime - initEnd) * 0.58);\n        if (elapsed() < saEnd) run_feasible_sa(cur, best, saEnd);\n        if (elapsed() < endTime) macro_perturb_search(best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 5; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    vector<int> polish_depth_seed(const vector<int>& seed, double endTime) {\n        DState best;\n        best.d = seed;\n        repair_depth(best.d);\n        rebuild(best);\n\n        for (int i = 0; i < 4; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        DState cur = best;\n        double rem = max(0.0, endTime - elapsed());\n        double saEnd = min(endTime, elapsed() + rem * 0.62);\n        if (elapsed() < saEnd) run_feasible_sa(cur, best, saEnd);\n        if (elapsed() < endTime) macro_perturb_search(best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        for (int i = 0; i < 3; i++) {\n            if (!greedy_up_pass(best, ordDesc, false)) break;\n        }\n\n        return best.d;\n    }\n\n    vector<int> quick_depth_polish(const vector<int>& seed, double endTime) {\n        DState st;\n        st.d = seed;\n        repair_depth(st.d);\n        rebuild(st);\n\n        for (int i = 0; i < 2; i++) {\n            if (!greedy_up_pass(st, ordDesc, false)) break;\n        }\n\n        DState best = st, cur = st;\n        if (elapsed() < endTime) run_feasible_sa(cur, best, endTime);\n\n        repair_depth(best.d);\n        rebuild(best);\n        greedy_up_pass(best, ordDesc, false);\n        return best.d;\n    }\n\n    // -------------------------\n    // Tree optimization\n    // -------------------------\n    void build_children_idx(Forest& f) const {\n        f.ch.assign(N, {});\n        f.idx.assign(N, -1);\n        for (int v = 0; v < N; v++) {\n            int p = f.p[v];\n            if (p != -1) {\n                f.idx[v] = (int)f.ch[p].size();\n                f.ch[p].push_back(v);\n            }\n        }\n    }\n\n    inline void cut(Forest& f, int v) const {\n        int p = f.p[v];\n        if (p == -1) return;\n        int i = f.idx[v];\n        int last = f.ch[p].back();\n        f.ch[p][i] = last;\n        f.idx[last] = i;\n        f.ch[p].pop_back();\n        f.p[v] = -1;\n        f.idx[v] = -1;\n    }\n\n    inline void link(Forest& f, int v, int p) const {\n        f.p[v] = p;\n        f.idx[v] = (int)f.ch[p].size();\n        f.ch[p].push_back(v);\n    }\n\n    inline void move_parent(Forest& f, int v, int np) const {\n        int op = f.p[v];\n        if (op == np) return;\n        if (op != -1) cut(f, v);\n        if (np != -1) link(f, v, np);\n    }\n\n    void recompute_depth_from_parent(Forest& f) const {\n        while (true) {\n            vector<int> nd(N, -1);\n            deque<int> dq;\n            for (int v = 0; v < N; v++) {\n                if (f.p[v] == -1) {\n                    nd[v] = 0;\n                    dq.push_back(v);\n                }\n            }\n\n            while (!dq.empty()) {\n                int x = dq.front();\n                dq.pop_front();\n                for (int y : f.ch[x]) {\n                    if (nd[y] != -1) continue;\n                    nd[y] = nd[x] + 1;\n                    dq.push_back(y);\n                }\n            }\n\n            bool fix = false;\n            for (int v = 0; v < N; v++) {\n                if (nd[v] == -1 || nd[v] > H) {\n                    if (f.p[v] != -1) {\n                        f.p[v] = -1;\n                        fix = true;\n                    } else if (nd[v] == -1) {\n                        fix = true;\n                    }\n                }\n            }\n\n            build_children_idx(f);\n            if (!fix) {\n                f.d.swap(nd);\n                f.extra = 0;\n                for (int v = 0; v < N; v++) f.extra += 1LL * f.d[v] * A[v];\n                return;\n            }\n        }\n    }\n\n    Forest build_forest_from_depth(const vector<int>& depth, int mode) {\n        Forest f;\n        f.d = depth;\n        f.p.assign(N, -1);\n\n        for (int v = 0; v < N; v++) {\n            if (f.d[v] == 0) {\n                f.p[v] = -1;\n                continue;\n            }\n\n            int need = f.d[v] - 1;\n            vector<int> cand;\n            cand.reserve(g[v].size());\n            for (int u : g[v]) if (f.d[u] == need) cand.push_back(u);\n\n            int par = -1;\n            if (!cand.empty()) {\n                if ((int)cand.size() == 1) {\n                    par = cand[0];\n                } else if (mode == 1) { // random\n                    par = cand[rng.next_int(0, (int)cand.size() - 1)];\n                } else if (mode == 2) { // high-degree\n                    int bestDeg = -1;\n                    for (int u : cand) {\n                        int du = (int)g[u].size();\n                        if (du > bestDeg || (du == bestDeg && (par == -1 || A[u] < A[par]))) {\n                            bestDeg = du;\n                            par = u;\n                        }\n                    }\n                } else { // low-A\n                    long long bestKey = (1LL << 60);\n                    for (int u : cand) {\n                        long long key = 1LL * A[u] * 512 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            par = u;\n                        }\n                    }\n                }\n            } else {\n                int bestd = INT_MAX;\n                for (int u : g[v]) {\n                    if (depth[u] < depth[v] && depth[u] < bestd) {\n                        bestd = depth[u];\n                        par = u;\n                    }\n                }\n            }\n\n            f.p[v] = par;\n        }\n\n        build_children_idx(f);\n        recompute_depth_from_parent(f);\n        return f;\n    }\n\n    void normalize_parents(Forest& f, int rounds, bool highFirst) {\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n\n        for (int r = 0; r < rounds; r++) {\n            if (highFirst) order = ordDesc;\n            else shuffle_vec(order);\n\n            for (int v : order) {\n                if (f.d[v] == 0) continue;\n                int need = f.d[v] - 1;\n                int curp = f.p[v];\n\n                int best = curp;\n                long long bestKey = (1LL << 60);\n                if (curp != -1) {\n                    bestKey = 1LL * A[curp] * 256 + (int)f.ch[curp].size() * 8 + (int)g[curp].size();\n                }\n\n                for (int u : g[v]) {\n                    if (f.d[u] != need) continue;\n                    long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                    if (key < bestKey) {\n                        bestKey = key;\n                        best = u;\n                    }\n                }\n\n                if (best != -1 && best != curp) move_parent(f, v, best);\n            }\n        }\n    }\n\n    void leafify_highA(Forest& f, int topK, int rounds) {\n        topK = min(topK, N);\n        for (int r = 0; r < rounds; r++) {\n            for (int i = 0; i < topK; i++) {\n                int v = ordDesc[i];\n                if (f.ch[v].empty()) continue;\n\n                vector<int> children = f.ch[v];\n                for (int x : children) {\n                    if (f.p[x] != v) continue;\n                    int need = f.d[x] - 1;\n                    if (need < 0) continue;\n\n                    int best = -1;\n                    long long bestKey = (1LL << 60);\n                    for (int u : g[x]) {\n                        if (u == v) continue;\n                        if (f.d[u] != need) continue;\n                        long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            best = u;\n                        }\n                    }\n                    if (best != -1) move_parent(f, x, best);\n                }\n            }\n        }\n    }\n\n    void compute_submax_static(const Forest& f, vector<int>& subMax) const {\n        subMax = f.d;\n        vector<vector<int>> bucket(H + 1);\n        for (int v = 0; v < N; v++) {\n            int dep = max(0, min(H, f.d[v]));\n            bucket[dep].push_back(v);\n        }\n        for (int dep = H; dep >= 0; dep--) {\n            for (int v : bucket[dep]) {\n                int p = f.p[v];\n                if (p != -1 && subMax[v] > subMax[p]) subMax[p] = subMax[v];\n            }\n        }\n    }\n\n    void trim_deep_branches(Forest& f, int topK, int rounds) {\n        topK = min(topK, N);\n        vector<int> subMax;\n        for (int r = 0; r < rounds; r++) {\n            compute_submax_static(f, subMax);\n            bool changed = false;\n\n            for (int i = 0; i < topK; i++) {\n                int v = ordDesc[i];\n                if (f.d[v] >= H) continue;\n                if (subMax[v] < H) continue;\n\n                vector<int> children = f.ch[v];\n                for (int c : children) {\n                    if (f.p[c] != v) continue;\n                    if (subMax[c] < H) continue;\n\n                    int need = f.d[c] - 1;\n                    int best = -1;\n                    long long bestKey = (1LL << 60);\n\n                    for (int u : g[c]) {\n                        if (u == v) continue;\n                        if (f.d[u] != need) continue;\n                        long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                        if (key < bestKey) {\n                            bestKey = key;\n                            best = u;\n                        }\n                    }\n\n                    if (best != -1) {\n                        move_parent(f, c, best);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void random_neutral_rewire(Forest& f, int tries) {\n        if (tries <= 0) return;\n        int topK = min(N, 260);\n\n        for (int t = 0; t < tries; t++) {\n            int v = (rng.next_double() < 0.65)\n                ? ordDesc[rng.next_int(0, topK - 1)]\n                : rng.next_int(0, N - 1);\n\n            if (f.d[v] == 0) continue;\n            int need = f.d[v] - 1;\n            int curp = f.p[v];\n\n            int best = -1;\n            if (rng.next_double() < 0.55) {\n                int cnt = 0;\n                for (int u : g[v]) {\n                    if (u == curp) continue;\n                    if (f.d[u] != need) continue;\n                    ++cnt;\n                    if (rng.next_int(1, cnt) == 1) best = u;\n                }\n            } else {\n                long long bestKey = (1LL << 60);\n                for (int u : g[v]) {\n                    if (u == curp) continue;\n                    if (f.d[u] != need) continue;\n                    long long key = 1LL * A[u] * 256 + (int)f.ch[u].size() * 8 + (int)g[u].size();\n                    if (key < bestKey) {\n                        bestKey = key;\n                        best = u;\n                    }\n                }\n            }\n\n            if (best != -1) move_parent(f, v, best);\n        }\n    }\n\n    void init_subinfo(const Forest& f, vector<long long>& subA, vector<int>& subMax) const {\n        subA.assign(N, 0);\n        subMax.assign(N, 0);\n\n        vector<vector<int>> bucket(H + 1);\n        for (int v = 0; v < N; v++) {\n            subA[v] = A[v];\n            subMax[v] = f.d[v];\n            int dep = max(0, min(H, f.d[v]));\n            bucket[dep].push_back(v);\n        }\n\n        for (int dep = H; dep >= 0; dep--) {\n            for (int v : bucket[dep]) {\n                int p = f.p[v];\n                if (p != -1) {\n                    subA[p] += subA[v];\n                    if (subMax[v] > subMax[p]) subMax[p] = subMax[v];\n                }\n            }\n        }\n    }\n\n    inline bool is_descendant(const Forest& f, int u, int anc) const {\n        while (u != -1 && f.d[u] > f.d[anc]) u = f.p[u];\n        return u == anc;\n    }\n\n    void run_tree_sa_fast(Forest& cur, Forest& best, double timeLimit) {\n        if (elapsed() >= timeLimit) return;\n\n        vector<long long> subA;\n        vector<int> subMax;\n        init_subinfo(cur, subA, subMax);\n\n        vector<int> nodes, stk;\n        nodes.reserve(N);\n        stk.reserve(N);\n\n        auto gather_nodes = [&](int root) {\n            nodes.clear();\n            stk.clear();\n            stk.push_back(root);\n            while (!stk.empty()) {\n                int x = stk.back();\n                stk.pop_back();\n                nodes.push_back(x);\n                for (int y : cur.ch[x]) stk.push_back(y);\n            }\n        };\n\n        auto recompute_up = [&](int a) {\n            while (a != -1) {\n                int mx = cur.d[a];\n                for (int c : cur.ch[a]) if (subMax[c] > mx) mx = subMax[c];\n                subMax[a] = mx;\n                a = cur.p[a];\n            }\n        };\n\n        auto apply_move = [&](int v, int np, int delta, long long gain) {\n            int oldp = cur.p[v];\n\n            if (delta == 0) {\n                if (oldp == np) return;\n\n                if (oldp != -1) cut(cur, v);\n                if (np != -1) link(cur, v, np);\n\n                cur.extra += gain;\n                long long sv = subA[v];\n\n                if (oldp != -1) {\n                    int a = oldp;\n                    while (a != -1) {\n                        subA[a] -= sv;\n                        a = cur.p[a];\n                    }\n                }\n                if (np != -1) {\n                    int a = np;\n                    while (a != -1) {\n                        subA[a] += sv;\n                        a = cur.p[a];\n                    }\n                }\n\n                if (oldp != -1) recompute_up(oldp);\n                if (np != -1) recompute_up(np);\n\n                if (cur.extra > best.extra) best = cur;\n                return;\n            }\n\n            gather_nodes(v);\n\n            if (oldp != -1) cut(cur, v);\n            if (np != -1) link(cur, v, np);\n\n            for (int x : nodes) {\n                cur.d[x] += delta;\n                subMax[x] += delta;\n            }\n\n            cur.extra += gain;\n            long long sv = subA[v];\n\n            if (oldp != -1) {\n                int a = oldp;\n                while (a != -1) {\n                    subA[a] -= sv;\n                    a = cur.p[a];\n                }\n            }\n            if (np != -1) {\n                int a = np;\n                while (a != -1) {\n                    subA[a] += sv;\n                    a = cur.p[a];\n                }\n            }\n\n            if (oldp != -1) recompute_up(oldp);\n            if (np != -1) recompute_up(np);\n\n            if (cur.extra > best.extra) best = cur;\n        };\n\n        auto choose_parent_at_depth = [&](int x, int depthNeed, int ban) -> int {\n            int bestPar = -1;\n            long long bestKey = (1LL << 60);\n            for (int u : g[x]) {\n                if (u == ban) continue;\n                if (cur.d[u] != depthNeed) continue;\n                if (is_descendant(cur, u, x)) continue;\n                long long key = 1LL * A[u] * 256 + (int)cur.ch[u].size() * 8 + (int)g[u].size();\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestPar = u;\n                }\n            }\n            return bestPar;\n        };\n\n        auto choose_parent_at_depth_outside = [&](int x, int depthNeed, int outV, int ban) -> int {\n            int bestPar = -1;\n            long long bestKey = (1LL << 60);\n            for (int u : g[x]) {\n                if (u == ban) continue;\n                if (cur.d[u] != depthNeed) continue;\n                if (outV != -1 && is_descendant(cur, u, outV)) continue;\n                if (is_descendant(cur, u, x)) continue;\n\n                long long key = ((subMax[u] == H) ? 0LL : (1LL << 20))\n                              + 1LL * A[u] * 256\n                              + 1LL * (int)cur.ch[u].size() * 8\n                              + (int)g[u].size();\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestPar = u;\n                }\n            }\n            return bestPar;\n        };\n\n        auto best_raise = [&](int v, int sm) -> tuple<int,int,long long> {\n            int bp = -1, bd = 0;\n            long long bg = 0;\n            for (int u : g[v]) {\n                if (is_descendant(cur, u, v)) continue;\n                int ndv = cur.d[u] + 1;\n                if (ndv > H) continue;\n                int delta = ndv - cur.d[v];\n                if (delta <= 0) continue;\n                if (sm + delta > H) continue;\n\n                long long gain = 1LL * delta * subA[v];\n                if (gain > bg || (gain == bg && bp != -1 && A[u] < A[bp])) {\n                    bg = gain;\n                    bp = u;\n                    bd = delta;\n                }\n            }\n            return {bp, bd, bg};\n        };\n\n        vector<int> ordSub(N);\n        auto refresh_ordSub = [&]() {\n            iota(ordSub.begin(), ordSub.end(), 0);\n            sort(ordSub.begin(), ordSub.end(), [&](int a, int b) {\n                if (subA[a] != subA[b]) return subA[a] > subA[b];\n                if (A[a] != A[b]) return A[a] > A[b];\n                return a < b;\n            });\n        };\n\n        auto greedy_positive = [&](int passes) {\n            for (int ps = 0; ps < passes; ps++) {\n                if (elapsed() >= timeLimit) return;\n                refresh_ordSub();\n                bool changed = false;\n\n                for (int ii = 0; ii < N; ii++) {\n                    if ((ii & 31) == 0 && elapsed() >= timeLimit) return;\n                    int v = ordSub[ii];\n                    long long sv = subA[v];\n                    int sm = subMax[v];\n\n                    long long bestG = 0;\n                    int bestPar = -2;\n                    int bestDelta = 0;\n\n                    for (int u : g[v]) {\n                        if (is_descendant(cur, u, v)) continue;\n                        int ndv = cur.d[u] + 1;\n                        if (ndv > H) continue;\n\n                        int delta = ndv - cur.d[v];\n                        if (delta <= 0) continue;\n                        if (sm + delta > H) continue;\n\n                        long long gain = 1LL * delta * sv;\n                        if (gain > bestG ||\n                            (gain == bestG && bestPar != -2 && A[u] < A[bestPar])) {\n                            bestG = gain;\n                            bestPar = u;\n                            bestDelta = delta;\n                        }\n                    }\n\n                    if (bestPar != -2) {\n                        apply_move(v, bestPar, bestDelta, bestG);\n                        changed = true;\n                    }\n                }\n\n                if (!changed) break;\n            }\n        };\n\n        auto composite_unblock = [&](int passes) {\n            struct Act { int c, np, delta; };\n            int topK = min(N, 260);\n\n            auto refresh_hLeaves = [&]() {\n                vector<int> h;\n                h.reserve(N / 3 + 8);\n                for (int x = 0; x < N; x++) {\n                    if (cur.d[x] == H && cur.ch[x].empty()) h.push_back(x);\n                }\n                return h;\n            };\n\n            for (int ps = 0; ps < passes; ps++) {\n                if (elapsed() >= timeLimit) return;\n                bool changed = false;\n                vector<int> hLeaves = refresh_hLeaves();\n\n                for (int i = 0; i < topK; i++) {\n                    if ((i & 31) == 0 && elapsed() >= timeLimit) return;\n                    int v = ordDesc[i];\n                    if (cur.d[v] <= 0 || cur.d[v] >= H) continue;\n\n                    auto [up0, del0, g0] = best_raise(v, subMax[v]);\n                    (void)del0; (void)g0;\n                    if (up0 == -1) continue;\n\n                    int leafMoves = 0;\n                    while (subMax[v] == H && leafMoves < 6) {\n                        int bestX = -1, bestP = -1;\n                        long long bestKey = (1LL << 62);\n\n                        for (int x : hLeaves) {\n                            if (cur.d[x] != H) continue;\n                            if (!cur.ch[x].empty()) continue;\n                            if (!is_descendant(cur, x, v)) continue;\n\n                            int np = choose_parent_at_depth_outside(x, H - 1, v, cur.p[x]);\n                            if (np == -1) continue;\n\n                            long long key = ((subMax[np] == H) ? 0LL : (1LL << 24))\n                                          + 1LL * A[x] * 64 + A[np];\n                            if (key < bestKey) {\n                                bestKey = key;\n                                bestX = x;\n                                bestP = np;\n                            }\n                        }\n\n                        if (bestX == -1) break;\n                        apply_move(bestX, bestP, 0, 0);\n                        leafMoves++;\n                    }\n\n                    if (subMax[v] <= H - 1) {\n                        auto [up, del, gg] = best_raise(v, subMax[v]);\n                        if (up != -1 && del > 0) {\n                            apply_move(v, up, del, gg);\n                            changed = true;\n                        }\n                        continue;\n                    }\n\n                    vector<int> blockers;\n                    for (int c : cur.ch[v]) if (subMax[c] == H) blockers.push_back(c);\n                    if (blockers.empty() || (int)blockers.size() > 8) continue;\n\n                    vector<Act> acts;\n                    long long removed = 0, cost = 0;\n                    bool ok = true;\n\n                    for (int c : blockers) {\n                        removed += subA[c];\n\n                        int p0 = choose_parent_at_depth_outside(c, cur.d[v], v, v);\n                        if (p0 != -1) {\n                            acts.push_back({c, p0, 0});\n                            continue;\n                        }\n\n                        long long bestCost = (1LL << 62);\n                        int bestPar = -2, bestDelta = 0;\n\n                        if (cur.d[v] - 1 >= 0) {\n                            int p1 = choose_parent_at_depth(c, cur.d[v] - 1, -1);\n                            if (p1 != -1) {\n                                long long cst = subA[c];\n                                if (cst < bestCost) {\n                                    bestCost = cst;\n                                    bestPar = p1;\n                                    bestDelta = -1;\n                                }\n                            }\n                        }\n\n                        long long rootCost = 1LL * cur.d[c] * subA[c];\n                        if (rootCost < bestCost) {\n                            bestCost = rootCost;\n                            bestPar = -1;\n                            bestDelta = -cur.d[c];\n                        }\n\n                        if (bestPar == -2) { ok = false; break; }\n                        cost += bestCost;\n                        acts.push_back({c, bestPar, bestDelta});\n                    }\n\n                    if (!ok) continue;\n                    long long estGain = (subA[v] - removed) - cost;\n                    if (estGain <= 0) continue;\n\n                    for (auto &ac : acts) {\n                        long long gain = 1LL * ac.delta * subA[ac.c];\n                        apply_move(ac.c, ac.np, ac.delta, gain);\n                    }\n\n                    if (subMax[v] <= H - 1) {\n                        auto [up, del, gg] = best_raise(v, subMax[v]);\n                        if (up != -1 && del > 0) {\n                            apply_move(v, up, del, gg);\n                            changed = true;\n                        }\n                    }\n                }\n\n                if (!changed) break;\n            }\n        };\n\n        auto neutral_kick = [&](int tries) {\n            int topK = min(N, 260);\n            for (int t = 0; t < tries; t++) {\n                int v = (rng.next_double() < 0.7)\n                    ? ordDesc[rng.next_int(0, topK - 1)]\n                    : rng.next_int(0, N - 1);\n\n                if (cur.d[v] == 0) continue;\n                int need = cur.d[v] - 1;\n\n                int bestP = -1;\n                long long bestKey = (1LL << 60);\n                for (int u : g[v]) {\n                    if (u == cur.p[v]) continue;\n                    if (cur.d[u] != need) continue;\n                    if (is_descendant(cur, u, v)) continue;\n\n                    long long key = ((subMax[u] == H) ? 0LL : (1LL << 20))\n                                  + 1LL * A[u] * 256\n                                  + 1LL * (int)cur.ch[u].size() * 8\n                                  + (int)g[u].size();\n                    if (key < bestKey) {\n                        bestKey = key;\n                        bestP = u;\n                    }\n                }\n                if (bestP != -1) apply_move(v, bestP, 0, 0);\n            }\n        };\n\n        greedy_positive(1);\n        composite_unblock(1);\n        greedy_positive(1);\n\n        struct Cand { int par, delta; long long gain; };\n        vector<Cand> cands;\n        cands.reserve(24);\n\n        refresh_ordSub();\n        const int topA = min(N, 300);\n        const int topS = min(N, 320);\n\n        double phaseStart = elapsed();\n        const double T0 = 3200.0;\n        const double T1 = 1.65;\n        const double ratio = T1 / T0;\n\n        long long iter = 0;\n        long long lastImprove = 0;\n\n        while (true) {\n            if ((iter & 127LL) == 0 && elapsed() >= timeLimit) break;\n            ++iter;\n\n            if ((iter & 1023LL) == 0) refresh_ordSub();\n\n            int v;\n            double rr = rng.next_double();\n            if (rr < 0.44) v = ordDesc[rng.next_int(0, topA - 1)];\n            else if (rr < 0.80) v = ordSub[rng.next_int(0, topS - 1)];\n            else v = rng.next_int(0, N - 1);\n\n            long long sv = subA[v];\n            int sm = subMax[v];\n\n            cands.clear();\n            long long bestGain = LLONG_MIN;\n            int bestIdx = -1;\n\n            for (int u : g[v]) {\n                if (is_descendant(cur, u, v)) continue;\n                int ndv = cur.d[u] + 1;\n                if (ndv > H) continue;\n\n                int delta = ndv - cur.d[v];\n                if (delta == 0 && cur.p[v] == u) continue;\n                if (sm + delta > H) continue;\n\n                long long gain = 1LL * delta * sv;\n                cands.push_back({u, delta, gain});\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestIdx = (int)cands.size() - 1;\n                }\n            }\n\n            if (cur.p[v] != -1) {\n                int delta = -cur.d[v];\n                if (sm + delta <= H) {\n                    long long gain = 1LL * delta * sv;\n                    cands.push_back({-1, delta, gain});\n                    if (gain > bestGain) {\n                        bestGain = gain;\n                        bestIdx = (int)cands.size() - 1;\n                    }\n                }\n            }\n\n            if (cands.empty()) continue;\n\n            int chosen;\n            if (bestIdx != -1 && bestGain > 0 && rng.next_double() < 0.78) chosen = bestIdx;\n            else chosen = rng.next_int(0, (int)cands.size() - 1);\n\n            Cand c = cands[chosen];\n            if (c.par == cur.p[v] && c.delta == 0) continue;\n\n            bool accept = false;\n            if (c.gain > 0) {\n                accept = true;\n            } else if (c.gain == 0) {\n                double pr = (c.par == cur.p[v]) ? 0.03 : 0.30;\n                if (c.par != -1 && cur.p[v] != -1) {\n                    if (A[c.par] + 2 < A[cur.p[v]]) pr += 0.18;\n                    if ((int)cur.ch[c.par].size() + 1 < (int)cur.ch[cur.p[v]].size()) pr += 0.08;\n                }\n                if (rng.next_double() < pr) accept = true;\n            } else {\n                double p = (elapsed() - phaseStart) / max(1e-9, timeLimit - phaseStart);\n                p = max(0.0, min(1.0, p));\n                double temp = T0 * pow(ratio, p);\n                double x = (double)c.gain / temp;\n                if (x > -25.0 && rng.next_double() < exp(x)) accept = true;\n            }\n\n            if (!accept) continue;\n\n            long long prevBest = best.extra;\n            apply_move(v, c.par, c.delta, c.gain);\n            if (best.extra > prevBest) lastImprove = iter;\n\n            if ((iter & 8191LL) == 0) {\n                if (cur.extra + 12000 < best.extra) {\n                    cur = best;\n                    init_subinfo(cur, subA, subMax);\n                    refresh_ordSub();\n                }\n            }\n\n            if (iter - lastImprove > 55000 && elapsed() + 0.015 < timeLimit) {\n                neutral_kick(24);\n                composite_unblock(1);\n                refresh_ordSub();\n                lastImprove = iter;\n            }\n        }\n\n        composite_unblock(1);\n        greedy_positive(2);\n    }\n\n    Forest tree_optimize(const vector<int>& baseDepth, double endTime, const Forest* warm) {\n        vector<int> d = baseDepth;\n        repair_depth(d);\n\n        auto make_init = [&](int mode, bool noisy) {\n            Forest f = build_forest_from_depth(d, mode);\n            normalize_parents(f, 1, mode == 0);\n            leafify_highA(f, (mode == 1 ? 280 : 240), 1);\n            trim_deep_branches(f, (mode == 1 ? 320 : 280), 1);\n            if (noisy) random_neutral_rewire(f, (mode == 2 ? 120 : 90));\n            return f;\n        };\n\n        Forest best;\n        if (warm != nullptr && warm->d == d) {\n            best = *warm;\n            build_children_idx(best);\n            recompute_depth_from_parent(best);\n            normalize_parents(best, 1, true);\n            leafify_highA(best, 220, 1);\n        } else {\n            best = make_init(0, false);\n        }\n\n        if (elapsed() >= endTime) return best;\n\n        Forest cur = best;\n        double now = elapsed();\n        double seg1 = now + (endTime - now) * 0.50;\n        run_tree_sa_fast(cur, best, seg1);\n\n        if (elapsed() < endTime - 0.05) {\n            Forest alt1 = make_init(1, true);\n            double now2 = elapsed();\n            double seg2 = now2 + (endTime - now2) * 0.62;\n            run_tree_sa_fast(alt1, best, seg2);\n        }\n\n        if (elapsed() < endTime - 0.03) {\n            Forest alt2 = make_init(2, true);\n            run_tree_sa_fast(alt2, best, endTime - 0.008);\n        }\n\n        if (elapsed() < endTime - 0.003) {\n            Forest fin = best;\n            random_neutral_rewire(fin, 36);\n            run_tree_sa_fast(fin, best, endTime);\n        }\n\n        return best;\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}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 20;\nconstexpr int MAXC = 80;\nconstexpr int MAXD = 20;\nconstexpr int MAXM = 64;\n\nstruct Chain {\n    char dir, rev;\n    int idx;\n};\nstruct Option {\n    int chain, req;\n};\nstruct State {\n    array<uint8_t, MAXC> d{};\n    array<uint8_t, MAXM> sat{};\n    uint64_t unsatMask = 0;\n    int cost = 0; // 2 * sum(depth)\n};\nstruct UPlan {\n    array<uint8_t, MAXC> in{};\n    vector<int> ord;\n    int save = 0; // sum depth on ord\n};\n\nclass Solver {\n    using Grid = array<array<char, MAXN>, MAXN>;\n    using Op = pair<char,int>;\n\n    int N, Cn, M;\n    vector<string> board;\n    Grid initGrid{};\n    int initialFuku = 0;\n\n    array<Chain, MAXC> chains{};\n    vector<vector<Option>> opts;\n    vector<pair<int,int>> oniPos;\n\n    array<int, MAXC> cap{};\n    array<array<uint64_t, MAXD + 1>, MAXC> eqMask{};\n    array<array<uint64_t, MAXD + 1>, MAXC> leMask{};\n    array<vector<int>, MAXC> usefulDepths{};\n\n    uint64_t fullMask = 0;\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n\npublic:\n    Solver(int n, vector<string> b) : N(n), Cn(4*n), board(move(b)) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        build();\n    }\n\n    vector<Op> solve() {\n        st = chrono::steady_clock::now();\n\n        const double depthEnd   = 1.48;\n        const double unpair1End = 1.66;\n        const double shrinkEnd  = 1.77;\n        const double unpair2End = 1.84;\n        const double pruneEnd   = 1.97;\n\n        State s = optimizeDepth(depthEnd);\n        if (s.unsatMask) return fallbackPerOni();\n        State guaranteed = s;\n\n        UPlan plan = optimizeUnpair(s, unpair1End, nullptr);\n\n        if (now() < shrinkEnd) {\n            exactDepthShrink(s, plan, shrinkEnd);\n        }\n\n        if (now() < unpair2End) {\n            plan = optimizeUnpair(s, unpair2End, &plan);\n        }\n\n        sanitizePlan(plan, s);\n        vector<Op> ans = buildOps(s, plan);\n\n        if (now() < pruneEnd) {\n            pruneOps(ans, pruneEnd);\n        }\n\n        if (!checkOpsValid(ans)) {\n            UPlan empty = emptyPlan();\n            vector<Op> safe = buildOps(guaranteed, empty);\n            if (checkOpsValid(safe)) {\n                ans.swap(safe);\n            } else {\n                vector<Op> fb = fallbackPerOni();\n                if (checkOpsValid(fb)) ans.swap(fb);\n                else ans = fb;\n            }\n        }\n\n        if ((int)ans.size() > 4 * N * N) {\n            vector<Op> fb = fallbackPerOni();\n            if (checkOpsValid(fb)) ans.swap(fb);\n        }\n\n        return ans;\n    }\n\nprivate:\n    inline double now() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline double rand01() {\n        return (double)(rng() & ((1u << 24) - 1)) / (double)(1u << 24);\n    }\n    static bool isOppDir(char a, char b) {\n        return (a == 'L' && b == 'R') || (a == 'R' && b == 'L') ||\n               (a == 'U' && b == 'D') || (a == 'D' && b == 'U');\n    }\n\n    inline int idUp(int j) const { return j; }\n    inline int idDown(int j) const { return N + j; }\n    inline int idLeft(int i) const { return 2 * N + i; }\n    inline int idRight(int i) const { return 3 * N + i; }\n\n    void build() {\n        for (int i = 0; i < MAXN; i++) for (int j = 0; j < MAXN; j++) initGrid[i][j] = '.';\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) {\n            initGrid[i][j] = board[i][j];\n            if (board[i][j] == 'x') oniPos.push_back({i, j});\n            if (board[i][j] == 'o') initialFuku++;\n        }\n        M = (int)oniPos.size();\n        opts.assign(M, {});\n\n        vector<int> upSafe(N, N), downSafe(N, N), leftSafe(N, N), rightSafe(N, N);\n\n        for (int j = 0; j < N; j++) {\n            for (int i = 0; i < N; i++) if (board[i][j] == 'o') { upSafe[j] = i; break; }\n            for (int i = N - 1; i >= 0; i--) if (board[i][j] == 'o') { downSafe[j] = N - 1 - i; break; }\n        }\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) if (board[i][j] == 'o') { leftSafe[i] = j; break; }\n            for (int j = N - 1; j >= 0; j--) if (board[i][j] == 'o') { rightSafe[i] = N - 1 - j; break; }\n        }\n\n        for (int j = 0; j < N; j++) {\n            chains[idUp(j)] = {'U', 'D', j};\n            chains[idDown(j)] = {'D', 'U', j};\n        }\n        for (int i = 0; i < N; i++) {\n            chains[idLeft(i)] = {'L', 'R', i};\n            chains[idRight(i)] = {'R', 'L', i};\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto [r, c] = oniPos[m];\n            int reqU = r + 1, reqD = N - r, reqL = c + 1, reqR = N - c;\n            if (reqU <= upSafe[c]) opts[m].push_back({idUp(c), reqU});\n            if (reqD <= downSafe[c]) opts[m].push_back({idDown(c), reqD});\n            if (reqL <= leftSafe[r]) opts[m].push_back({idLeft(r), reqL});\n            if (reqR <= rightSafe[r]) opts[m].push_back({idRight(r), reqR});\n            if (opts[m].empty()) opts[m].push_back({idUp(c), min(reqU, N)}); // safety\n        }\n\n        for (int c = 0; c < MAXC; c++) {\n            cap[c] = 0;\n            usefulDepths[c].clear();\n            for (int d = 0; d <= MAXD; d++) {\n                eqMask[c][d] = 0;\n                leMask[c][d] = 0;\n            }\n        }\n\n        for (int m = 0; m < M; m++) {\n            for (auto &op : opts[m]) eqMask[op.chain][op.req] |= (1ULL << m);\n        }\n\n        for (int c = 0; c < Cn; c++) {\n            leMask[c][0] = 0;\n            for (int d = 1; d <= N; d++) {\n                leMask[c][d] = leMask[c][d - 1] | eqMask[c][d];\n                if (eqMask[c][d]) {\n                    usefulDepths[c].push_back(d);\n                    cap[c] = d;\n                }\n            }\n        }\n\n        fullMask = (M == 64 ? ~0ULL : ((1ULL << M) - 1ULL));\n    }\n\n    // ---------- State ----------\n    State makeZeroState() const {\n        State s;\n        s.d.fill(0);\n        s.sat.fill(0);\n        s.unsatMask = fullMask;\n        s.cost = 0;\n        return s;\n    }\n\n    inline void incChain(State &s, int c) {\n        int nd = (int)s.d[c] + 1;\n        uint64_t bits = eqMask[c][nd];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            if (s.sat[m]++ == 0) s.unsatMask &= ~(1ULL << m);\n        }\n        s.d[c] = (uint8_t)nd;\n        s.cost += 2;\n    }\n\n    inline void decChain(State &s, int c) {\n        int t = (int)s.d[c];\n        uint64_t bits = eqMask[c][t];\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            uint8_t v = --s.sat[m];\n            if (v == 0) s.unsatMask |= (1ULL << m);\n        }\n        s.d[c] = (uint8_t)(t - 1);\n        s.cost -= 2;\n    }\n\n    inline void setChain(State &s, int c, int nd) {\n        while ((int)s.d[c] < nd) incChain(s, c);\n        while ((int)s.d[c] > nd) decChain(s, c);\n    }\n\n    State fromDepth(const array<uint8_t, MAXC>& depth) {\n        State s = makeZeroState();\n        for (int c = 0; c < Cn; c++) {\n            for (int t = 0; t < (int)depth[c]; t++) incChain(s, c);\n        }\n        return s;\n    }\n\n    void reduceDepth(State &s, bool randomOrder) {\n        array<int, MAXC> ord{};\n        for (int i = 0; i < Cn; i++) ord[i] = i;\n        if (randomOrder) shuffle(ord.begin(), ord.begin() + Cn, rng);\n\n        for (int ii = 0; ii < Cn; ii++) {\n            int c = ord[ii];\n            while ((int)s.d[c] > 0) {\n                int t = (int)s.d[c];\n                uint64_t bits = eqMask[c][t];\n                bool ok = true;\n                while (bits) {\n                    int m = __builtin_ctzll(bits);\n                    bits &= bits - 1;\n                    if (s.sat[m] == 1) { ok = false; break; }\n                }\n                if (!ok) break;\n                decChain(s, c);\n            }\n        }\n    }\n\n    bool exactRepairSmall(State &s) {\n        int k = __builtin_popcountll(s.unsatMask);\n        if (k == 0) return true;\n        if (k > 10) return false;\n\n        vector<int> uns;\n        uns.reserve(k);\n        int loc[MAXM];\n        for (int i = 0; i < MAXM; i++) loc[i] = -1;\n\n        uint64_t bits = s.unsatMask;\n        while (bits) {\n            int m = __builtin_ctzll(bits);\n            bits &= bits - 1;\n            loc[m] = (int)uns.size();\n            uns.push_back(m);\n        }\n\n        int S = 1 << k;\n        const int INF = 1e9;\n\n        static int dp[1 << 10], ndp[1 << 10];\n        struct Parent { uint16_t prev; uint8_t dep; uint8_t used; };\n        static Parent par[MAXC + 1][1 << 10];\n\n        for (int mask = 0; mask < S; mask++) dp[mask] = INF;\n        dp[0] = 0;\n\n        for (int c = 0; c < Cn; c++) {\n            for (int mask = 0; mask < S; mask++) ndp[mask] = INF;\n\n            for (int mask = 0; mask < S; mask++) {\n                if (dp[mask] < ndp[mask]) {\n                    ndp[mask] = dp[mask];\n                    par[c + 1][mask] = {(uint16_t)mask, 0, 0};\n                }\n            }\n\n            if ((int)s.d[c] < cap[c]) {\n                static int bestCost[1 << 10];\n                static uint8_t bestDep[1 << 10];\n                for (int i = 0; i < S; i++) { bestCost[i] = INF; bestDep[i] = 0; }\n\n                for (int r = (int)s.d[c] + 1; r <= cap[c]; r++) {\n                    uint64_t gm = leMask[c][r] & s.unsatMask;\n                    if (!gm) continue;\n                    int lm = 0;\n                    uint64_t t = gm;\n                    while (t) {\n                        int m = __builtin_ctzll(t);\n                        t &= t - 1;\n                        lm |= (1 << loc[m]);\n                    }\n                    int add = r - (int)s.d[c];\n                    if (add < bestCost[lm]) {\n                        bestCost[lm] = add;\n                        bestDep[lm] = (uint8_t)r;\n                    }\n                }\n\n                vector<tuple<int,int,uint8_t>> cand;\n                cand.reserve(S);\n                for (int lm = 1; lm < S; lm++) if (bestCost[lm] < INF) {\n                    cand.emplace_back(lm, bestCost[lm], bestDep[lm]);\n                }\n\n                for (int mask = 0; mask < S; mask++) {\n                    if (dp[mask] >= INF) continue;\n                    for (auto [lm, add, dep] : cand) {\n                        int nm = mask | lm;\n                        int val = dp[mask] + add;\n                        if (val < ndp[nm]) {\n                            ndp[nm] = val;\n                            par[c + 1][nm] = {(uint16_t)mask, dep, 1};\n                        }\n                    }\n                }\n            }\n\n            for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n        }\n\n        int target = S - 1;\n        if (dp[target] >= INF) return false;\n\n        array<uint8_t, MAXC> tgt = s.d;\n        int mask = target;\n        for (int c = Cn; c >= 1; c--) {\n            auto p = par[c][mask];\n            if (p.used) {\n                int chain = c - 1;\n                tgt[chain] = max<int>(tgt[chain], p.dep);\n            }\n            mask = p.prev;\n        }\n\n        for (int c = 0; c < Cn; c++) setChain(s, c, tgt[c]);\n        return (s.unsatMask == 0);\n    }\n\n    void greedyRepair(State &s, bool randomized) {\n        while (s.unsatMask) {\n            int unsCnt = __builtin_popcountll(s.unsatMask);\n            if (unsCnt <= 10) {\n                if (exactRepairSmall(s)) return;\n            }\n\n            double bestScore = -1e100;\n            int bc = -1, br = -1;\n            int bg = -1, bdelta = 1e9;\n\n            for (int c = 0; c < Cn; c++) {\n                int dc = (int)s.d[c];\n                if (dc >= cap[c]) continue;\n                for (int r : usefulDepths[c]) {\n                    if (r <= dc) continue;\n                    uint64_t gainMask = leMask[c][r] & s.unsatMask;\n                    int g = __builtin_popcountll(gainMask);\n                    if (g == 0) continue;\n                    int delta = r - dc;\n                    double score = (double)g / (double)delta;\n                    if (randomized) score += (double)(rng() & 1023) * 1e-6;\n\n                    if (score > bestScore + 1e-12 ||\n                        (fabs(score - bestScore) <= 1e-12 &&\n                         (g > bg || (g == bg && delta < bdelta)))) {\n                        bestScore = score;\n                        bc = c; br = r; bg = g; bdelta = delta;\n                    }\n                }\n            }\n\n            if (bc == -1) {\n                int m = __builtin_ctzll(s.unsatMask);\n                int bestDelta = 1e9;\n                for (auto &op : opts[m]) {\n                    int delta = max(0, op.req - (int)s.d[op.chain]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bc = op.chain;\n                        br = op.req;\n                    }\n                }\n                if (bc == -1) break;\n            }\n\n            setChain(s, bc, br);\n        }\n    }\n\n    // ---------- objective proxy ----------\n    int rowSave(const State &s) const {\n        int sv = 0;\n        for (int i = 0; i < N; i++) {\n            int l = s.d[idLeft(i)], r = s.d[idRight(i)];\n            if (l == 0 || r == 0) sv += l + r;\n            else sv += max(l, r);\n        }\n        return sv;\n    }\n    int colSave(const State &s) const {\n        int sv = 0;\n        for (int j = 0; j < N; j++) {\n            int u = s.d[idUp(j)], d = s.d[idDown(j)];\n            if (u == 0 || d == 0) sv += u + d;\n            else sv += max(u, d);\n        }\n        return sv;\n    }\n    int estimateMoves(const State &s) const {\n        return s.cost - max(rowSave(s), colSave(s));\n    }\n\n    State baselineMinReq() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            depth[op.chain] = max<int>(depth[op.chain], op.req);\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, false);\n        return s;\n    }\n\n    State trialAssign() {\n        array<uint8_t, MAXC> depth{};\n        depth.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n        stable_sort(ord.begin(), ord.end(),\n                    [&](int a, int b) { return opts[a].size() < opts[b].size(); });\n\n        for (int m : ord) {\n            int choose = 0;\n            if ((int)(rng() % 100) < 8) {\n                choose = (int)(rng() % opts[m].size());\n            } else {\n                int bestKey = 1e9;\n                vector<int> cand;\n                for (int i = 0; i < (int)opts[m].size(); i++) {\n                    auto op = opts[m][i];\n                    int delta = max(0, op.req - (int)depth[op.chain]);\n                    int key = delta * 64 + op.req;\n                    if (key < bestKey) {\n                        bestKey = key;\n                        cand.clear();\n                        cand.push_back(i);\n                    } else if (key == bestKey) {\n                        cand.push_back(i);\n                    }\n                }\n                choose = cand[(int)(rng() % cand.size())];\n            }\n\n            auto op = opts[m][choose];\n            if (op.req > depth[op.chain]) depth[op.chain] = op.req;\n        }\n\n        State s = fromDepth(depth);\n        reduceDepth(s, true);\n        if ((rng() % 100) < 30) reduceDepth(s, true);\n        return s;\n    }\n\n    State trialCover(bool randomized) {\n        State s = makeZeroState();\n        greedyRepair(s, randomized);\n        if (s.unsatMask == 0) {\n            reduceDepth(s, true);\n            if (randomized && (rng() % 100) < 30) reduceDepth(s, true);\n        }\n        return s;\n    }\n\n    int pickNonZeroChain(const State &s) {\n        for (int t = 0; t < 24; t++) {\n            int c = (int)(rng() % Cn);\n            if (s.d[c] > 0) return c;\n        }\n        int cnt = 0;\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) cnt++;\n        if (cnt == 0) return -1;\n        int k = (int)(rng() % cnt);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) if (k-- == 0) return c;\n        return -1;\n    }\n\n    State optimizeDepth(double endTime) {\n        State best = baselineMinReq();\n        int bestObj = estimateMoves(best);\n\n        State c0 = trialCover(false);\n        if (c0.unsatMask == 0) {\n            int c0Obj = estimateMoves(c0);\n            if (c0Obj < bestObj || (c0Obj == bestObj && c0.cost < best.cost)) {\n                best = c0;\n                bestObj = c0Obj;\n            }\n        }\n\n        int itInit = 0;\n        while (now() < 0.30) {\n            State cand = (itInit % 2 == 0 ? trialAssign() : trialCover(true));\n            itInit++;\n            if (cand.unsatMask) continue;\n            int obj = estimateMoves(cand);\n            if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = obj;\n            }\n        }\n\n        State cur = best;\n        int curObj = bestObj;\n        int iter = 0;\n\n        while (now() < endTime) {\n            iter++;\n            State cand = cur;\n\n            int k = 1 + (int)(rng() % 4);\n            if ((rng() % 100) < 20) k++;\n\n            for (int t = 0; t < k; t++) {\n                int c = pickNonZeroChain(cand);\n                if (c < 0) break;\n                int old = cand.d[c];\n                int nd;\n                int r = (int)(rng() % 100);\n                if (r < 55) nd = old - 1;\n                else if (r < 85) {\n                    int dec = 1 + (int)(rng() % max(1, min(4, old)));\n                    nd = max(0, old - dec);\n                } else {\n                    nd = (int)(rng() % (old + 1));\n                }\n                setChain(cand, c, nd);\n            }\n\n            if ((rng() % 100) < 10) {\n                int c = (int)(rng() % Cn);\n                if ((int)cand.d[c] < cap[c] && cap[c] > 0) {\n                    int nd = min(cap[c], (int)cand.d[c] + 1 + (int)(rng() % 3));\n                    setChain(cand, c, nd);\n                }\n            }\n\n            greedyRepair(cand, true);\n            if (cand.unsatMask) continue;\n\n            reduceDepth(cand, true);\n            if ((rng() % 100) < 35) reduceDepth(cand, true);\n\n            int candObj = estimateMoves(cand);\n            double prog = min(1.0, now() / endTime);\n            double temp = 5.0 * pow(0.03 / 5.0, prog);\n            int delta = candObj - curObj;\n\n            bool accept = false;\n            if (delta <= 0) {\n                accept = true;\n            } else {\n                double prob = exp(-delta / temp);\n                if (rand01() < prob) accept = true;\n            }\n\n            if (accept) {\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if (candObj < bestObj || (candObj == bestObj && cand.cost < best.cost)) {\n                best = cand;\n                bestObj = candObj;\n                cur = cand;\n                curObj = candObj;\n            }\n\n            if ((iter % 300) == 0 && (rng() % 100) < 40) {\n                cur = best;\n                curObj = bestObj;\n            }\n        }\n\n        vector<int> ord(Cn);\n        iota(ord.begin(), ord.end(), 0);\n        auto sortOrd = [&]() {\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return best.d[a] > best.d[b];\n            });\n        };\n        sortOrd();\n\n        bool improved = true;\n        while (improved && now() < endTime) {\n            improved = false;\n            for (int c : ord) {\n                if (now() >= endTime) break;\n                if (best.d[c] == 0) continue;\n                State cand = best;\n                setChain(cand, c, 0);\n                greedyRepair(cand, false);\n                if (cand.unsatMask) continue;\n                reduceDepth(cand, true);\n                int obj = estimateMoves(cand);\n                if (obj < bestObj || (obj == bestObj && cand.cost < best.cost)) {\n                    best = cand;\n                    bestObj = obj;\n                    improved = true;\n                    sortOrd();\n                    break;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    // ---------- simulation ----------\n    inline bool applyShift(Grid &g, char d, int p, int &oniLeft) const {\n        char out = '.';\n        if (d == 'L') {\n            out = g[p][0];\n            for (int j = 0; j + 1 < N; j++) g[p][j] = g[p][j + 1];\n            g[p][N - 1] = '.';\n        } else if (d == 'R') {\n            out = g[p][N - 1];\n            for (int j = N - 1; j >= 1; j--) g[p][j] = g[p][j - 1];\n            g[p][0] = '.';\n        } else if (d == 'U') {\n            out = g[0][p];\n            for (int i = 0; i + 1 < N; i++) g[i][p] = g[i + 1][p];\n            g[N - 1][p] = '.';\n        } else { // D\n            out = g[N - 1][p];\n            for (int i = N - 1; i >= 1; i--) g[i][p] = g[i - 1][p];\n            g[0][p] = '.';\n        }\n\n        if (out == 'o') return false;\n        if (out == 'x') oniLeft--;\n        return true;\n    }\n\n    bool checkOpsValid(const vector<Op> &ops) const {\n        if ((int)ops.size() > 4 * N * N) return false;\n        Grid g = initGrid;\n        int oniLeft = M;\n        for (auto [d, p] : ops) {\n            if (!applyShift(g, d, p, oniLeft)) return false;\n        }\n        return oniLeft == 0;\n    }\n\n    // ---------- unpair plan ----------\n    UPlan emptyPlan() const {\n        UPlan p;\n        p.in.fill(0);\n        p.ord.clear();\n        p.save = 0;\n        return p;\n    }\n\n    int computeSave(const State &s, const UPlan &p) const {\n        int sv = 0;\n        for (int c : p.ord) sv += s.d[c];\n        return sv;\n    }\n\n    void sanitizePlan(UPlan &p, const State &s) const {\n        array<uint8_t, MAXC> used{};\n        used.fill(0);\n\n        vector<int> v;\n        v.reserve(p.ord.size());\n\n        for (int c : p.ord) {\n            if (c < 0 || c >= Cn) continue;\n            if (used[c]) continue;\n            if (!p.in[c]) continue;\n            if (s.d[c] == 0) continue;\n            used[c] = 1;\n            v.push_back(c);\n        }\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c] && s.d[c] > 0 && !used[c]) {\n                used[c] = 1;\n                v.push_back(c);\n            }\n        }\n\n        p.ord.swap(v);\n        p.in.fill(0);\n        for (int c : p.ord) p.in[c] = 1;\n        p.save = computeSave(s, p);\n    }\n\n    UPlan makeRowPlan(const State &s, bool tieRight) const {\n        UPlan p = emptyPlan();\n        for (int i = 0; i < N; i++) {\n            int lc = idLeft(i), rc = idRight(i);\n            int l = s.d[lc], r = s.d[rc];\n            if (l == 0 && r == 0) continue;\n            int ch;\n            if (l > r) ch = lc;\n            else if (r > l) ch = rc;\n            else ch = tieRight ? rc : lc;\n            if (s.d[ch] > 0) {\n                p.ord.push_back(ch);\n                p.in[ch] = 1;\n            }\n        }\n        p.save = computeSave(s, p);\n        return p;\n    }\n\n    UPlan makeColPlan(const State &s, bool tieDown) const {\n        UPlan p = emptyPlan();\n        for (int j = 0; j < N; j++) {\n            int uc = idUp(j), dc = idDown(j);\n            int u = s.d[uc], d = s.d[dc];\n            if (u == 0 && d == 0) continue;\n            int ch;\n            if (u > d) ch = uc;\n            else if (d > u) ch = dc;\n            else ch = tieDown ? dc : uc;\n            if (s.d[ch] > 0) {\n                p.ord.push_back(ch);\n                p.in[ch] = 1;\n            }\n        }\n        p.save = computeSave(s, p);\n        return p;\n    }\n\n    int pickNotIn(const UPlan &p, const vector<int> &active) {\n        if ((int)p.ord.size() >= (int)active.size()) return -1;\n        for (int t = 0; t < 24; t++) {\n            int c = active[(int)(rng() % active.size())];\n            if (!p.in[c]) return c;\n        }\n        for (int c : active) if (!p.in[c]) return c;\n        return -1;\n    }\n\n    bool checkPlanValid(const State &s, const UPlan &p) const {\n        if (s.cost - p.save > 4 * N * N) return false;\n        Grid g = initGrid;\n        int oniLeft = M;\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c]) continue;\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].dir, chains[c].idx, oniLeft)) return false;\n            }\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].rev, chains[c].idx, oniLeft)) return false;\n            }\n        }\n\n        for (int c : p.ord) {\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) {\n                if (!applyShift(g, chains[c].dir, chains[c].idx, oniLeft)) return false;\n            }\n        }\n\n        return oniLeft == 0;\n    }\n\n    UPlan optimizeUnpair(const State &s, double endTime, const UPlan *seed) {\n        vector<UPlan> seeds;\n        seeds.reserve(8);\n        seeds.push_back(emptyPlan());\n        seeds.push_back(makeRowPlan(s, false));\n        seeds.push_back(makeRowPlan(s, true));\n        seeds.push_back(makeColPlan(s, false));\n        seeds.push_back(makeColPlan(s, true));\n        if (seed) seeds.push_back(*seed);\n\n        UPlan best = emptyPlan();\n        bool hasBest = false;\n\n        for (auto &p : seeds) {\n            if (now() >= endTime) break;\n            sanitizePlan(p, s);\n            if (checkPlanValid(s, p)) {\n                if (!hasBest || p.save > best.save) {\n                    best = p;\n                    hasBest = true;\n                }\n            }\n        }\n        if (!hasBest) return emptyPlan();\n\n        vector<int> active;\n        active.reserve(Cn);\n        for (int c = 0; c < Cn; c++) if (s.d[c] > 0) active.push_back(c);\n        if (active.empty()) return best;\n\n        UPlan cur = best;\n        double greedyEnd = min(endTime, now() + (endTime - now()) * 0.40);\n\n        while (now() < greedyEnd) {\n            bool improved = false;\n            vector<int> cand;\n            cand.reserve(active.size());\n            for (int c : active) if (!cur.in[c]) cand.push_back(c);\n            if (cand.empty()) break;\n\n            shuffle(cand.begin(), cand.end(), rng);\n            sort(cand.begin(), cand.end(), [&](int a, int b) {\n                if (s.d[a] != s.d[b]) return s.d[a] > s.d[b];\n                return a < b;\n            });\n\n            for (int c : cand) {\n                if (now() >= greedyEnd) break;\n                int sz = (int)cur.ord.size();\n\n                vector<int> pos;\n                pos.reserve(sz + 1);\n                pos.push_back(sz);\n                if (sz > 0) pos.push_back(0);\n                for (int i = 1; i < sz; i++) pos.push_back(i);\n                if ((int)pos.size() > 2) shuffle(pos.begin() + 2, pos.end(), rng);\n\n                bool ok = false;\n                for (int pidx : pos) {\n                    UPlan q = cur;\n                    q.ord.insert(q.ord.begin() + pidx, c);\n                    q.in[c] = 1;\n                    q.save = computeSave(s, q);\n                    if (checkPlanValid(s, q)) {\n                        cur = move(q);\n                        if (cur.save > best.save) best = cur;\n                        improved = true;\n                        ok = true;\n                        break;\n                    }\n                }\n                if (ok) break;\n            }\n\n            if (!improved) break;\n        }\n\n        cur = best;\n        double saStart = now();\n\n        while (now() < endTime) {\n            UPlan cand = cur;\n            bool moved = false;\n            int typ = (int)(rng() % 100);\n            int sz = (int)cand.ord.size();\n\n            if (typ < 35) { // add\n                int c = pickNotIn(cand, active);\n                if (c != -1) {\n                    int pos = (int)(rng() % (sz + 1));\n                    cand.ord.insert(cand.ord.begin() + pos, c);\n                    cand.in[c] = 1;\n                    moved = true;\n                }\n            } else if (typ < 55) { // remove\n                if (sz > 0) {\n                    int idx = (int)(rng() % sz);\n                    int c = cand.ord[idx];\n                    cand.ord.erase(cand.ord.begin() + idx);\n                    cand.in[c] = 0;\n                    moved = true;\n                }\n            } else if (typ < 75) { // swap\n                if (sz >= 2) {\n                    int i = (int)(rng() % sz), j = (int)(rng() % sz);\n                    if (i != j) {\n                        swap(cand.ord[i], cand.ord[j]);\n                        moved = true;\n                    }\n                }\n            } else if (typ < 90) { // move\n                if (sz >= 2) {\n                    int i = (int)(rng() % sz);\n                    int c = cand.ord[i];\n                    cand.ord.erase(cand.ord.begin() + i);\n                    int pos = (int)(rng() % sz); // after erase size is sz-1\n                    cand.ord.insert(cand.ord.begin() + pos, c);\n                    moved = true;\n                }\n            } else { // replace\n                if (sz > 0) {\n                    int idx = (int)(rng() % sz);\n                    int oldc = cand.ord[idx];\n                    cand.ord.erase(cand.ord.begin() + idx);\n                    cand.in[oldc] = 0;\n                    int nc = pickNotIn(cand, active);\n                    if (nc != -1) {\n                        int pos = (int)(rng() % ((int)cand.ord.size() + 1));\n                        cand.ord.insert(cand.ord.begin() + pos, nc);\n                        cand.in[nc] = 1;\n                        moved = true;\n                    } else {\n                        cand.ord.insert(cand.ord.begin() + idx, oldc);\n                        cand.in[oldc] = 1;\n                    }\n                }\n            }\n\n            if (!moved) continue;\n\n            cand.save = computeSave(s, cand);\n            if (!checkPlanValid(s, cand)) continue;\n\n            int delta = cand.save - cur.save;\n            double denom = max(1e-9, endTime - saStart);\n            double rem = (endTime - now()) / denom;\n            rem = max(0.0, min(1.0, rem));\n            double temp = 1.5 * rem + 0.03;\n\n            if (delta >= 0 || rand01() < exp((double)delta / temp)) {\n                cur = cand;\n            }\n            if (cand.save > best.save) best = cand;\n        }\n\n        sanitizePlan(best, s);\n        return best;\n    }\n\n    // Stepwise exact shrink\n    void exactDepthShrink(State &s, UPlan &p, double endTime) {\n        sanitizePlan(p, s);\n        if (!checkPlanValid(s, p)) return;\n\n        bool improved = true;\n        while (improved && now() < endTime) {\n            improved = false;\n            vector<int> ord(Cn);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b){ return s.d[a] > s.d[b]; });\n\n            for (int c : ord) {\n                if (now() >= endTime) break;\n                while (s.d[c] > 0 && now() < endTime) {\n                    State cand = s;\n                    setChain(cand, c, (int)s.d[c] - 1);\n\n                    UPlan q = p;\n                    if (q.in[c] && cand.d[c] == 0) {\n                        q.in[c] = 0;\n                        auto it = find(q.ord.begin(), q.ord.end(), c);\n                        if (it != q.ord.end()) q.ord.erase(it);\n                    }\n                    sanitizePlan(q, cand);\n\n                    if (checkPlanValid(cand, q)) {\n                        s = move(cand);\n                        p = move(q);\n                        improved = true;\n                    } else break;\n                }\n            }\n        }\n\n        sanitizePlan(p, s);\n    }\n\n    vector<Op> buildOps(const State &s, const UPlan &p) const {\n        vector<Op> ops;\n        ops.reserve(max(0, s.cost - p.save) + 16);\n\n        for (int c = 0; c < Cn; c++) {\n            if (p.in[c]) continue;\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].rev, chains[c].idx});\n        }\n        for (int c : p.ord) {\n            int k = s.d[c];\n            for (int t = 0; t < k; t++) ops.push_back({chains[c].dir, chains[c].idx});\n        }\n        return ops;\n    }\n\n    bool tryEraseRange(vector<Op> &ops, int l, int r) {\n        if (l < 0 || r > (int)ops.size() || l >= r) return false;\n        vector<Op> cand;\n        cand.reserve((int)ops.size() - (r - l));\n        cand.insert(cand.end(), ops.begin(), ops.begin() + l);\n        cand.insert(cand.end(), ops.begin() + r, ops.end());\n        if (checkOpsValid(cand)) {\n            ops.swap(cand);\n            return true;\n        }\n        return false;\n    }\n\n    bool tryEraseIndices(vector<Op> &ops, vector<int> idx) {\n        if (idx.empty()) return false;\n        sort(idx.begin(), idx.end());\n        idx.erase(unique(idx.begin(), idx.end()), idx.end());\n        if (idx.front() < 0 || idx.back() >= (int)ops.size()) return false;\n\n        vector<Op> cand;\n        cand.reserve((int)ops.size() - (int)idx.size());\n        int p = 0;\n        for (int i = 0; i < (int)ops.size(); i++) {\n            if (p < (int)idx.size() && idx[p] == i) { p++; continue; }\n            cand.push_back(ops[i]);\n        }\n\n        if (checkOpsValid(cand)) {\n            ops.swap(cand);\n            return true;\n        }\n        return false;\n    }\n\n    void pruneOps(vector<Op> &ops, double endTime) {\n        if (!checkOpsValid(ops)) return;\n\n        struct Run {\n            int l, r;\n            char d;\n            int p;\n        };\n        auto buildRuns = [&](const vector<Op>& v) {\n            vector<Run> runs;\n            runs.reserve(v.size());\n            for (int l = 0; l < (int)v.size(); ) {\n                int r = l + 1;\n                while (r < (int)v.size() && v[r] == v[l]) r++;\n                runs.push_back({l, r, v[l].first, v[l].second});\n                l = r;\n            }\n            return runs;\n        };\n\n        // Deterministic phase\n        while (now() < endTime) {\n            bool changed = false;\n\n            // backward single deletion\n            for (int i = (int)ops.size() - 1; i >= 0 && now() < endTime; --i) {\n                if (tryEraseRange(ops, i, i + 1)) changed = true;\n            }\n\n            // backward pair deletion\n            for (int i = (int)ops.size() - 2; i >= 0 && now() < endTime; --i) {\n                if (tryEraseRange(ops, i, i + 2)) changed = true;\n            }\n\n            // delete whole contiguous runs\n            bool runChanged = true;\n            while (runChanged && now() < endTime) {\n                runChanged = false;\n                auto runs = buildRuns(ops);\n\n                vector<tuple<int,int,int>> cand; // len,l,r\n                for (auto &ru : runs) {\n                    int len = ru.r - ru.l;\n                    if (len >= 3) cand.emplace_back(len, ru.l, ru.r);\n                }\n                sort(cand.begin(), cand.end(), [](auto &a, auto &b) {\n                    if (get<0>(a) != get<0>(b)) return get<0>(a) > get<0>(b);\n                    return get<1>(a) > get<1>(b);\n                });\n\n                for (auto [len, l, r] : cand) {\n                    if (now() >= endTime) break;\n                    if (tryEraseRange(ops, l, r)) {\n                        runChanged = true;\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            // delete adjacent opposite-run blocks on same line\n            bool oppChanged = true;\n            while (oppChanged && now() < endTime) {\n                oppChanged = false;\n                auto runs = buildRuns(ops);\n\n                vector<tuple<int,int,int>> cand; // totalLen,l,r\n                for (int i = 0; i + 1 < (int)runs.size(); i++) {\n                    auto &A = runs[i];\n                    auto &B = runs[i + 1];\n                    if (A.p == B.p && isOppDir(A.d, B.d)) {\n                        int len = (A.r - A.l) + (B.r - B.l);\n                        if (len >= 4) cand.emplace_back(len, A.l, B.r);\n                    }\n                }\n                sort(cand.begin(), cand.end(), [](auto &a, auto &b) {\n                    if (get<0>(a) != get<0>(b)) return get<0>(a) > get<0>(b);\n                    return get<1>(a) > get<1>(b);\n                });\n\n                for (auto [len, l, r] : cand) {\n                    if (now() >= endTime) break;\n                    if (tryEraseRange(ops, l, r)) {\n                        oppChanged = true;\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            // NEW: symmetric center trim for adjacent opposite-run pairs\n            bool trimChanged = true;\n            while (trimChanged && now() < endTime) {\n                trimChanged = false;\n                auto runs = buildRuns(ops);\n\n                vector<tuple<int,int,int>> cand; // k, l, r\n                for (int i = 0; i + 1 < (int)runs.size(); i++) {\n                    auto &A = runs[i];\n                    auto &B = runs[i + 1];\n                    if (A.p == B.p && isOppDir(A.d, B.d)) {\n                        int la = A.r - A.l, lb = B.r - B.l;\n                        int k = min(la, lb);\n                        if (k >= 1) {\n                            cand.emplace_back(k, A.r - k, B.l + k);\n                        }\n                    }\n                }\n                sort(cand.begin(), cand.end(), [](auto &x, auto &y) {\n                    if (get<0>(x) != get<0>(y)) return get<0>(x) > get<0>(y);\n                    return get<1>(x) > get<1>(y);\n                });\n\n                for (auto [k, l, r] : cand) {\n                    if (now() >= endTime) break;\n                    if (tryEraseRange(ops, l, r)) {\n                        trimChanged = true;\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        // Random block / random multi-index deletion\n        int fail = 0;\n        while (now() < endTime) {\n            int n = (int)ops.size();\n            if (n == 0) break;\n\n            bool ok = false;\n            int typ = (int)(rng() % 100);\n\n            if (typ < 20) {\n                auto runs = buildRuns(ops);\n                vector<int> candIdx;\n                for (int i = 0; i + 1 < (int)runs.size(); i++) {\n                    if (runs[i].p == runs[i + 1].p && isOppDir(runs[i].d, runs[i + 1].d)) {\n                        candIdx.push_back(i);\n                    }\n                }\n                if (!candIdx.empty()) {\n                    int i = candIdx[(int)(rng() % candIdx.size())];\n                    auto &A = runs[i];\n                    auto &B = runs[i + 1];\n                    int la = A.r - A.l, lb = B.r - B.l;\n                    int k = min(la, lb);\n                    int t = (rng() % 100 < 60 ? k : 1);\n                    if (t >= 1) ok = tryEraseRange(ops, A.r - t, B.l + t);\n                }\n            }\n\n            if (!ok) {\n                if (typ < 70) {\n                    int maxLen = min(40, n);\n                    int rr = (int)(rng() % 100);\n                    int len;\n                    if (rr < 60) {\n                        int lim = min(6, maxLen);\n                        len = 1 + (int)(rng() % lim);\n                    } else if (rr < 90) {\n                        int lim = min(12, maxLen);\n                        len = 1 + (int)(rng() % lim);\n                    } else {\n                        len = 1 + (int)(rng() % maxLen);\n                    }\n                    int l = (int)(rng() % (n - len + 1));\n                    ok = tryEraseRange(ops, l, l + len);\n                } else if (typ < 90) {\n                    int i = (int)(rng() % n);\n                    int l = i, r = i + 1;\n                    while (l > 0 && ops[l - 1] == ops[i]) l--;\n                    while (r < n && ops[r] == ops[i]) r++;\n                    if (r - l >= 2) ok = tryEraseRange(ops, l, r);\n                    else {\n                        int len = min(2 + (int)(rng() % 6), n);\n                        int ll = (int)(rng() % (n - len + 1));\n                        ok = tryEraseRange(ops, ll, ll + len);\n                    }\n                } else {\n                    if (n == 1) {\n                        ok = tryEraseRange(ops, 0, 1);\n                    } else {\n                        int kmax = min(4, n);\n                        int k = 2 + (int)(rng() % (kmax - 1)); // 2..kmax\n                        vector<int> idx(n);\n                        iota(idx.begin(), idx.end(), 0);\n                        shuffle(idx.begin(), idx.end(), rng);\n                        idx.resize(k);\n                        ok = tryEraseIndices(ops, idx);\n                    }\n                }\n            }\n\n            if (ok) {\n                fail = 0;\n                if ((rng() % 100) < 25 && now() < endTime) {\n                    int m = (int)ops.size();\n                    if (m > 0) {\n                        int p = (int)(rng() % m);\n                        int L = max(0, p - 3), R = min(m, p + 4);\n                        for (int i = R - 1; i >= L && now() < endTime; --i) {\n                            tryEraseRange(ops, i, i + 1);\n                        }\n                    }\n                }\n            } else {\n                fail++;\n                if (fail > 4000 && now() > endTime - 0.02) break;\n            }\n        }\n\n        // final quick pass\n        for (int rep = 0; rep < 2 && now() < endTime; rep++) {\n            bool any = false;\n            for (int i = (int)ops.size() - 1; i >= 0 && now() < endTime; --i) {\n                if (tryEraseRange(ops, i, i + 1)) any = true;\n            }\n            if (!any) break;\n        }\n    }\n\n    vector<Op> fallbackPerOni() const {\n        vector<Op> ops;\n        ops.reserve(1600);\n\n        for (int m = 0; m < M; m++) {\n            int bi = 0;\n            for (int i = 1; i < (int)opts[m].size(); i++) {\n                if (opts[m][i].req < opts[m][bi].req) bi = i;\n            }\n            auto op = opts[m][bi];\n            const auto& ch = chains[op.chain];\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.dir, ch.idx});\n            for (int t = 0; t < op.req; t++) ops.push_back({ch.rev, ch.idx});\n        }\n        return ops;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    Solver solver(N, C);\n    auto ans = solver.solve();\n\n    for (auto [d, p] : ans) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\nstatic inline long long absl(long long x) { return x < 0 ? -x : x; }\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    inline uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    inline double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct State {\n    array<int, MAXN> a{}, b{};\n    array<int, MAXN> cnt{}, useA{}, useB{};\n    int last = 0;\n    long long err = (1LL << 60);\n};\n\nstatic int g_cost[MAXN][MAXN];\n\nstatic inline int sample_weighted(const uint64_t* w, int n, RNG& rng) {\n    uint64_t sum = 0;\n    for (int i = 0; i < n; i++) sum += w[i];\n    if (sum == 0) return rng.nextInt(n);\n    uint64_t r = rng.nextU64() % sum;\n    uint64_t acc = 0;\n    for (int i = 0; i < n; i++) {\n        acc += w[i];\n        if (r < acc) return i;\n    }\n    return n - 1;\n}\n\nstatic inline void shuffle_order(array<int, MAXN>& ord, int N, RNG& rng) {\n    for (int i = N - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(ord[i], ord[j]);\n    }\n}\n\nstatic inline void set_cycle_from_order(const array<int, MAXN>& ord, int N, array<int, MAXN>& a) {\n    for (int i = 0; i < N; i++) a[ord[i]] = ord[(i + 1) % N];\n}\n\nstatic long long simulate(\n    const array<int, MAXN>& a,\n    const array<int, MAXN>& b,\n    int N, int L,\n    const array<int, MAXN>& T,\n    array<int, MAXN>& cnt,\n    array<int, MAXN>& useA,\n    array<int, MAXN>& useB,\n    int& last\n) {\n    for (int i = 0; i < N; i++) cnt[i] = 0;\n\n    int cur = 0;\n    cnt[0] = 1; // week 1\n\n    for (int step = 1; step < L; step++) {\n        int s = cur;\n        if (cnt[s] & 1) cur = a[s];\n        else cur = b[s];\n        cnt[cur]++;\n    }\n    last = cur;\n\n    for (int i = 0; i < N; i++) {\n        int dep = cnt[i] - (i == last ? 1 : 0);\n        if (dep < 0) dep = 0;\n        useA[i] = (dep + 1) >> 1;\n        useB[i] = dep >> 1;\n    }\n\n    long long e = 0;\n    for (int i = 0; i < N; i++) e += absl((long long)cnt[i] - T[i]);\n    return e;\n}\n\n// Hungarian: source i -> destination assignment[i]\nstatic long long hungarian(int n, int cost[MAXN][MAXN], array<int, MAXN>& assignment) {\n    const long long INF = (1LL << 60);\n    static long long u[MAXN + 1], v[MAXN + 1], minv[MAXN + 1];\n    static int p[MAXN + 1], way[MAXN + 1];\n    static unsigned char used[MAXN + 1];\n\n    for (int i = 0; i <= n; i++) {\n        u[i] = v[i] = 0;\n        p[i] = way[i] = 0;\n    }\n\n    for (int i = 1; i <= n; i++) {\n        p[0] = i;\n        for (int j = 0; j <= n; j++) {\n            minv[j] = INF;\n            used[j] = 0;\n        }\n\n        int j0 = 0;\n        do {\n            used[j0] = 1;\n            int i0 = p[j0], j1 = 0;\n            long long delta = INF;\n\n            for (int j = 1; j <= n; j++) if (!used[j]) {\n                long long cur = (long long)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\n            for (int j = 0; j <= n; j++) {\n                if (used[j]) {\n                    u[p[j]] += delta;\n                    v[j] -= delta;\n                } else {\n                    minv[j] -= delta;\n                }\n            }\n            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    for (int j = 1; j <= n; j++) assignment[p[j] - 1] = j - 1;\n    return -v[0];\n}\n\nstatic inline int diff_cost(long long diff, int mode) {\n    diff = diff < 0 ? -diff : diff;\n    if (mode == 0) { // L1\n        return (int)diff;\n    } else if (mode == 1) { // L2\n        long long v = diff * diff;\n        if (v > 1000000000LL) v = 1000000000LL;\n        return (int)v;\n    } else { // hybrid\n        long long v = diff + (diff * diff) / 4;\n        if (v > 1000000000LL) v = 1000000000LL;\n        return (int)v;\n    }\n}\n\n// rem semantics: assign source s(weight w) to d => rem[d] -= w\n// move old->d: rem[old]+=w, rem[d]-=w\nstatic void local_improve_edge(\n    array<int, MAXN>& edge,\n    array<long long, MAXN>& rem,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    int passes\n) {\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool improved = false;\n        shuffle_order(ord, N, rng);\n\n        for (int zi = 0; zi < N; zi++) {\n            int s = ord[zi];\n            long long w = T[s];\n            if (w == 0) continue;\n\n            int old = edge[s];\n            int best = old;\n            long long bestDelta = 0;\n            long long absOld = absl(rem[old]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == old) continue;\n                long long delta =\n                    absl(rem[old] + w) + absl(rem[d] - w) - absOld - absl(rem[d]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = d;\n                }\n            }\n\n            if (best != old) {\n                rem[old] += w;\n                rem[best] -= w;\n                edge[s] = best;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nstatic void optimize_b_greedy_given_a(\n    const array<int, MAXN>& a,\n    int N,\n    const array<int, MAXN>& T,\n    const array<int, MAXN>& srcDesc,\n    RNG& rng,\n    array<int, MAXN>& b,\n    double random_rate,\n    int local_passes\n) {\n    array<long long, MAXN> rem{};\n    for (int j = 0; j < N; j++) rem[j] = 2LL * T[j];\n    for (int s = 0; s < N; s++) rem[a[s]] -= T[s];\n\n    for (int k = 0; k < N; k++) {\n        int s = srcDesc[k];\n        long long w = T[s];\n\n        int best = 0, second = 0;\n        long long vb = absl(rem[0] - w), vs = (1LL << 60);\n\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] - w);\n            if (v < vb) {\n                second = best;\n                vs = vb;\n                best = d;\n                vb = v;\n            } else if (v < vs) {\n                second = d;\n                vs = v;\n            }\n        }\n\n        int dst = best;\n        if (random_rate > 0.0 && second != best && rng.nextDouble() < 0.14 * random_rate) {\n            dst = second;\n        }\n\n        b[s] = dst;\n        rem[dst] -= w;\n    }\n\n    local_improve_edge(b, rem, N, T, rng, local_passes);\n}\n\nstatic void optimize_b_hung_given_a(\n    const array<int, MAXN>& a,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& b,\n    int cost_mode,\n    bool relax,\n    int relax_passes\n) {\n    array<long long, MAXN> inA{}, D{}, rem{};\n    for (int s = 0; s < N; s++) inA[a[s]] += T[s];\n    for (int j = 0; j < N; j++) D[j] = 2LL * T[j] - inA[j];\n\n    for (int s = 0; s < N; s++) {\n        for (int d = 0; d < N; d++) {\n            g_cost[s][d] = diff_cost(D[d] - T[s], cost_mode);\n        }\n    }\n\n    array<int, MAXN> asg{};\n    hungarian(N, g_cost, asg);\n    for (int s = 0; s < N; s++) b[s] = asg[s];\n\n    if (relax) {\n        for (int j = 0; j < N; j++) rem[j] = D[j];\n        for (int s = 0; s < N; s++) rem[b[s]] -= T[s];\n        local_improve_edge(b, rem, N, T, rng, relax_passes);\n    }\n}\n\nstatic void optimize_a_hung_given_b(\n    const array<int, MAXN>& b,\n    int N,\n    const array<int, MAXN>& T,\n    RNG& rng,\n    array<int, MAXN>& a,\n    int cost_mode,\n    bool relax,\n    int relax_passes\n) {\n    array<long long, MAXN> inB{}, D{}, rem{};\n    for (int s = 0; s < N; s++) inB[b[s]] += T[s];\n    for (int j = 0; j < N; j++) D[j] = 2LL * T[j] - inB[j];\n\n    for (int s = 0; s < N; s++) {\n        for (int d = 0; d < N; d++) {\n            g_cost[s][d] = diff_cost(D[d] - T[s], cost_mode);\n        }\n    }\n\n    array<int, MAXN> asg{};\n    hungarian(N, g_cost, asg);\n    for (int s = 0; s < N; s++) a[s] = asg[s];\n\n    if (relax) {\n        for (int j = 0; j < N; j++) rem[j] = 2LL * T[j];\n        for (int s = 0; s < N; s++) rem[a[s]] -= T[s];\n        for (int s = 0; s < N; s++) rem[b[s]] -= T[s];\n        local_improve_edge(a, rem, N, T, rng, relax_passes);\n    }\n}\n\n// usage model: rem = cnt - T\n// move old->d with usage u => rem[old]-=u, rem[d]+=u\nstatic void local_improve_usage_edge(\n    array<int, MAXN>& edge,\n    const array<int, MAXN>& use,\n    array<long long, MAXN>& rem,\n    int N,\n    RNG& rng,\n    int passes\n) {\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool improved = false;\n        shuffle_order(ord, N, rng);\n\n        for (int zi = 0; zi < N; zi++) {\n            int s = ord[zi];\n            int u = use[s];\n            if (u == 0) continue;\n\n            int old = edge[s];\n            int best = old;\n            long long bestDelta = 0;\n            long long absOld = absl(rem[old]);\n\n            for (int d = 0; d < N; d++) {\n                if (d == old) continue;\n                long long delta =\n                    absl(rem[old] - u) + absl(rem[d] + u) - absOld - absl(rem[d]);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    best = d;\n                }\n            }\n\n            if (best != old) {\n                rem[old] -= u;\n                rem[best] += u;\n                edge[s] = best;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nstatic void rebuild_edge_by_usage(\n    const array<int, MAXN>& curEdge,\n    const array<int, MAXN>& use,\n    const array<int, MAXN>& cnt,\n    const array<int, MAXN>& T,\n    int N,\n    RNG& rng,\n    array<int, MAXN>& outEdge,\n    int local_passes,\n    double second_rate\n) {\n    outEdge = curEdge;\n\n    array<long long, MAXN> rem{};\n    for (int j = 0; j < N; j++) rem[j] = (long long)cnt[j] - T[j];\n\n    // remove old contributions\n    for (int s = 0; s < N; s++) rem[outEdge[s]] -= use[s];\n\n    array<int, MAXN> ord{};\n    for (int i = 0; i < N; i++) ord[i] = i;\n    sort(ord.begin(), ord.begin() + N, [&](int x, int y) {\n        if (use[x] != use[y]) return use[x] > use[y];\n        return x < y;\n    });\n\n    for (int zi = 0; zi < N; zi++) {\n        int s = ord[zi];\n        int u = use[s];\n        if (u == 0) continue;\n\n        int best = 0, second = 0;\n        long long vb = absl(rem[0] + u), vs = (1LL << 60);\n\n        for (int d = 1; d < N; d++) {\n            long long v = absl(rem[d] + u);\n            if (v < vb) {\n                second = best;\n                vs = vb;\n                best = d;\n                vb = v;\n            } else if (v < vs) {\n                second = d;\n                vs = v;\n            }\n        }\n\n        int dst = best;\n        if (second != best && second_rate > 0.0 && rng.nextDouble() < second_rate) dst = second;\n        outEdge[s] = dst;\n        rem[dst] += u;\n    }\n\n    local_improve_usage_edge(outEdge, use, rem, N, rng, local_passes);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, L;\n    cin >> N >> L;\n    array<int, MAXN> T{};\n    for (int i = 0; i < N; i++) cin >> T[i];\n    if (N <= 0 || N > MAXN) return 0;\n\n    uint64_t seed = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        seed ^= (uint64_t)(T[i] + 0x9e3779b97f4a7c15ULL + ((uint64_t)i << 16));\n        seed *= 1099511628211ULL;\n    }\n    seed ^= ((uint64_t)N << 32) ^ (uint64_t)L;\n    RNG rng(seed);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    };\n\n    const double T_INIT_END   = 0.43;\n    const double T_SA_END     = 1.72;\n    const double T_DIVER_END  = 1.82;\n    const double T_RESCUE_END = 1.87;\n    const double T_END        = 1.92;\n\n    // Base orders\n    array<int, MAXN> ordNatural{}, ordAsc{}, ordDesc{}, ordMountain{}, ordMountainRev{};\n    for (int i = 0; i < N; i++) ordNatural[i] = i;\n\n    vector<int> idx(N);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        if (T[x] != T[y]) return T[x] < T[y];\n        return x < y;\n    });\n    for (int i = 0; i < N; i++) ordAsc[i] = idx[i];\n    for (int i = 0; i < N; i++) ordDesc[i] = idx[N - 1 - i];\n\n    {\n        int l = 0, r = N - 1, p = 0;\n        while (l <= r) {\n            ordMountain[p++] = ordAsc[l++];\n            if (l <= r) ordMountain[p++] = ordAsc[r--];\n        }\n    }\n    for (int i = 0; i < N; i++) ordMountainRev[i] = ordMountain[N - 1 - i];\n\n    array<int, MAXN> srcDesc = ordDesc;\n\n    vector<array<int, MAXN>> baseOrders;\n    baseOrders.push_back(ordNatural);\n    baseOrders.push_back(ordAsc);\n    baseOrders.push_back(ordDesc);\n    baseOrders.push_back(ordMountain);\n    baseOrders.push_back(ordMountainRev);\n\n    auto differs = [&](const array<int, MAXN>& x, const array<int, MAXN>& y) -> bool {\n        for (int i = 0; i < N; i++) if (x[i] != y[i]) return true;\n        return false;\n    };\n\n    State best;\n    best.err = (1LL << 60);\n    vector<State> pool;\n    pool.reserve(12);\n\n    auto add_pool = [&](const State& s) {\n        pool.push_back(s);\n        sort(pool.begin(), pool.end(), [](const State& A, const State& B) { return A.err < B.err; });\n        if ((int)pool.size() > 10) pool.resize(10);\n    };\n\n    auto register_state = [&](const State& s) {\n        if (s.err < best.err) best = s;\n        if ((int)pool.size() < 10) add_pool(s);\n        else if (s.err <= pool.back().err + 1200) add_pool(s);\n    };\n\n    auto evaluate_candidate = [&](const array<int, MAXN>& a, const array<int, MAXN>& b) -> long long {\n        State s;\n        s.a = a;\n        s.b = b;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        register_state(s);\n        return s.err;\n    };\n\n    array<int, MAXN> candA{}, candB{};\n\n    auto build_by_order = [&](const array<int, MAXN>& ord, int strategy, bool rnd) {\n        set_cycle_from_order(ord, N, candA);\n\n        switch (strategy) {\n            case 0:\n                optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, rnd ? 1.0 : 0.0, 5);\n                break;\n            case 1:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, true, 4);\n                break;\n            case 2:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 1, true, 4);\n                break;\n            case 3:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 2, true, 4);\n                break;\n            case 4:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, false, 0);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 0, false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, true, 3);\n                break;\n            case 5:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 1, false, 0);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 2, false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 2, true, 3);\n                break;\n            case 6:\n                optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, rnd ? 0.9 : 0.0, 4);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 2, false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 2, true, 3);\n                break;\n            default:\n                optimize_b_hung_given_a(candA, N, T, rng, candB, 0, false, 0);\n                optimize_a_hung_given_b(candB, N, T, rng, candA, 1, false, 0);\n                if (rnd && rng.nextDouble() < 0.5) {\n                    optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, 0.6, 4);\n                } else {\n                    optimize_b_hung_given_a(candA, N, T, rng, candB, 1, true, 3);\n                }\n                break;\n        }\n    };\n\n    array<int, MAXN> bestOrder = ordAsc;\n    long long bestOrderErr = (1LL << 60);\n\n    // deterministic init\n    for (const auto& ord : baseOrders) {\n        for (int st = 0; st < 8; st++) {\n            build_by_order(ord, st, false);\n            long long e = evaluate_candidate(candA, candB);\n            if (e < bestOrderErr) {\n                bestOrderErr = e;\n                bestOrder = ord;\n            }\n        }\n    }\n\n    // randomized init\n    while (elapsed() < T_INIT_END) {\n        if (!pool.empty() && rng.nextDouble() < 0.12) {\n            State base = pool[rng.nextInt((int)pool.size())];\n            candA = base.a;\n            candB = base.b;\n\n            int mode = rng.nextInt(5);\n            if (mode == 0) {\n                optimize_b_greedy_given_a(candA, N, T, srcDesc, rng, candB, 0.9, 4);\n            } else if (mode == 1) {\n                optimize_b_hung_given_a(candA, N, T, rng, candB, rng.nextInt(3), true, 3);\n            } else if (mode == 2) {\n                optimize_a_hung_given_b(candB, N, T, rng, candA, rng.nextInt(3), false, 0);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, rng.nextInt(3), true, 3);\n            } else if (mode == 3) {\n                rebuild_edge_by_usage(candB, base.useB, base.cnt, T, N, rng, candB, 3, 0.03);\n            } else {\n                rebuild_edge_by_usage(candA, base.useA, base.cnt, T, N, rng, candA, 2, 0.02);\n                optimize_b_hung_given_a(candA, N, T, rng, candB, rng.nextInt(3), true, 2);\n            }\n            evaluate_candidate(candA, candB);\n            continue;\n        }\n\n        array<int, MAXN> ord{};\n        if (rng.nextDouble() < 0.45) ord = bestOrder;\n        else ord = baseOrders[rng.nextInt((int)baseOrders.size())];\n\n        int swaps = 1 + rng.nextInt(24);\n        for (int s = 0; s < swaps; s++) {\n            int i = rng.nextInt(N), j = rng.nextInt(N);\n            swap(ord[i], ord[j]);\n        }\n\n        if (rng.nextDouble() < 0.25) {\n            int l = rng.nextInt(N), r = rng.nextInt(N);\n            if (l > r) swap(l, r);\n            reverse(ord.begin() + l, ord.begin() + r + 1);\n        }\n        if (rng.nextDouble() < 0.08) shuffle_order(ord, N, rng);\n\n        int st = rng.nextInt(8);\n        build_by_order(ord, st, true);\n        long long e = evaluate_candidate(candA, candB);\n        if (e < bestOrderErr) {\n            bestOrderErr = e;\n            bestOrder = ord;\n        }\n    }\n\n    if (pool.empty()) add_pool(best);\n    State cur = best;\n\n    array<int, MAXN> trialA{}, trialB{}, tmpCnt{}, tmpUseA{}, tmpUseB{};\n    int tmpLast = 0;\n    array<uint64_t, MAXN> w1{}, w2{};\n\n    // SA with mid-run restart\n    double saStart = elapsed();\n    double saSpan = max(1e-9, T_SA_END - saStart);\n    double switchT = saStart + saSpan * 0.58;\n    bool switched = false;\n    long long iter = 0, lastImprove = 0;\n\n    while (elapsed() < T_SA_END) {\n        iter++;\n\n        if (!switched && elapsed() > switchT) {\n            switched = true;\n            State base = best;\n            if ((int)pool.size() >= 2) base = pool[1];\n\n            trialA = base.a;\n            trialB = base.b;\n\n            int swp = 2 + rng.nextInt(5);\n            for (int k = 0; k < swp; k++) {\n                int i = rng.nextInt(N), j = rng.nextInt(N - 1);\n                if (j >= i) j++;\n                swap(trialA[i], trialA[j]);\n            }\n            optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 2);\n\n            State alt;\n            alt.a = trialA;\n            alt.b = trialB;\n            alt.err = simulate(alt.a, alt.b, N, L, T, alt.cnt, alt.useA, alt.useB, alt.last);\n\n            cur = alt;\n            register_state(cur);\n        }\n\n        if ((iter & 255LL) == 0 && !pool.empty()) {\n            if (cur.err > best.err + 1800 ||\n                ((iter - lastImprove > 900) && rng.nextDouble() < 0.40)) {\n                cur = pool[rng.nextInt((int)pool.size())];\n            }\n        }\n\n        double prog = (elapsed() - saStart) / saSpan;\n        if (prog < 0.0) prog = 0.0;\n        if (prog > 1.0) prog = 1.0;\n        double temp = 1300.0 * (1.0 - prog) + 2.2;\n\n        trialA = cur.a;\n        trialB = cur.b;\n        bool changed = false;\n\n        double rr = rng.nextDouble();\n\n        if (rr < 0.28) {\n            // guided single b move\n            for (int s = 0; s < N; s++) {\n                int dst = cur.b[s];\n                int over = cur.cnt[dst] - T[dst];\n                if (over < 0) over = 0;\n                w1[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(over + 1);\n            }\n\n            int s = sample_weighted(w1.data(), N, rng);\n            int old = cur.b[s];\n            int u = cur.useB[s];\n            if (u <= 0 && rng.nextDouble() < 0.90) continue;\n\n            int bestDst = old;\n            long long bestPred = (1LL << 60);\n            long long xOld = (long long)cur.cnt[old] - T[old];\n            long long absOld = absl(xOld);\n\n            for (int d = 0; d < N; d++) if (d != old) {\n                long long x = (long long)cur.cnt[d] - T[d];\n                long long pred = absl(xOld - u) + absl(x + u) - absOld - absl(x);\n                if (pred < bestPred) {\n                    bestPred = pred;\n                    bestDst = d;\n                }\n            }\n\n            if (bestDst == old) continue;\n            if (bestPred > 0 && rng.nextDouble() < (0.68 + 0.22 * prog)) continue;\n            if (bestPred == 0 && rng.nextDouble() < 0.45) continue;\n\n            if (rng.nextDouble() < 0.10) {\n                for (int d = 0; d < N; d++) {\n                    int under = T[d] - cur.cnt[d];\n                    if (under < 0) under = 0;\n                    w2[d] = (uint64_t)(under + 1);\n                }\n                int rndDst = sample_weighted(w2.data(), N, rng);\n                if (rndDst != old) bestDst = rndDst;\n            }\n\n            trialB[s] = bestDst;\n            changed = true;\n\n        } else if (rr < 0.42) {\n            // b swap\n            for (int s = 0; s < N; s++) {\n                int d = cur.b[s];\n                int over = cur.cnt[d] - T[d];\n                if (over < 0) over = 0;\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w1[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(over + 1);\n                w2[s] = (uint64_t)(cur.useB[s] + 1) * (uint64_t)(under + 1);\n            }\n\n            int s1 = sample_weighted(w1.data(), N, rng);\n            int s2 = sample_weighted(w2.data(), N, rng);\n            if (s1 == s2) {\n                s2 = rng.nextInt(N - 1);\n                if (s2 >= s1) s2++;\n            }\n\n            int d1 = cur.b[s1], d2 = cur.b[s2];\n            if (d1 == d2) continue;\n\n            int u1 = cur.useB[s1], u2 = cur.useB[s2];\n            long long x1 = (long long)cur.cnt[d1] - T[d1];\n            long long x2 = (long long)cur.cnt[d2] - T[d2];\n            long long pred = absl(x1 - u1 + u2) + absl(x2 - u2 + u1) - absl(x1) - absl(x2);\n            if (pred > 0 && rng.nextDouble() < (0.72 + 0.18 * prog)) continue;\n\n            swap(trialB[s1], trialB[s2]);\n            changed = true;\n\n        } else if (rr < 0.53) {\n            // guided single a move\n            for (int s = 0; s < N; s++) {\n                int dst = cur.a[s];\n                int over = cur.cnt[dst] - T[dst];\n                if (over < 0) over = 0;\n                w1[s] = (uint64_t)(cur.useA[s] + 1) * (uint64_t)(over + 1);\n            }\n\n            int s = sample_weighted(w1.data(), N, rng);\n            int old = cur.a[s];\n            int u = cur.useA[s];\n            if (u <= 0 && rng.nextDouble() < 0.90) continue;\n\n            int bestDst = old;\n            long long bestPred = (1LL << 60);\n            long long xOld = (long long)cur.cnt[old] - T[old];\n            long long absOld = absl(xOld);\n\n            for (int d = 0; d < N; d++) if (d != old) {\n                long long x = (long long)cur.cnt[d] - T[d];\n                long long pred = absl(xOld - u) + absl(x + u) - absOld - absl(x);\n                if (pred < bestPred) {\n                    bestPred = pred;\n                    bestDst = d;\n                }\n            }\n\n            if (bestDst == old) continue;\n            if (bestPred > 0 && rng.nextDouble() < (0.74 + 0.18 * prog)) continue;\n            if (bestPred == 0 && rng.nextDouble() < 0.52) continue;\n\n            trialA[s] = bestDst;\n            changed = true;\n\n        } else if (rr < 0.63) {\n            // a swap\n            for (int s = 0; s < N; s++) {\n                int d = cur.a[s];\n                int over = cur.cnt[d] - T[d];\n                if (over < 0) over = 0;\n                int under = T[d] - cur.cnt[d];\n                if (under < 0) under = 0;\n                w1[s] = (uint64_t)(cur.useA[s] + 1) * (uint64_t)(over + 1);\n                w2[s] = (uint64_t)(cur.useA[s] + 1) * (uint64_t)(under + 1);\n            }\n\n            int s1 = sample_weighted(w1.data(), N, rng);\n            int s2 = sample_weighted(w2.data(), N, rng);\n            if (s1 == s2) {\n                s2 = rng.nextInt(N - 1);\n                if (s2 >= s1) s2++;\n            }\n\n            int d1 = cur.a[s1], d2 = cur.a[s2];\n            if (d1 == d2) continue;\n\n            int u1 = cur.useA[s1], u2 = cur.useA[s2];\n            long long x1 = (long long)cur.cnt[d1] - T[d1];\n            long long x2 = (long long)cur.cnt[d2] - T[d2];\n            long long pred = absl(x1 - u1 + u2) + absl(x2 - u2 + u1) - absl(x1) - absl(x2);\n            if (pred > 0 && rng.nextDouble() < (0.76 + 0.16 * prog)) continue;\n\n            swap(trialA[s1], trialA[s2]);\n            changed = true;\n\n        } else if (rr < 0.74) {\n            // rebuild b\n            if (rng.nextDouble() < 0.45) {\n                optimize_b_greedy_given_a(trialA, N, T, srcDesc, rng, trialB, 0.9, 4);\n            } else {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 3);\n            }\n            changed = differs(trialB, cur.b);\n\n        } else if (rr < 0.84) {\n            // rebuild a + maybe b\n            optimize_a_hung_given_b(trialB, N, T, rng, trialA, rng.nextInt(3), false, 0);\n\n            double r2 = rng.nextDouble();\n            if (r2 < 0.45) {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 3);\n            } else if (r2 < 0.75) {\n                optimize_b_greedy_given_a(trialA, N, T, srcDesc, rng, trialB, 0.7, 4);\n            }\n\n            changed = differs(trialA, cur.a) || differs(trialB, cur.b);\n\n        } else if (rr < 0.92) {\n            // usage rebuild b\n            rebuild_edge_by_usage(cur.b, cur.useB, cur.cnt, T, N, rng, trialB, 3, 0.03);\n            if (rng.nextDouble() < 0.20) {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 2);\n            }\n            changed = differs(trialB, cur.b);\n\n        } else {\n            // usage rebuild both\n            rebuild_edge_by_usage(cur.a, cur.useA, cur.cnt, T, N, rng, trialA, 2, 0.02);\n            if (rng.nextDouble() < 0.65) {\n                rebuild_edge_by_usage(cur.b, cur.useB, cur.cnt, T, N, rng, trialB, 3, 0.03);\n            } else {\n                optimize_b_hung_given_a(trialA, N, T, rng, trialB, rng.nextInt(3), true, 3);\n            }\n            if (rng.nextDouble() < 0.18) {\n                optimize_a_hung_given_b(trialB, N, T, rng, trialA, rng.nextInt(3), false, 0);\n            }\n            changed = differs(trialA, cur.a) || differs(trialB, cur.b);\n        }\n\n        if (!changed) continue;\n\n        long long newErr = simulate(trialA, trialB, N, L, T, tmpCnt, tmpUseA, tmpUseB, tmpLast);\n\n        bool accept = false;\n        if (newErr <= cur.err) accept = true;\n        else {\n            double prob = exp((double)(cur.err - newErr) / temp);\n            if (rng.nextDouble() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.a = trialA;\n            cur.b = trialB;\n            cur.err = newErr;\n            cur.cnt = tmpCnt;\n            cur.useA = tmpUseA;\n            cur.useB = tmpUseB;\n            cur.last = tmpLast;\n\n            if (cur.err < best.err) {\n                best = cur;\n                add_pool(best);\n                lastImprove = iter;\n            } else if (cur.err <= best.err + 900 && rng.nextDouble() < 0.12) {\n                add_pool(cur);\n            }\n        }\n    }\n\n    auto try_update = [&](const array<int, MAXN>& aa, const array<int, MAXN>& bb) -> bool {\n        long long oldBest = best.err;\n        State s;\n        s.a = aa;\n        s.b = bb;\n        s.err = simulate(s.a, s.b, N, L, T, s.cnt, s.useA, s.useB, s.last);\n        register_state(s);\n        return best.err < oldBest;\n    };\n\n    array<int, MAXN> trialA2{}, trialB2{};\n\n    // deterministic rebuild polish\n    if (elapsed() < T_END - 0.09) {\n        trialA2 = best.a;\n        optimize_b_greedy_given_a(trialA2, N, T, srcDesc, rng, trialB2, 0.0, 5);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.09) {\n        trialA2 = best.a;\n        optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, 0, true, 4);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.09) {\n        trialA2 = best.a;\n        optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, 1, true, 4);\n        try_update(trialA2, trialB2);\n    }\n    if (elapsed() < T_END - 0.09) {\n        trialA2 = best.a;\n        rebuild_edge_by_usage(best.b, best.useB, best.cnt, T, N, rng, trialB2, 4, 0.0);\n        try_update(trialA2, trialB2);\n    }\n\n    // diversification\n    while (elapsed() < T_DIVER_END) {\n        State base = best;\n        if (!pool.empty() && rng.nextDouble() < 0.70) base = pool[rng.nextInt((int)pool.size())];\n\n        trialA2 = base.a;\n        trialB2 = base.b;\n\n        int sw = 1 + rng.nextInt(4);\n        for (int k = 0; k < sw; k++) {\n            int i = rng.nextInt(N), j = rng.nextInt(N - 1);\n            if (j >= i) j++;\n            swap(trialA2[i], trialA2[j]);\n        }\n\n        double r = rng.nextDouble();\n        if (r < 0.35) {\n            optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, rng.nextInt(3), true, 3);\n        } else if (r < 0.70) {\n            rebuild_edge_by_usage(base.b, base.useB, base.cnt, T, N, rng, trialB2, 3, 0.04);\n        } else {\n            rebuild_edge_by_usage(base.a, base.useA, base.cnt, T, N, rng, trialA2, 2, 0.03);\n            optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, rng.nextInt(3), true, 2);\n        }\n\n        State cand;\n        cand.a = trialA2;\n        cand.b = trialB2;\n        cand.err = simulate(cand.a, cand.b, N, L, T, cand.cnt, cand.useA, cand.useB, cand.last);\n        register_state(cand);\n    }\n\n    auto polish_sourcewise_single_once = [&](State& st, int evalLimit, double until) -> bool {\n        struct Cand {\n            long long pred;\n            int type; // 0:a, 1:b\n            int s, d;\n        };\n\n        vector<Cand> cands;\n        cands.reserve(500);\n\n        array<long long, MAXN> res{};\n        for (int i = 0; i < N; i++) res[i] = (long long)st.cnt[i] - T[i];\n\n        for (int s = 0; s < N; s++) {\n            // b\n            {\n                int u = st.useB[s];\n                if (u > 0) {\n                    int old = st.b[s];\n                    long long ro = res[old], aro = absl(ro);\n                    long long p1 = (1LL << 60), p2 = (1LL << 60);\n                    int d1 = old, d2 = old;\n\n                    for (int d = 0; d < N; d++) if (d != old) {\n                        long long p = absl(ro - u) + absl(res[d] + u) - aro - absl(res[d]);\n                        if (p < p1) { p2 = p1; d2 = d1; p1 = p; d1 = d; }\n                        else if (p < p2) { p2 = p; d2 = d; }\n                    }\n\n                    if (d1 != old) cands.push_back({p1, 1, s, d1});\n                    if (d2 != old && p2 <= 0) cands.push_back({p2, 1, s, d2});\n                }\n            }\n\n            // a\n            {\n                int u = st.useA[s];\n                if (u > 0) {\n                    int old = st.a[s];\n                    long long ro = res[old], aro = absl(ro);\n                    long long p1 = (1LL << 60), p2 = (1LL << 60);\n                    int d1 = old, d2 = old;\n\n                    for (int d = 0; d < N; d++) if (d != old) {\n                        long long p = absl(ro - u) + absl(res[d] + u) - aro - absl(res[d]);\n                        if (p < p1) { p2 = p1; d2 = d1; p1 = p; d1 = d; }\n                        else if (p < p2) { p2 = p; d2 = d; }\n                    }\n\n                    if (d1 != old) cands.push_back({p1, 0, s, d1});\n                    if (d2 != old && p2 <= 0) cands.push_back({p2, 0, s, d2});\n                }\n            }\n        }\n\n        if (cands.empty()) return false;\n        sort(cands.begin(), cands.end(), [](const Cand& A, const Cand& B) { return A.pred < B.pred; });\n\n        State bestLocal = st;\n        bool improved = false;\n        int evals = 0;\n\n        for (const auto& cd : cands) {\n            if (evals >= evalLimit || elapsed() >= until) break;\n\n            State tmp;\n            tmp.a = st.a;\n            tmp.b = st.b;\n            if (cd.type == 0) tmp.a[cd.s] = cd.d;\n            else tmp.b[cd.s] = cd.d;\n\n            tmp.err = simulate(tmp.a, tmp.b, N, L, T, tmp.cnt, tmp.useA, tmp.useB, tmp.last);\n            evals++;\n\n            if (tmp.err < bestLocal.err) {\n                bestLocal = tmp;\n                improved = true;\n            }\n        }\n\n        if (improved) st = bestLocal;\n        return improved;\n    };\n\n    auto polish_top_swap_once = [&](State& st, bool onA, int topKeep, int evalLimit, double until) -> bool {\n        struct Cand {\n            long long pred;\n            int i, j;\n        };\n\n        vector<Cand> cands;\n        cands.reserve(6000);\n\n        array<long long, MAXN> res{};\n        for (int k = 0; k < N; k++) res[k] = (long long)st.cnt[k] - T[k];\n\n        const auto& edge = onA ? st.a : st.b;\n        const auto& use  = onA ? st.useA : st.useB;\n\n        for (int i = 0; i < N; i++) {\n            int d1 = edge[i], u1 = use[i];\n            for (int j = i + 1; j < N; j++) {\n                int d2 = edge[j], u2 = use[j];\n                if (d1 == d2 || (u1 == 0 && u2 == 0)) continue;\n                long long pred =\n                    absl(res[d1] - u1 + u2) + absl(res[d2] - u2 + u1)\n                    - absl(res[d1]) - absl(res[d2]);\n                cands.push_back({pred, i, j});\n            }\n        }\n\n        if (cands.empty()) return false;\n\n        auto cmp = [](const Cand& A, const Cand& B) { return A.pred < B.pred; };\n        if ((int)cands.size() > topKeep) {\n            nth_element(cands.begin(), cands.begin() + topKeep, cands.end(), cmp);\n            cands.resize(topKeep);\n        }\n        sort(cands.begin(), cands.end(), cmp);\n\n        State bestLocal = st;\n        bool improved = false;\n        int evals = 0;\n\n        for (const auto& cd : cands) {\n            if (evals >= evalLimit || elapsed() >= until) break;\n\n            State tmp = st;\n            if (onA) swap(tmp.a[cd.i], tmp.a[cd.j]);\n            else swap(tmp.b[cd.i], tmp.b[cd.j]);\n\n            tmp.err = simulate(tmp.a, tmp.b, N, L, T, tmp.cnt, tmp.useA, tmp.useB, tmp.last);\n            evals++;\n\n            if (tmp.err < bestLocal.err) {\n                bestLocal = tmp;\n                improved = true;\n            }\n        }\n\n        if (improved) st = bestLocal;\n        return improved;\n    };\n\n    auto exact_heavy_one_edge = [&](State& st, bool onA, int maxSources, int candPerSource, int evalLimit, double until) -> bool {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n\n        const auto& use = onA ? st.useA : st.useB;\n        sort(ord.begin(), ord.end(), [&](int x, int y) {\n            if (use[x] != use[y]) return use[x] > use[y];\n            return x < y;\n        });\n\n        array<long long, MAXN> res{};\n        for (int i = 0; i < N; i++) res[i] = (long long)st.cnt[i] - T[i];\n\n        State bestLocal = st;\n        bool improved = false;\n        int evals = 0;\n\n        for (int oi = 0; oi < N && oi < maxSources; oi++) {\n            if (evals >= evalLimit || elapsed() >= until) break;\n            int s = ord[oi];\n            int u = use[s];\n            if (u == 0) break;\n\n            int old = onA ? st.a[s] : st.b[s];\n            long long ro = res[old], aro = absl(ro);\n\n            array<pair<long long, int>, MAXN> cand{};\n            int cc = 0;\n\n            for (int d = 0; d < N; d++) if (d != old) {\n                long long p = absl(ro - u) + absl(res[d] + u) - aro - absl(res[d]);\n\n                if (cc < candPerSource) {\n                    cand[cc++] = {p, d};\n                    if (cc == candPerSource) sort(cand.begin(), cand.begin() + cc);\n                } else if (p < cand[cc - 1].first) {\n                    cand[cc - 1] = {p, d};\n                    int k = cc - 1;\n                    while (k > 0 && cand[k] < cand[k - 1]) {\n                        swap(cand[k], cand[k - 1]);\n                        k--;\n                    }\n                }\n            }\n\n            for (int k = 0; k < cc; k++) {\n                if (evals >= evalLimit || elapsed() >= until) break;\n                int d = cand[k].second;\n\n                State tmp;\n                tmp.a = st.a;\n                tmp.b = st.b;\n                if (onA) tmp.a[s] = d;\n                else tmp.b[s] = d;\n\n                tmp.err = simulate(tmp.a, tmp.b, N, L, T, tmp.cnt, tmp.useA, tmp.useB, tmp.last);\n                evals++;\n\n                if (tmp.err < bestLocal.err) {\n                    bestLocal = tmp;\n                    improved = true;\n                }\n            }\n        }\n\n        if (improved) st = bestLocal;\n        return improved;\n    };\n\n    // Conditional tail rescue\n    if (best.err > 10800 && elapsed() < T_RESCUE_END - 0.001) {\n        while (elapsed() < T_RESCUE_END - 0.001) {\n            if (rng.nextDouble() < 0.58) {\n                array<int, MAXN> ord{};\n                if (rng.nextDouble() < 0.55) ord = bestOrder;\n                else ord = baseOrders[rng.nextInt((int)baseOrders.size())];\n\n                int swaps = 8 + rng.nextInt(20);\n                for (int s = 0; s < swaps; s++) {\n                    int i = rng.nextInt(N), j = rng.nextInt(N);\n                    swap(ord[i], ord[j]);\n                }\n                if (rng.nextDouble() < 0.35) {\n                    int l = rng.nextInt(N), r = rng.nextInt(N);\n                    if (l > r) swap(l, r);\n                    reverse(ord.begin() + l, ord.begin() + r + 1);\n                }\n\n                int st = rng.nextInt(8);\n                build_by_order(ord, st, true);\n                evaluate_candidate(candA, candB);\n            } else {\n                State base = best;\n                if (!pool.empty()) base = pool[rng.nextInt((int)pool.size())];\n\n                trialA2 = base.a;\n                trialB2 = base.b;\n\n                double r = rng.nextDouble();\n                if (r < 0.34) {\n                    optimize_a_hung_given_b(base.b, N, T, rng, trialA2, rng.nextInt(3), false, 0);\n                    optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, rng.nextInt(3), true, 3);\n                } else if (r < 0.67) {\n                    rebuild_edge_by_usage(base.b, base.useB, base.cnt, T, N, rng, trialB2, 3, 0.04);\n                    if (rng.nextDouble() < 0.35) {\n                        optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, rng.nextInt(3), true, 2);\n                    }\n                } else {\n                    rebuild_edge_by_usage(base.a, base.useA, base.cnt, T, N, rng, trialA2, 2, 0.03);\n                    rebuild_edge_by_usage(base.b, base.useB, base.cnt, T, N, rng, trialB2, 3, 0.04);\n                }\n\n                State c;\n                c.a = trialA2;\n                c.b = trialB2;\n                c.err = simulate(c.a, c.b, N, L, T, c.cnt, c.useA, c.useB, c.last);\n\n                if (c.err <= best.err + 1500 && elapsed() < T_RESCUE_END - 0.0004) {\n                    polish_sourcewise_single_once(c, 6, T_RESCUE_END - 0.0001);\n                }\n                register_state(c);\n            }\n        }\n    }\n\n    // Final exact polish on best\n    if (elapsed() < T_END - 0.018) {\n        int stagn = 0;\n        int evalSingle = (best.err > 11000 ? 22 : 16);\n\n        while (elapsed() < T_END - 0.018 && stagn < 5) {\n            bool imp = false;\n            imp |= polish_sourcewise_single_once(best, evalSingle, T_END - 0.0035);\n            if (elapsed() < T_END - 0.015) imp |= polish_top_swap_once(best, false, 120, 8, T_END - 0.0035);\n            if (elapsed() < T_END - 0.013) imp |= polish_top_swap_once(best, true, 90, 6, T_END - 0.0035);\n            if (elapsed() < T_END - 0.011) imp |= exact_heavy_one_edge(best, false, 20, 2, 12, T_END - 0.0035);\n            if (elapsed() < T_END - 0.010) imp |= exact_heavy_one_edge(best, true, 16, 2, 8, T_END - 0.0035);\n\n            if (imp) {\n                register_state(best);\n                stagn = 0;\n            } else {\n                stagn++;\n            }\n        }\n    }\n\n    // Elite light polish\n    if (elapsed() < T_END - 0.008 && !pool.empty()) {\n        vector<State> elites = pool;\n        sort(elites.begin(), elites.end(), [](const State& A, const State& B) { return A.err < B.err; });\n        int K = min(3, (int)elites.size());\n\n        for (int ei = 0; ei < K && elapsed() < T_END - 0.008; ei++) {\n            State cand = elites[ei];\n            int rounds = 0;\n\n            while (elapsed() < T_END - 0.006 && rounds < 2) {\n                bool imp = false;\n                imp |= polish_sourcewise_single_once(cand, 8, T_END - 0.0035);\n                if (elapsed() < T_END - 0.0055) imp |= polish_top_swap_once(cand, false, 70, 4, T_END - 0.0035);\n                if (elapsed() < T_END - 0.0050) imp |= exact_heavy_one_edge(cand, false, 10, 2, 6, T_END - 0.0035);\n                if (!imp) break;\n                rounds++;\n            }\n\n            register_state(cand);\n        }\n    }\n\n    // last tiny perturbations\n    int trials = 0;\n    while (elapsed() < T_END - 0.0025 && trials < 14) {\n        trialA2 = best.a;\n        int i = rng.nextInt(N);\n        int j = rng.nextInt(N - 1);\n        if (j >= i) j++;\n        swap(trialA2[i], trialA2[j]);\n\n        if (rng.nextDouble() < 0.55) {\n            optimize_b_hung_given_a(trialA2, N, T, rng, trialB2, rng.nextInt(3), true, 3);\n        } else {\n            optimize_b_greedy_given_a(trialA2, N, T, srcDesc, rng, trialB2, 0.4, 4);\n        }\n\n        try_update(trialA2, trialB2);\n        trials++;\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\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        iota(p.begin(), p.end(), 0);\n        sz.assign(n, 1);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool unite(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int MAXN = 800;\n    static constexpr int EDGE_BASE = 1024;\n\n    int N, M, Q, L, W;\n    vector<int> G;\n\n    vector<int> lx, rx, ly, ry;\n    vector<int> wx, wy;              // rectangle widths\n    vector<int> cx2, cy2, cx, cy;    // center*2 and center\n    vector<uint32_t> zkey;\n\n    vector<int> d_center; // center-based distance (scaled coords)\n    vector<int> d_base;   // uncertainty-aware distance\n    vector<int> d_group;  // d_base + query-learned bonuses\n\n    vector<uint16_t> obsCnt;             // observed edge frequency\n    vector<pair<int,int>> touchedObs;    // unique (a<b) observed edges\n\n    mt19937 rng;\n\n    inline int ID(int a, int b) const { return a * N + b; }\n    inline int DBase(int a, int b) const { return d_base[ID(a, b)]; }\n    inline int DGroup(int a, int b) const { return d_group[ID(a, b)]; }\n\n    static uint32_t part1by1(uint32_t x) {\n        x &= 0x0000ffffu;\n        x = (x | (x << 8)) & 0x00FF00FFu;\n        x = (x | (x << 4)) & 0x0F0F0F0Fu;\n        x = (x | (x << 2)) & 0x33333333u;\n        x = (x | (x << 1)) & 0x55555555u;\n        return x;\n    }\n    static uint32_t morton(uint32_t x, uint32_t y) {\n        return part1by1(x) | (part1by1(y) << 1);\n    }\n\n    void input() {\n        cin >> N >> M >> Q >> L >> W;\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N); rx.resize(N); ly.resize(N); ry.resize(N);\n        wx.resize(N); wy.resize(N);\n        cx2.resize(N); cy2.resize(N);\n        cx.resize(N); cy.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n            wx[i] = rx[i] - lx[i];\n            wy[i] = ry[i] - ly[i];\n            cx2[i] = lx[i] + rx[i];\n            cy2[i] = ly[i] + ry[i];\n            cx[i] = cx2[i] / 2;\n            cy[i] = cy2[i] / 2;\n        }\n    }\n\n    void init_rng() {\n        uint64_t seed = 0x9e3779b97f4a7c15ull;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ull + (seed << 6) + (seed >> 2);\n        };\n\n        mix(((uint64_t)N << 32) ^ (uint64_t)M);\n        mix(((uint64_t)Q << 32) ^ (uint64_t)L);\n        mix((uint64_t)W);\n        for (int i = 0; i < N; i++) {\n            mix(((uint64_t)(cx2[i] + 10007) << 32) ^ (uint64_t)(cy2[i] + 10009));\n            mix((uint64_t)(wx[i] + 1) * 1000003ull + (uint64_t)(wy[i] + 7));\n        }\n\n        rng.seed((uint32_t)(seed ^ (seed >> 32)));\n    }\n\n    void preprocess() {\n        zkey.resize(N);\n        for (int i = 0; i < N; i++) {\n            zkey[i] = morton((uint32_t)cx[i], (uint32_t)cy[i]);\n        }\n\n        d_center.assign(N * N, 0);\n        d_base.assign(N * N, 0);\n        d_group.assign(N * N, 0);\n\n        for (int i = 0; i < N; i++) {\n            d_center[ID(i, i)] = 0;\n            d_base[ID(i, i)] = 0;\n            for (int j = i + 1; j < N; j++) {\n                long long dx = (long long)cx2[i] - cx2[j];\n                long long dy = (long long)cy2[i] - cy2[j];\n                long long sq = dx * dx + dy * dy;\n                int dc = (int)std::sqrt((double)sq);\n                d_center[ID(i, j)] = d_center[ID(j, i)] = dc;\n\n                // uncertainty-aware proxy:\n                // E[(error_x)^2 + (error_y)^2] approx (wx_i^2 + wx_j^2 + wy_i^2 + wy_j^2)/3\n                long double add = ((long double)wx[i] * wx[i] + (long double)wx[j] * wx[j]\n                                 + (long double)wy[i] * wy[i] + (long double)wy[j] * wy[j]) / 3.0L;\n                long double bq = (long double)dc * dc + add;\n                int db = (int)std::sqrt((double)bq);\n\n                d_base[ID(i, j)] = d_base[ID(j, i)] = db;\n            }\n        }\n\n        d_group = d_base;\n        obsCnt.assign(N * N, 0);\n        touchedObs.clear();\n    }\n\n    int query_need(int g) const {\n        if (g <= 2) return 0;\n        return (g - 2) / (L - 1) + 1; // ceil((g-1)/(L-1))\n    }\n\n    vector<pair<int,int>> do_query(const vector<int>& subset) {\n        cout << \"? \" << subset.size();\n        for (int c : subset) cout << \" \" << c;\n        cout << \"\\n\";\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        ret.reserve((int)subset.size() - 1);\n        for (int i = 0; i < (int)subset.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.emplace_back(a, b);\n        }\n        return ret;\n    }\n\n    void record_edges(const vector<pair<int,int>>& edges) {\n        for (auto [a, b] : edges) {\n            if (a > b) swap(a, b);\n            int p = ID(a, b), q = ID(b, a);\n            if (obsCnt[p] == 0) touchedObs.emplace_back(a, b);\n            if (obsCnt[p] < 65535) obsCnt[p]++;\n            if (obsCnt[q] < 65535) obsCnt[q]++;\n        }\n    }\n\n    template<class F>\n    vector<int> make_city_order(F comp) const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), comp);\n        return ord;\n    }\n\n    vector<int> city_order_projection(double ang) const {\n        double ax = cos(ang), ay = sin(ang);\n        vector<double> key(N);\n        for (int i = 0; i < N; i++) key[i] = ax * cx2[i] + ay * cy2[i];\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (fabs(key[a] - key[b]) > 1e-12) return key[a] < key[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        return ord;\n    }\n\n    vector<vector<int>> build_knn(const vector<int>& mat, int K) const {\n        K = min(K, N - 1);\n        vector<vector<int>> near(N);\n\n        auto cmp = [](const pair<int,int>& p1, const pair<int,int>& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        };\n\n        for (int i = 0; i < N; i++) {\n            vector<pair<int,int>> arr;\n            arr.reserve(N - 1);\n            int base = i * N;\n            for (int j = 0; j < N; j++) {\n                if (i == j) continue;\n                arr.emplace_back(mat[base + j], j);\n            }\n\n            if ((int)arr.size() > K) {\n                nth_element(arr.begin(), arr.begin() + K, arr.end(), cmp);\n                arr.resize(K);\n            }\n            sort(arr.begin(), arr.end(), cmp);\n\n            near[i].reserve((int)arr.size());\n            for (auto& p : arr) near[i].push_back(p.second);\n        }\n        return near;\n    }\n\n    void perform_exploration(int q_explore, int& q_used) {\n        if (q_explore <= 0) return;\n\n        int Kexp = min(N - 1, max(24, L * 4));\n        auto near = build_knn(d_base, Kexp);\n\n        vector<int> ordZ(N);\n        iota(ordZ.begin(), ordZ.end(), 0);\n        sort(ordZ.begin(), ordZ.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<double> w(N);\n        for (int i = 0; i < N; i++) w[i] = (double)(wx[i] + wy[i] + 20);\n        discrete_distribution<int> anchorDist(w.begin(), w.end());\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        vector<int> mark(N, 0);\n        int stamp = 1;\n\n        for (int t = 0; t < q_explore; t++) {\n            vector<int> subset;\n            subset.reserve(L);\n            ++stamp;\n\n            auto addNode = [&](int v) -> bool {\n                if (v < 0 || v >= N) return false;\n                if (mark[v] == stamp) return false;\n                mark[v] = stamp;\n                subset.push_back(v);\n                return true;\n            };\n\n            int mode = uniform_int_distribution<int>(0, 99)(rng);\n\n            if (mode < 65) {\n                int a = anchorDist(rng);\n                addNode(a);\n                auto& ne = near[a];\n\n                int fixed = min((int)ne.size(), max(1, (L - 1) / 2));\n                for (int i = 0; i < fixed && (int)subset.size() < L; i++) addNode(ne[i]);\n\n                int R = min((int)ne.size(), max(10, L * 3));\n                if (R > 0) {\n                    for (int tries = 0; tries < R * 3 && (int)subset.size() < L; tries++) {\n                        int idx = uniform_int_distribution<int>(0, R - 1)(rng);\n                        addNode(ne[idx]);\n                    }\n                }\n\n                for (int tries = 0; tries < 20 && (int)subset.size() < L; tries++) addNode(uid(rng));\n            } else if (mode < 90) {\n                int a = anchorDist(rng);\n                addNode(a);\n\n                int b = uid(rng);\n                auto& na = near[a];\n                if (!na.empty()) {\n                    int R = min((int)na.size(), 10);\n                    b = na[uniform_int_distribution<int>(0, R - 1)(rng)];\n                }\n                addNode(b);\n\n                vector<int> bases = {a, b};\n                int ptr0 = 0, ptr1 = 0;\n\n                for (int step = 0; step < 200 && (int)subset.size() < L; step++) {\n                    int bi = step & 1;\n                    auto& ne = near[bases[bi]];\n                    int& ptr = (bi == 0 ? ptr0 : ptr1);\n\n                    while (ptr < (int)ne.size() && mark[ne[ptr]] == stamp) ptr++;\n                    if (ptr < (int)ne.size()) {\n                        addNode(ne[ptr]);\n                        ptr++;\n                    } else {\n                        addNode(uid(rng));\n                    }\n                }\n            } else {\n                int len = min(L, N);\n                int s = 0;\n                if (N > len) s = uniform_int_distribution<int>(0, N - len)(rng);\n                for (int i = 0; i < len; i++) addNode(ordZ[s + i]);\n                for (int tries = 0; tries < 20 && (int)subset.size() < L; tries++) addNode(uid(rng));\n            }\n\n            while ((int)subset.size() < 2) addNode(uid(rng));\n            if ((int)subset.size() > L) subset.resize(L);\n\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n        }\n    }\n\n    void rebuild_group_matrix_from_obs() {\n        d_group = d_base;\n        int beta = max(30, W / 14); // roughly 35..178\n\n        for (auto [a, b] : touchedObs) {\n            int c = (int)obsCnt[ID(a, b)];\n            if (c <= 0) continue;\n            int bonus = beta * c;\n            if (c >= 2) bonus += beta / 2;\n\n            int v = d_base[ID(a, b)] - bonus;\n            if (v < 1) v = 1;\n            d_group[ID(a, b)] = d_group[ID(b, a)] = v;\n        }\n    }\n\n    long long prim_cost(const vector<int>& nodes, const vector<int>& mat) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return 0;\n\n        const int INF = 1e9;\n        int mn[MAXN + 5];\n        unsigned char used[MAXN + 5];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        long long cost = 0;\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            cost += mn[v];\n\n            int idv = nodes[v];\n            int base = idv * N;\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = mat[base + nodes[u]];\n                if (w < mn[u]) mn[u] = w;\n            }\n        }\n        return cost;\n    }\n\n    vector<pair<int,int>> prim_tree(const vector<int>& nodes, const vector<int>& mat) const {\n        int n = (int)nodes.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            edges.push_back(p);\n            return edges;\n        }\n\n        const int INF = 1e9;\n        int mn[MAXN + 5], par[MAXN + 5];\n        unsigned char used[MAXN + 5];\n\n        for (int i = 0; i < n; i++) {\n            mn[i] = INF;\n            par[i] = -1;\n            used[i] = 0;\n        }\n        mn[0] = 0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int idv = nodes[v];\n            int base = idv * N;\n\n            for (int u = 0; u < n; u++) {\n                if (used[u]) continue;\n                int w = mat[base + nodes[u]];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        edges.reserve(n - 1);\n        for (int i = 1; i < n; i++) {\n            int a = nodes[i], b = nodes[par[i]];\n            if (a > b) swap(a, b);\n            edges.emplace_back(a, b);\n        }\n        return edges;\n    }\n\n    long long edge_proxy_cost(const vector<pair<int,int>>& edges, const vector<int>& mat) const {\n        long long s = 0;\n        for (auto [a, b] : edges) s += mat[ID(a, b)];\n        return s;\n    }\n\n    vector<int> global_mst_order(const vector<int>& mat) const {\n        const int INF = 1e9;\n        vector<int> mn(N, INF), par(N, -1);\n        vector<char> used(N, 0);\n\n        int root = 0;\n        for (int i = 1; i < N; i++) if (zkey[i] < zkey[root]) root = i;\n        mn[root] = 0;\n\n        for (int it = 0; it < N; it++) {\n            int v = -1;\n            for (int i = 0; i < N; i++) {\n                if (!used[i] && (v == -1 || mn[i] < mn[v])) v = i;\n            }\n            used[v] = 1;\n            int base = v * N;\n            for (int u = 0; u < N; u++) {\n                if (used[u]) continue;\n                int w = mat[base + u];\n                if (w < mn[u]) {\n                    mn[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<vector<int>> adj(N);\n        for (int i = 0; i < N; i++) {\n            if (i == root) continue;\n            if (par[i] >= 0) {\n                adj[i].push_back(par[i]);\n                adj[par[i]].push_back(i);\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            sort(adj[i].begin(), adj[i].end(), [&](int a, int b) {\n                if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                return a < b;\n            });\n        }\n\n        vector<int> order;\n        order.reserve(N);\n        vector<int> st;\n        vector<int> itPtr(N, 0);\n        vector<char> vis(N, 0);\n\n        st.push_back(root);\n        vis[root] = 1;\n        order.push_back(root);\n\n        while (!st.empty()) {\n            int v = st.back();\n            if (itPtr[v] == (int)adj[v].size()) {\n                st.pop_back();\n                continue;\n            }\n            int to = adj[v][itPtr[v]++];\n            if (vis[to]) continue;\n            vis[to] = 1;\n            order.push_back(to);\n            st.push_back(to);\n        }\n\n        if ((int)order.size() < N) {\n            vector<char> used2(N, 0);\n            for (int x : order) used2[x] = 1;\n            for (int i = 0; i < N; i++) if (!used2[i]) order.push_back(i);\n        }\n        return order;\n    }\n\n    bool validate_groups(const vector<vector<int>>& groups) const {\n        if ((int)groups.size() != M) return false;\n        vector<int> cnt(N, 0);\n        for (int g = 0; g < M; g++) {\n            if ((int)groups[g].size() != G[g]) return false;\n            for (int c : groups[g]) {\n                if (c < 0 || c >= N) return false;\n                cnt[c]++;\n            }\n        }\n        for (int i = 0; i < N; i++) if (cnt[i] != 1) return false;\n        return true;\n    }\n\n    long long eval_groups(const vector<vector<int>>& groups) const {\n        long long s = 0;\n        for (int g = 0; g < M; g++) s += prim_cost(groups[g], d_group);\n        return s;\n    }\n\n    vector<vector<int>> build_order_trial(const vector<int>& city_order, const vector<int>& group_order) const {\n        vector<vector<int>> out(M);\n        int p = 0;\n        for (int gid : group_order) {\n            int sz = G[gid];\n            out[gid].assign(city_order.begin() + p, city_order.begin() + p + sz);\n            p += sz;\n        }\n        return out;\n    }\n\n    void rec_assign(vector<int> cities, vector<int> gids, vector<vector<int>>& out, bool randomized) {\n        if ((int)gids.size() == 1) {\n            out[gids[0]] = std::move(cities);\n            return;\n        }\n\n        int S = (int)cities.size();\n\n        int minx = INT_MAX, maxx = INT_MIN, miny = INT_MAX, maxy = INT_MIN;\n        for (int c : cities) {\n            minx = min(minx, cx2[c]);\n            maxx = max(maxx, cx2[c]);\n            miny = min(miny, cy2[c]);\n            maxy = max(maxy, cy2[c]);\n        }\n\n        int axis = ((maxx - minx) >= (maxy - miny)) ? 0 : 1;\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 28) axis ^= 1;\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            if (axis == 0) {\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                return a < b;\n            } else {\n                if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n                if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n                return a < b;\n            }\n        });\n\n        vector<int> pg = gids;\n        if (randomized) shuffle(pg.begin(), pg.end(), rng);\n\n        vector<char> dp(S + 1, 0);\n        vector<int> prv(S + 1, -1), itm(S + 1, -1);\n        dp[0] = 1;\n\n        for (int j = 0; j < (int)pg.size(); j++) {\n            int w = G[pg[j]];\n            for (int s = S - w; s >= 0; s--) {\n                if (dp[s] && !dp[s + w]) {\n                    dp[s + w] = 1;\n                    prv[s + w] = s;\n                    itm[s + w] = j;\n                }\n            }\n        }\n\n        int target = S / 2;\n        if (randomized) {\n            int r = max(1, S / 6);\n            target += uniform_int_distribution<int>(-r, r)(rng);\n            target = max(1, min(S - 1, target));\n        }\n\n        int bestDiff = INT_MAX;\n        vector<int> candS;\n        for (int s = 1; s <= S - 1; s++) {\n            if (!dp[s]) continue;\n            int diff = abs(s - target);\n            if (diff < bestDiff) {\n                bestDiff = diff;\n                candS.clear();\n                candS.push_back(s);\n            } else if (diff == bestDiff) {\n                candS.push_back(s);\n            }\n        }\n\n        int split = -1;\n        if (!candS.empty()) {\n            split = randomized\n                ? candS[uniform_int_distribution<int>(0, (int)candS.size() - 1)(rng)]\n                : candS[0];\n        }\n\n        vector<int> gA, gB;\n        bool ok = (split > 0 && split < S);\n        if (ok) {\n            vector<char> take(pg.size(), 0);\n            int cur = split;\n            while (cur > 0) {\n                int j = itm[cur];\n                if (j < 0 || take[j]) {\n                    ok = false;\n                    break;\n                }\n                take[j] = 1;\n                cur = prv[cur];\n            }\n\n            if (ok) {\n                int sumA = 0;\n                for (int j = 0; j < (int)pg.size(); j++) {\n                    if (take[j]) {\n                        gA.push_back(pg[j]);\n                        sumA += G[pg[j]];\n                    } else {\n                        gB.push_back(pg[j]);\n                    }\n                }\n                if (gA.empty() || gB.empty() || sumA != split) ok = false;\n            }\n        }\n\n        if (!ok) {\n            gA.clear(); gB.clear();\n            gA.push_back(pg[0]);\n            split = G[pg[0]];\n            for (int j = 1; j < (int)pg.size(); j++) gB.push_back(pg[j]);\n        }\n\n        vector<int> cA(cities.begin(), cities.begin() + split);\n        vector<int> cB(cities.begin() + split, cities.end());\n\n        rec_assign(std::move(cA), std::move(gA), out, randomized);\n        rec_assign(std::move(cB), std::move(gB), out, randomized);\n    }\n\n    vector<vector<int>> build_recursive_trial(bool randomized) {\n        vector<vector<int>> out(M);\n        vector<int> cities(N), gids(M);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        sort(gids.begin(), gids.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        if (randomized && uniform_int_distribution<int>(0, 99)(rng) < 20) {\n            shuffle(gids.begin(), gids.end(), rng);\n        }\n\n        rec_assign(std::move(cities), std::move(gids), out, randomized);\n        return out;\n    }\n\n    vector<vector<int>> make_grouping() {\n        vector<vector<int>> best;\n        long long bestScore = (1LL << 62);\n\n        auto consider = [&](vector<vector<int>> cand) {\n            if (!validate_groups(cand)) return;\n            long long sc = eval_groups(cand);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = std::move(cand);\n            }\n        };\n\n        vector<int> goOrig(M), goDesc(M), goAsc(M), goRand(M);\n        iota(goOrig.begin(), goOrig.end(), 0);\n        goDesc = goOrig;\n        goAsc = goOrig;\n        goRand = goOrig;\n\n        sort(goDesc.begin(), goDesc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        sort(goAsc.begin(), goAsc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        shuffle(goRand.begin(), goRand.end(), rng);\n\n        vector<vector<int>> groupOrders = {goDesc, goOrig, goAsc, goRand};\n\n        vector<vector<int>> cityOrders;\n        auto ordZ = make_city_order([&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n        auto ordX = make_city_order([&](int a, int b) {\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            return a < b;\n        });\n        auto ordY = make_city_order([&](int a, int b) {\n            if (cy2[a] != cy2[b]) return cy2[a] < cy2[b];\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ordD1 = make_city_order([&](int a, int b) {\n            int ka = cx2[a] + cy2[a];\n            int kb = cx2[b] + cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n        auto ordD2 = make_city_order([&](int a, int b) {\n            int ka = cx2[a] - cy2[a];\n            int kb = cx2[b] - cy2[b];\n            if (ka != kb) return ka < kb;\n            if (cx2[a] != cx2[b]) return cx2[a] < cx2[b];\n            return a < b;\n        });\n\n        cityOrders.push_back(ordZ);\n        cityOrders.push_back(ordX);\n        cityOrders.push_back(ordY);\n        cityOrders.push_back(ordD1);\n        cityOrders.push_back(ordD2);\n\n        auto rev = ordZ;\n        reverse(rev.begin(), rev.end());\n        cityOrders.push_back(rev);\n\n        cityOrders.push_back(global_mst_order(d_group));\n\n        const double PI = acos(-1.0);\n        cityOrders.push_back(city_order_projection(PI * 1.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 3.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 5.0 / 8.0));\n        cityOrders.push_back(city_order_projection(PI * 7.0 / 8.0));\n\n        uniform_real_distribution<double> ur(0.0, PI);\n        cityOrders.push_back(city_order_projection(ur(rng)));\n        cityOrders.push_back(city_order_projection(ur(rng)));\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                consider(build_order_trial(co, go));\n            }\n        }\n\n        consider(build_recursive_trial(false));\n        for (int t = 0; t < 6; t++) consider(build_recursive_trial(true));\n\n        if (best.empty()) best = build_order_trial(ordZ, goOrig);\n        return best;\n    }\n\n    void optimize_groups(vector<vector<int>>& groups, double sec_budget) {\n        using Clock = chrono::steady_clock;\n        auto start = Clock::now();\n        auto deadline = start + chrono::milliseconds((int)(sec_budget * 1000.0));\n        auto stage1 = start + chrono::milliseconds((int)(sec_budget * 650.0));\n\n        vector<int> gid(N, -1), pos(N, -1);\n        for (int g = 0; g < M; g++) {\n            for (int i = 0; i < (int)groups[g].size(); i++) {\n                int c = groups[g][i];\n                gid[c] = g;\n                pos[c] = i;\n            }\n        }\n\n        vector<long long> gcost(M, 0);\n        for (int g = 0; g < M; g++) gcost[g] = prim_cost(groups[g], d_group);\n\n        auto near = build_knn(d_group, 24);\n        vector<int> order(N);\n        iota(order.begin(), order.end(), 0);\n        uniform_int_distribution<int> uid(0, N - 1);\n\n        long long opBudget = 45000000;\n\n        auto try_swap = [&](int u, int v) -> bool {\n            int ga = gid[u], gb = gid[v];\n            if (ga == gb || ga < 0 || gb < 0) return false;\n\n            int sa = (int)groups[ga].size();\n            int sb = (int)groups[gb].size();\n            long long est = 1LL * sa * sa + 1LL * sb * sb;\n            if (est > opBudget) return false;\n            opBudget -= est;\n\n            int pu = pos[u], pv = pos[v];\n            auto& A = groups[ga];\n            auto& B = groups[gb];\n\n            swap(A[pu], B[pv]);\n            long long nA = prim_cost(A, d_group);\n            long long nB = prim_cost(B, d_group);\n\n            if (nA + nB < gcost[ga] + gcost[gb]) {\n                gid[u] = gb; gid[v] = ga;\n                pos[u] = pv; pos[v] = pu;\n                gcost[ga] = nA;\n                gcost[gb] = nB;\n                return true;\n            } else {\n                swap(A[pu], B[pv]);\n                return false;\n            }\n        };\n\n        while (Clock::now() < stage1 && opBudget > 0) {\n            bool improved = false;\n            shuffle(order.begin(), order.end(), rng);\n\n            for (int it = 0; it < N; it++) {\n                if ((it & 31) == 0) {\n                    if (Clock::now() >= stage1 || opBudget <= 0) break;\n                }\n\n                int u = order[it];\n                bool ok = false;\n\n                int T = min(12, (int)near[u].size());\n                for (int i = 0; i < T; i++) {\n                    int v = near[u][i];\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        ok = true;\n                        break;\n                    }\n                }\n                if (ok) continue;\n\n                for (int r = 0; r < 2; r++) {\n                    int v = uid(rng);\n                    if (v == u) continue;\n                    if (try_swap(u, v)) {\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n\n        auto try_pair_repartition = [&](int a, int b) -> bool {\n            if (a == b) return false;\n            int sa = (int)groups[a].size();\n            int sb = (int)groups[b].size();\n            if (sa == 0 || sb == 0) return false;\n            if (sa + sb > 220) return false;\n\n            vector<int> U = groups[a];\n            U.insert(U.end(), groups[b].begin(), groups[b].end());\n\n            long long oldCost = gcost[a] + gcost[b];\n            long long bestCost = oldCost;\n            long long bestCA = gcost[a], bestCB = gcost[b];\n            vector<int> bestA = groups[a], bestB = groups[b];\n\n            auto centroid = [&](const vector<int>& V) -> pair<double,double> {\n                double sx = 0.0, sy = 0.0;\n                for (int c : V) {\n                    sx += cx2[c];\n                    sy += cy2[c];\n                }\n                double inv = 1.0 / (double)V.size();\n                return {sx * inv, sy * inv};\n            };\n\n            auto [ax, ay] = centroid(groups[a]);\n            auto [bx, by] = centroid(groups[b]);\n\n            auto considerAB = [&](const vector<int>& A, const vector<int>& B) {\n                if ((int)A.size() != sa || (int)B.size() != sb) return;\n                long long cA = prim_cost(A, d_group);\n                long long cB = prim_cost(B, d_group);\n                if (cA + cB < bestCost) {\n                    bestCost = cA + cB;\n                    bestCA = cA;\n                    bestCB = cB;\n                    bestA = A;\n                    bestB = B;\n                }\n            };\n\n            auto eval_sorted = [&](vector<pair<double,int>>& arr) {\n                sort(arr.begin(), arr.end(), [&](const auto& p1, const auto& p2) {\n                    if (fabs(p1.first - p2.first) > 1e-12) return p1.first < p2.first;\n                    return p1.second < p2.second;\n                });\n\n                vector<int> A, B;\n                A.reserve(sa); B.reserve(sb);\n\n                // first sa -> A\n                for (int i = 0; i < sa; i++) A.push_back(arr[i].second);\n                for (int i = sa; i < sa + sb; i++) B.push_back(arr[i].second);\n                considerAB(A, B);\n\n                // first sb -> B\n                A.clear(); B.clear();\n                for (int i = 0; i < sb; i++) B.push_back(arr[i].second);\n                for (int i = sb; i < sa + sb; i++) A.push_back(arr[i].second);\n                considerAB(A, B);\n            };\n\n            // proposal 1: da-db\n            {\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    double dax = cx2[v] - ax, day = cy2[v] - ay;\n                    double dbx = cx2[v] - bx, dby = cy2[v] - by;\n                    double da = dax * dax + day * day;\n                    double db = dbx * dbx + dby * dby;\n                    arr.push_back({da - db, v});\n                }\n                eval_sorted(arr);\n            }\n\n            // proposal 2: centroid axis projection\n            {\n                double vx = bx - ax, vy = by - ay;\n                if (fabs(vx) + fabs(vy) < 1e-12) {\n                    double ang = uniform_real_distribution<double>(0.0, acos(-1.0))(rng);\n                    vx = cos(ang); vy = sin(ang);\n                }\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    arr.push_back({vx * cx2[v] + vy * cy2[v], v});\n                }\n                eval_sorted(arr);\n            }\n\n            // proposal 3: random projection\n            {\n                double ang = uniform_real_distribution<double>(0.0, acos(-1.0))(rng);\n                double vx = cos(ang), vy = sin(ang);\n                vector<pair<double,int>> arr;\n                arr.reserve(sa + sb);\n                for (int v : U) {\n                    arr.push_back({vx * cx2[v] + vy * cy2[v], v});\n                }\n                eval_sorted(arr);\n            }\n\n            if (bestCost < oldCost) {\n                groups[a] = std::move(bestA);\n                groups[b] = std::move(bestB);\n                gcost[a] = bestCA;\n                gcost[b] = bestCB;\n\n                for (int i = 0; i < (int)groups[a].size(); i++) {\n                    int c = groups[a][i];\n                    gid[c] = a;\n                    pos[c] = i;\n                }\n                for (int i = 0; i < (int)groups[b].size(); i++) {\n                    int c = groups[b][i];\n                    gid[c] = b;\n                    pos[c] = i;\n                }\n                return true;\n            }\n            return false;\n        };\n\n        for (int pass = 0; pass < 3; pass++) {\n            if (Clock::now() >= deadline) break;\n\n            vector<pair<double,double>> cent(M, {0.0, 0.0});\n            for (int g = 0; g < M; g++) {\n                double sx = 0.0, sy = 0.0;\n                for (int c : groups[g]) {\n                    sx += cx2[c];\n                    sy += cy2[c];\n                }\n                if (!groups[g].empty()) {\n                    double inv = 1.0 / (double)groups[g].size();\n                    cent[g] = {sx * inv, sy * inv};\n                }\n            }\n\n            const int K = 5;\n            vector<pair<int,int>> pairs;\n            vector<char> seen(M * M, 0);\n\n            for (int a = 0; a < M; a++) {\n                vector<pair<double,int>> arr;\n                arr.reserve(M - 1);\n                for (int b = 0; b < M; b++) {\n                    if (a == b) continue;\n                    double dx = cent[a].first - cent[b].first;\n                    double dy = cent[a].second - cent[b].second;\n                    arr.push_back({dx * dx + dy * dy, b});\n                }\n\n                int k = min(K, (int)arr.size());\n                if ((int)arr.size() > k) {\n                    nth_element(arr.begin(), arr.begin() + k, arr.end(),\n                                [&](const auto& p1, const auto& p2) { return p1.first < p2.first; });\n                    arr.resize(k);\n                }\n                sort(arr.begin(), arr.end(),\n                     [&](const auto& p1, const auto& p2) { return p1.first < p2.first; });\n\n                for (auto& e : arr) {\n                    int b = e.second;\n                    int x = min(a, b), y = max(a, b);\n                    int key = x * M + y;\n                    if (!seen[key]) {\n                        seen[key] = 1;\n                        pairs.push_back({x, y});\n                    }\n                }\n            }\n\n            shuffle(pairs.begin(), pairs.end(), rng);\n\n            bool improved = false;\n            for (auto [a, b] : pairs) {\n                if (Clock::now() >= deadline) break;\n                if (try_pair_repartition(a, b)) improved = true;\n            }\n            if (!improved) break;\n        }\n    }\n\n    int choose_medoid_idx(const vector<int>& nodes) const {\n        int n = (int)nodes.size();\n        int best = 0;\n        long long bestSum = (1LL << 62);\n\n        for (int i = 0; i < n; i++) {\n            int a = nodes[i];\n            int base = a * N;\n            long long s = 0;\n            for (int j = 0; j < n; j++) {\n                s += d_base[base + nodes[j]];\n                if (s >= bestSum) break;\n            }\n            if (s < bestSum) {\n                bestSum = s;\n                best = i;\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_base_group_edges(const vector<int>& nodes, int& q_used, vector<pair<int,int>>& cand_store) {\n        int g = (int)nodes.size();\n        vector<pair<int,int>> base;\n        if (g <= 1) return base;\n\n        auto append_ret = [&](const vector<pair<int,int>>& ret) {\n            for (auto [a, b] : ret) {\n                if (a > b) swap(a, b);\n                base.emplace_back(a, b);\n                cand_store.emplace_back(a, b);\n            }\n        };\n\n        if (g == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            base.push_back(p);\n            cand_store.push_back(p);\n            return base;\n        }\n\n        int need = query_need(g);\n        if (q_used + need > Q) {\n            base = prim_tree(nodes, d_base);\n            cand_store.insert(cand_store.end(), base.begin(), base.end());\n            return base;\n        }\n\n        vector<int> ord = nodes;\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        if (g <= L) {\n            auto ret = do_query(ord);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n            if ((int)base.size() != g - 1) {\n                base = prim_tree(nodes, d_base);\n                cand_store.insert(cand_store.end(), base.begin(), base.end());\n            }\n            return base;\n        }\n\n        int root = choose_medoid_idx(ord);\n\n        vector<char> conn(g, 0);\n        vector<int> nearestDist(g, (int)1e9), nearestAnchor(g, -1);\n\n        // first query: root + nearest (L-1)\n        vector<pair<int,int>> arr;\n        arr.reserve(g - 1);\n        for (int i = 0; i < g; i++) {\n            if (i == root) continue;\n            arr.push_back({DBase(ord[root], ord[i]), i});\n        }\n        sort(arr.begin(), arr.end(), [&](const auto& p1, const auto& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        });\n\n        int t0 = min(L - 1, g - 1);\n        vector<int> firstIdx;\n        firstIdx.reserve(t0);\n        for (int i = 0; i < t0; i++) firstIdx.push_back(arr[i].second);\n\n        vector<int> subset;\n        subset.reserve(1 + t0);\n        subset.push_back(ord[root]);\n        for (int idx : firstIdx) subset.push_back(ord[idx]);\n\n        {\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n        }\n\n        conn[root] = 1;\n        for (int idx : firstIdx) conn[idx] = 1;\n        int rem = g - 1 - t0;\n\n        auto update_by_new = [&](int idx) {\n            int c = ord[idx];\n            for (int j = 0; j < g; j++) {\n                if (conn[j]) continue;\n                int d = DBase(c, ord[j]);\n                if (d < nearestDist[j]) {\n                    nearestDist[j] = d;\n                    nearestAnchor[j] = idx;\n                }\n            }\n        };\n\n        for (int i = 0; i < g; i++) {\n            nearestDist[i] = (int)1e9;\n            nearestAnchor[i] = -1;\n        }\n        update_by_new(root);\n        for (int idx : firstIdx) update_by_new(idx);\n\n        while (rem > 0) {\n            int u = -1, best = (int)1e9;\n            for (int i = 0; i < g; i++) {\n                if (!conn[i] && nearestDist[i] < best) {\n                    best = nearestDist[i];\n                    u = i;\n                }\n            }\n            if (u < 0) break;\n\n            int anchor = nearestAnchor[u];\n            if (anchor < 0) anchor = root;\n\n            int t = min(L - 1, rem);\n            vector<int> batch;\n            batch.reserve(t);\n            batch.push_back(u);\n\n            if (t > 1) {\n                vector<pair<int,int>> cand;\n                cand.reserve(rem - 1);\n                int ac = ord[anchor];\n                for (int i = 0; i < g; i++) {\n                    if (conn[i] || i == u) continue;\n                    cand.push_back({DBase(ac, ord[i]), i});\n                }\n                sort(cand.begin(), cand.end(), [&](const auto& p1, const auto& p2) {\n                    if (p1.first != p2.first) return p1.first < p2.first;\n                    return p1.second < p2.second;\n                });\n                for (int i = 0; i < t - 1 && i < (int)cand.size(); i++) {\n                    batch.push_back(cand[i].second);\n                }\n            }\n\n            subset.clear();\n            subset.push_back(ord[anchor]);\n            for (int idx : batch) subset.push_back(ord[idx]);\n\n            auto ret = do_query(subset);\n            q_used++;\n            record_edges(ret);\n            append_ret(ret);\n\n            for (int idx : batch) {\n                if (!conn[idx]) {\n                    conn[idx] = 1;\n                    rem--;\n                }\n            }\n            for (int idx : batch) update_by_new(idx);\n        }\n\n        if ((int)base.size() != g - 1) {\n            base = prim_tree(nodes, d_base);\n            cand_store.insert(cand_store.end(), base.begin(), base.end());\n        }\n        return base;\n    }\n\n    vector<int> make_subset_window(const vector<int>& ordz) {\n        int g = (int)ordz.size();\n        int l = min(L, g);\n        if (l < 2) return {};\n        if (g == l) return ordz;\n        int s = uniform_int_distribution<int>(0, g - l)(rng);\n        return vector<int>(ordz.begin() + s, ordz.begin() + s + l);\n    }\n\n    vector<int> make_subset_star(const vector<int>& nodes) {\n        int g = (int)nodes.size();\n        int l = min(L, g);\n        if (l < 2) return {};\n        if (g == l) return nodes;\n\n        int center = nodes[uniform_int_distribution<int>(0, g - 1)(rng)];\n        vector<pair<int,int>> arr;\n        arr.reserve(g - 1);\n        for (int v : nodes) if (v != center) {\n            arr.push_back({DBase(center, v), v});\n        }\n\n        auto cmp = [](const pair<int,int>& p1, const pair<int,int>& p2) {\n            if (p1.first != p2.first) return p1.first < p2.first;\n            return p1.second < p2.second;\n        };\n\n        if ((int)arr.size() > l - 1) {\n            nth_element(arr.begin(), arr.begin() + (l - 1), arr.end(), cmp);\n            arr.resize(l - 1);\n        }\n        sort(arr.begin(), arr.end(), cmp);\n\n        vector<int> subset;\n        subset.reserve(l);\n        subset.push_back(center);\n        for (auto& p : arr) {\n            if ((int)subset.size() >= l) break;\n            subset.push_back(p.second);\n        }\n\n        if ((int)subset.size() < 2) {\n            for (int v : nodes) if (v != center) {\n                subset.push_back(v);\n                break;\n            }\n        }\n        return subset;\n    }\n\n    vector<pair<int,int>> mst_from_candidates(const vector<int>& nodes, const vector<pair<int,int>>& cand) const {\n        int n = (int)nodes.size();\n        if (n <= 1) return {};\n        if (n == 2) {\n            auto p = minmax(nodes[0], nodes[1]);\n            return {p};\n        }\n\n        vector<int> loc(N, -1);\n        for (int i = 0; i < n; i++) loc[nodes[i]] = i;\n\n        unordered_map<int, int> cnt;\n        cnt.reserve(cand.size() * 2 + 1);\n\n        for (auto [a, b] : cand) {\n            if (a > b) swap(a, b);\n            if (a < 0 || b < 0 || a >= N || b >= N || a == b) continue;\n            if (loc[a] < 0 || loc[b] < 0) continue;\n            int key = a * EDGE_BASE + b;\n            cnt[key]++;\n        }\n\n        struct E {\n            long long w;\n            int a, b;\n        };\n        vector<E> es;\n        es.reserve(cnt.size());\n\n        for (auto& kv : cnt) {\n            int key = kv.first;\n            int c = kv.second;\n            int a = key / EDGE_BASE;\n            int b = key % EDGE_BASE;\n\n            long long w = 1LL * d_base[ID(a, b)] * 10 - 90LL * min(c, 6);\n            es.push_back({w, a, b});\n        }\n\n        sort(es.begin(), es.end(), [&](const E& e1, const E& e2) {\n            if (e1.w != e2.w) return e1.w < e2.w;\n            if (e1.a != e2.a) return e1.a < e2.a;\n            return e1.b < e2.b;\n        });\n\n        DSU dsu(n);\n        vector<pair<int,int>> out;\n        out.reserve(n - 1);\n\n        for (auto& e : es) {\n            int ia = loc[e.a], ib = loc[e.b];\n            if (ia < 0 || ib < 0) continue;\n            if (dsu.unite(ia, ib)) {\n                int a = e.a, b = e.b;\n                if (a > b) swap(a, b);\n                out.emplace_back(a, b);\n                if ((int)out.size() == n - 1) break;\n            }\n        }\n\n        if ((int)out.size() != n - 1) return {};\n        return out;\n    }\n\n    vector<vector<int>> fallback_grouping() const {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n            return a < b;\n        });\n\n        vector<vector<int>> groups(M);\n        int p = 0;\n        for (int k = 0; k < M; k++) {\n            groups[k].assign(ord.begin() + p, ord.begin() + p + G[k]);\n            p += G[k];\n        }\n        return groups;\n    }\n\n    void solve() {\n        input();\n        init_rng();\n        preprocess();\n\n        int reqMin = 0;\n        for (int g : G) reqMin += query_need(g);\n        int spare = Q - reqMin;\n\n        int q_used = 0;\n        int q_explore = 0;\n        if (spare > 20) {\n            if (spare <= 80) q_explore = spare / 3;\n            else if (spare <= 180) q_explore = spare / 2;\n            else q_explore = (spare * 2) / 3;\n            q_explore = min(q_explore, 180);\n            q_explore = min(q_explore, spare);\n        }\n\n        // 1) Exploration for better grouping\n        perform_exploration(q_explore, q_used);\n        rebuild_group_matrix_from_obs();\n\n        // 2) Grouping + local improvement (on learned distance)\n        auto groups = make_grouping();\n        if (!validate_groups(groups)) groups = fallback_grouping();\n\n        optimize_groups(groups, 0.72);\n        if (!validate_groups(groups)) groups = fallback_grouping();\n\n        // 3) Mandatory group-edge construction queries\n        vector<vector<pair<int,int>>> baseEdges(M), candEdges(M);\n\n        vector<int> gidOrder(M);\n        iota(gidOrder.begin(), gidOrder.end(), 0);\n        sort(gidOrder.begin(), gidOrder.end(), [&](int a, int b) {\n            if ((int)groups[a].size() != (int)groups[b].size()) return groups[a].size() > groups[b].size();\n            return a < b;\n        });\n\n        for (int gid : gidOrder) {\n            baseEdges[gid] = build_base_group_edges(groups[gid], q_used, candEdges[gid]);\n        }\n\n        // 4) Extra queries for large groups only\n        if (q_used < Q) {\n            vector<int> targets;\n            for (int g = 0; g < M; g++) if ((int)groups[g].size() > L) targets.push_back(g);\n\n            if (!targets.empty()) {\n                vector<vector<int>> ordz(M);\n                for (int gid : targets) {\n                    ordz[gid] = groups[gid];\n                    sort(ordz[gid].begin(), ordz[gid].end(), [&](int a, int b) {\n                        if (zkey[a] != zkey[b]) return zkey[a] < zkey[b];\n                        return a < b;\n                    });\n                }\n\n                vector<double> weights;\n                weights.reserve(targets.size());\n                for (int gid : targets) {\n                    double sz = (double)groups[gid].size();\n                    weights.push_back(pow(sz, 1.35));\n                }\n\n                discrete_distribution<int> pick(weights.begin(), weights.end());\n\n                while (q_used < Q) {\n                    int gid = targets[pick(rng)];\n                    vector<int> subset;\n                    int mode = uniform_int_distribution<int>(0, 99)(rng);\n                    if (mode < 55) subset = make_subset_window(ordz[gid]);\n                    else subset = make_subset_star(groups[gid]);\n\n                    if ((int)subset.size() < 2) continue;\n                    auto ret = do_query(subset);\n                    q_used++;\n                    record_edges(ret);\n\n                    for (auto [a, b] : ret) {\n                        if (a > b) swap(a, b);\n                        candEdges[gid].emplace_back(a, b);\n                    }\n                }\n            }\n        }\n\n        // 5) Build final trees\n        vector<int> city_gid(N, -1);\n        for (int g = 0; g < M; g++) {\n            for (int c : groups[g]) city_gid[c] = g;\n        }\n\n        // Add all observed in-group edges (explore + mandatory + extra) as candidates\n        for (auto [a, b] : touchedObs) {\n            int ga = city_gid[a], gb = city_gid[b];\n            if (ga >= 0 && ga == gb) {\n                int c = (int)obsCnt[ID(a, b)];\n                int rep = min(4, c);\n                for (int t = 0; t < rep; t++) candEdges[ga].emplace_back(a, b);\n            }\n        }\n\n        vector<vector<pair<int,int>>> finalEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int sz = (int)groups[k].size();\n            if (sz <= 1) {\n                finalEdges[k].clear();\n                continue;\n            }\n\n            if ((int)baseEdges[k].size() != sz - 1) {\n                baseEdges[k] = prim_tree(groups[k], d_base);\n            }\n\n            // If sz<=L, baseEdges is exact MST query result (or trivial), so keep it.\n            if (sz <= L) {\n                finalEdges[k] = baseEdges[k];\n                continue;\n            }\n\n            auto candTree = mst_from_candidates(groups[k], candEdges[k]);\n            if ((int)candTree.size() == sz - 1) {\n                long long bc = edge_proxy_cost(baseEdges[k], d_base);\n                long long cc = edge_proxy_cost(candTree, d_base);\n                if (cc < bc) finalEdges[k] = std::move(candTree);\n                else finalEdges[k] = baseEdges[k];\n            } else {\n                finalEdges[k] = baseEdges[k];\n            }\n\n            if ((int)finalEdges[k].size() != sz - 1) {\n                finalEdges[k] = prim_tree(groups[k], d_base);\n            }\n        }\n\n        // 6) Output\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << \"\\n\";\n            for (auto [a, b] : finalEdges[k]) {\n                cout << a << \" \" << b << \"\\n\";\n            }\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point { int r, c; };\nstruct Action { char a, d; };\n\nclass Solver {\n    static constexpr int MAXN = 20;\n    static constexpr int INF = 1e9;\n    using Clock = chrono::steady_clock;\n\n    int N, M, LIMIT, n2;\n    vector<Point> pts;                 // pts[0]=start, pts[1..]=targets\n    vector<int> pid;                   // cell id for pts[i]\n    vector<int> cellR, cellC;          // cell id -> r,c\n    vector<array<int,4>> to;           // neighbors for move\n    vector<int> targetIdxAtCell;       // cell id -> index in pts, -1 if non-target\n\n    array<uint32_t, MAXN> lowMask{}, highMask{};\n    const array<int,4> DR{{-1, 1, 0, 0}};\n    const array<int,4> DC{{0, 0, -1, 1}};\n    const array<char,4> DCH{{'U','D','L','R'}};\n\n    struct Node {\n        array<uint32_t, MAXN> row{};\n        array<uint32_t, MAXN> col{};\n        int cost = INF;\n        int parent = -1;          // index in previous layer\n        uint8_t op = 0;           // 0:none, 1:A, 2:M+A, 3:S+A, 4:A+A\n        uint8_t d1 = 0, d2 = 0;   // params for op\n        uint16_t bcnt = 0;        // number of blocked cells (tracked incrementally)\n        int eval = 0;\n    };\n\n    struct Config {\n        bool allowFutureToggle = false;\n        bool enableDoubleAlter = false; // A+A\n        int wEarly = 180, wMid = 140, wLate = 110;\n        int preMul = 6;\n        int elitePct = 50;\n\n        int wCost = 10;\n        int wH1 = 4;\n        int wH2 = 2;\n        int wFutureBlocked = 0;\n        int wBlockBonus = 1;\n        int evalDistLimit = 55;\n    };\n\n    inline int widthAt(const Config& cfg, int k) const {\n        if (k < 12) return cfg.wEarly;\n        if (k < 26) return cfg.wMid;\n        return cfg.wLate;\n    }\n\n    inline bool isBlocked(const array<uint32_t,MAXN>& row, int id) const {\n        return ((row[cellR[id]] >> cellC[id]) & 1u) != 0u;\n    }\n\n    inline void toggleCell(array<uint32_t,MAXN>& row, array<uint32_t,MAXN>& col, int id) const {\n        int r = cellR[id], c = cellC[id];\n        row[r] ^= (1u << c);\n        col[c] ^= (1u << r);\n    }\n\n    inline int rowCompare(const array<uint32_t,MAXN>& a, const array<uint32_t,MAXN>& b) const {\n        return memcmp(a.data(), b.data(), N * sizeof(uint32_t));\n    }\n\n    inline bool isEmptyBoard(const array<uint32_t,MAXN>& row) const {\n        for (int r = 0; r < N; r++) if (row[r]) return false;\n        return true;\n    }\n\n    inline bool allowToggleCell(int cell, int k, const Config& cfg) const {\n        if (cell < 0) return false;\n        if (cfg.allowFutureToggle) return true;\n        int idx = targetIdxAtCell[cell];\n        return !(idx != -1 && idx > k);\n    }\n\n    inline int slideDest(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col, int u, int d) const {\n        int r = cellR[u], c = cellC[u];\n        if (d == 0) { // U\n            uint32_t m = col[c] & lowMask[r];\n            int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n            return nr * N + c;\n        } else if (d == 1) { // D\n            uint32_t m = col[c] & highMask[r];\n            int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n            return nr * N + c;\n        } else if (d == 2) { // L\n            uint32_t m = row[r] & lowMask[c];\n            int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n            return r * N + nc;\n        } else { // R\n            uint32_t m = row[r] & highMask[c];\n            int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n            return r * N + nc;\n        }\n    }\n\n    // Returns shortest distance if <= lim, else INF.\n    int bfsDistLimit(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                     int s, int g, int lim) const {\n        if (lim < 0) return INF;\n        if (s == g) return 0;\n\n        int dist[400];\n        for (int i = 0; i < n2; i++) dist[i] = -1;\n\n        int q[400];\n        int head = 0, tail = 0;\n        dist[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            if (du > lim) continue;\n            int r = cellR[u], c = cellC[u];\n\n            // Move\n            for (int d = 0; d < 4; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (dist[v] != -1) continue;\n                dist[v] = du;\n                if (v == g) return du;\n                q[tail++] = v;\n            }\n\n            // Slide U\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide D\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide L\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n            // Slide R\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (dist[v] == -1) {\n                        dist[v] = du;\n                        if (v == g) return du;\n                        q[tail++] = v;\n                    }\n                }\n            }\n        }\n        return INF;\n    }\n\n    bool bfsPath(const array<uint32_t,MAXN>& row, const array<uint32_t,MAXN>& col,\n                 int s, int g, vector<Action>& out) const {\n        out.clear();\n        if (s == g) return true;\n\n        int dist[400], par[400];\n        uint8_t pdir[400];\n        char pact[400];\n        for (int i = 0; i < n2; i++) {\n            dist[i] = -1;\n            par[i] = -1;\n        }\n\n        int q[400], head = 0, tail = 0;\n        dist[s] = 0;\n        par[s] = s;\n        q[tail++] = s;\n\n        bool found = false;\n        while (head < tail && !found) {\n            int u = q[head++];\n            int du = dist[u] + 1;\n            int r = cellR[u], c = cellC[u];\n\n            auto relax = [&](int v, char a, int d)->bool {\n                if (v == u) return false;\n                if (dist[v] != -1) return false;\n                dist[v] = du;\n                par[v] = u;\n                pact[v] = a;\n                pdir[v] = (uint8_t)d;\n                q[tail++] = v;\n                return v == g;\n            };\n\n            // Move\n            for (int d = 0; d < 4 && !found; d++) {\n                int v = to[u][d];\n                if (v == -1) continue;\n                if (isBlocked(row, v)) continue;\n                if (relax(v, 'M', d)) found = true;\n            }\n            if (found) break;\n\n            // Slides\n            {\n                uint32_t m = col[c] & lowMask[r];\n                int nr = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 0)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = col[c] & highMask[r];\n                int nr = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nr != r) {\n                    int v = nr * N + c;\n                    if (relax(v, 'S', 1)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = row[r] & lowMask[c];\n                int nc = m ? (31 - __builtin_clz(m)) + 1 : 0;\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 2)) found = true;\n                }\n            }\n            if (found) break;\n            {\n                uint32_t m = row[r] & highMask[c];\n                int nc = m ? (__builtin_ctz(m) - 1) : (N - 1);\n                if (nc != c) {\n                    int v = r * N + nc;\n                    if (relax(v, 'S', 3)) found = true;\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        vector<Action> rev;\n        int cur = g;\n        while (cur != s) {\n            if (cur < 0 || par[cur] < 0) return false;\n            rev.push_back(Action{pact[cur], DCH[pdir[cur]]});\n            cur = par[cur];\n        }\n        reverse(rev.begin(), rev.end());\n        out.swap(rev);\n        return true;\n    }\n\n    int countBlockedFutureTargets(const array<uint32_t,MAXN>& row, int fromIdx) const {\n        if (fromIdx >= M) return 0;\n        int cnt = 0;\n        for (int i = fromIdx; i < M; i++) {\n            int id = pid[i];\n            if ((row[cellR[id]] >> cellC[id]) & 1u) cnt++;\n        }\n        return cnt;\n    }\n\n    vector<Action> fallbackManhattan() const {\n        vector<Action> ans;\n        int r = pts[0].r, c = pts[0].c;\n        for (int k = 1; k < M; k++) {\n            int tr = pts[k].r, tc = pts[k].c;\n            while (r < tr) { ans.push_back({'M','D'}); r++; }\n            while (r > tr) { ans.push_back({'M','U'}); r--; }\n            while (c < tc) { ans.push_back({'M','R'}); c++; }\n            while (c > tc) { ans.push_back({'M','L'}); c--; }\n        }\n        return ans;\n    }\n\n    vector<Action> fallbackNoBlock() const {\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u); col.fill(0u);\n\n        vector<Action> ans;\n        int cur = pid[0];\n        for (int k = 0; k < M - 1; k++) {\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, pid[k+1], path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = pid[k+1];\n        }\n        return ans;\n    }\n\n    bool validate(const vector<Action>& acts) const {\n        if ((int)acts.size() > LIMIT) return false;\n        vector<vector<uint8_t>> blk(N, vector<uint8_t>(N, 0));\n\n        int r = pts[0].r, c = pts[0].c;\n        int nxt = 1;\n\n        auto dirId = [&](char ch)->int {\n            if (ch == 'U') return 0;\n            if (ch == 'D') return 1;\n            if (ch == 'L') return 2;\n            if (ch == 'R') return 3;\n            return -1;\n        };\n\n        for (const auto& ac : acts) {\n            int d = dirId(ac.d);\n            if (d < 0) return false;\n\n            if (ac.a == 'M') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                if (blk[nr][nc]) return false;\n                r = nr; c = nc;\n            } else if (ac.a == 'S') {\n                int nr = r, nc = c;\n                while (true) {\n                    int tr = nr + DR[d], tc = nc + DC[d];\n                    if (!(0 <= tr && tr < N && 0 <= tc && tc < N)) break;\n                    if (blk[tr][tc]) break;\n                    nr = tr; nc = tc;\n                }\n                r = nr; c = nc;\n            } else if (ac.a == 'A') {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!(0 <= nr && nr < N && 0 <= nc && nc < N)) return false;\n                blk[nr][nc] ^= 1;\n            } else {\n                return false;\n            }\n\n            if (nxt < M && r == pts[nxt].r && c == pts[nxt].c) nxt++;\n        }\n\n        return nxt == M;\n    }\n\n    vector<Action> runBeam(int upperBound, const Config& cfg, Clock::time_point dl) {\n        if (upperBound <= 0) return {};\n\n        vector<vector<Node>> layers(M);\n        layers[0].reserve(1);\n        Node init;\n        init.row.fill(0u);\n        init.col.fill(0u);\n        init.cost = 0;\n        init.parent = -1;\n        init.op = 0;\n        init.d1 = init.d2 = 0;\n        init.bcnt = 0;\n        layers[0].push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            if (Clock::now() >= dl) return {};\n\n            int s = pid[k], g = pid[k+1];\n            int W = widthAt(cfg, k);\n            int PRE = max(W + 1, W * cfg.preMul);\n\n            int approxTrans = 1 + 4 + 16 + 16 + (cfg.enableDoubleAlter ? 6 : 0);\n            vector<Node> cand;\n            cand.reserve((int)layers[k].size() * approxTrans + 16);\n\n            for (int si = 0; si < (int)layers[k].size(); si++) {\n                if ((si & 15) == 0 && Clock::now() >= dl) return {};\n                const Node& st = layers[k][si];\n\n                // 0) no prep\n                {\n                    int rem = upperBound - 1 - st.cost;\n                    if (rem >= 0) {\n                        int d0 = bfsDistLimit(st.row, st.col, s, g, rem);\n                        if (d0 < INF) {\n                            Node nd = st;\n                            nd.cost = st.cost + d0;\n                            nd.parent = si;\n                            nd.op = 0;\n                            nd.d1 = nd.d2 = 0;\n                            nd.eval = 0;\n                            cand.push_back(std::move(nd));\n                        }\n                    }\n                }\n\n                // 1) A\n                {\n                    int rem = upperBound - 1 - (st.cost + 1);\n                    if (rem >= 0) {\n                        array<uint32_t,MAXN> rowA = st.row;\n                        array<uint32_t,MAXN> colA = st.col;\n\n                        for (int ad = 0; ad < 4; ad++) {\n                            int tcell = to[s][ad];\n                            if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                            bool was = isBlocked(rowA, tcell);\n                            toggleCell(rowA, colA, tcell);\n\n                            int d = bfsDistLimit(rowA, colA, s, g, rem);\n                            if (d < INF) {\n                                Node nd;\n                                nd.row = rowA;\n                                nd.col = colA;\n                                nd.cost = st.cost + 1 + d;\n                                nd.parent = si;\n                                nd.op = 1;\n                                nd.d1 = (uint8_t)ad;\n                                nd.d2 = 0;\n                                int nb = (int)st.bcnt + (was ? -1 : +1);\n                                if (nb < 0) nb = 0;\n                                nd.bcnt = (uint16_t)nb;\n                                nd.eval = 0;\n                                cand.push_back(std::move(nd));\n                            }\n\n                            toggleCell(rowA, colA, tcell); // revert\n                        }\n                    }\n                }\n\n                // 2) M + A\n                // 3) S + A\n                {\n                    int rem = upperBound - 1 - (st.cost + 2);\n                    if (rem >= 0) {\n                        // M + A\n                        for (int md = 0; md < 4; md++) {\n                            int ncell = to[s][md];\n                            if (ncell == -1) continue;\n                            if (isBlocked(st.row, ncell)) continue; // move first\n\n                            array<uint32_t,MAXN> rowMA = st.row;\n                            array<uint32_t,MAXN> colMA = st.col;\n\n                            for (int ad = 0; ad < 4; ad++) {\n                                int tcell = to[ncell][ad];\n                                if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                                bool was = isBlocked(rowMA, tcell);\n                                toggleCell(rowMA, colMA, tcell);\n\n                                int d = bfsDistLimit(rowMA, colMA, ncell, g, rem);\n                                if (d < INF) {\n                                    Node nd;\n                                    nd.row = rowMA;\n                                    nd.col = colMA;\n                                    nd.cost = st.cost + 2 + d;\n                                    nd.parent = si;\n                                    nd.op = 2;\n                                    nd.d1 = (uint8_t)md;\n                                    nd.d2 = (uint8_t)ad;\n                                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                                    if (nb < 0) nb = 0;\n                                    nd.bcnt = (uint16_t)nb;\n                                    nd.eval = 0;\n                                    cand.push_back(std::move(nd));\n                                }\n\n                                toggleCell(rowMA, colMA, tcell); // revert\n                            }\n                        }\n\n                        // S + A\n                        for (int sd = 0; sd < 4; sd++) {\n                            int ncell = slideDest(st.row, st.col, s, sd);\n                            if (ncell == s) continue; // cannot slide\n\n                            array<uint32_t,MAXN> rowSA = st.row;\n                            array<uint32_t,MAXN> colSA = st.col;\n\n                            for (int ad = 0; ad < 4; ad++) {\n                                int tcell = to[ncell][ad];\n                                if (!allowToggleCell(tcell, k, cfg)) continue;\n\n                                bool was = isBlocked(rowSA, tcell);\n                                toggleCell(rowSA, colSA, tcell);\n\n                                int d = bfsDistLimit(rowSA, colSA, ncell, g, rem);\n                                if (d < INF) {\n                                    Node nd;\n                                    nd.row = rowSA;\n                                    nd.col = colSA;\n                                    nd.cost = st.cost + 2 + d;\n                                    nd.parent = si;\n                                    nd.op = 3;\n                                    nd.d1 = (uint8_t)sd;\n                                    nd.d2 = (uint8_t)ad;\n                                    int nb = (int)st.bcnt + (was ? -1 : +1);\n                                    if (nb < 0) nb = 0;\n                                    nd.bcnt = (uint16_t)nb;\n                                    nd.eval = 0;\n                                    cand.push_back(std::move(nd));\n                                }\n\n                                toggleCell(rowSA, colSA, tcell); // revert\n                            }\n                        }\n\n                        // 4) A + A (optional)\n                        if (cfg.enableDoubleAlter) {\n                            array<uint32_t,MAXN> rowAA = st.row;\n                            array<uint32_t,MAXN> colAA = st.col;\n\n                            for (int d1 = 0; d1 < 4; d1++) {\n                                int c1 = to[s][d1];\n                                if (!allowToggleCell(c1, k, cfg)) continue;\n\n                                bool was1 = isBlocked(rowAA, c1);\n                                toggleCell(rowAA, colAA, c1);\n                                int delta1 = was1 ? -1 : +1;\n\n                                for (int d2 = d1 + 1; d2 < 4; d2++) {\n                                    int c2 = to[s][d2];\n                                    if (!allowToggleCell(c2, k, cfg)) continue;\n\n                                    bool was2 = isBlocked(rowAA, c2); // c2 != c1\n                                    toggleCell(rowAA, colAA, c2);\n\n                                    int d = bfsDistLimit(rowAA, colAA, s, g, rem);\n                                    if (d < INF) {\n                                        Node nd;\n                                        nd.row = rowAA;\n                                        nd.col = colAA;\n                                        nd.cost = st.cost + 2 + d;\n                                        nd.parent = si;\n                                        nd.op = 4;\n                                        nd.d1 = (uint8_t)d1;\n                                        nd.d2 = (uint8_t)d2;\n                                        int nb = (int)st.bcnt + delta1 + (was2 ? -1 : +1);\n                                        if (nb < 0) nb = 0;\n                                        nd.bcnt = (uint16_t)nb;\n                                        nd.eval = 0;\n                                        cand.push_back(std::move(nd));\n                                    }\n\n                                    toggleCell(rowAA, colAA, c2); // revert d2\n                                }\n\n                                toggleCell(rowAA, colAA, c1); // revert d1\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (cand.empty()) return {};\n\n            // Dedup by board\n            sort(cand.begin(), cand.end(), [&](const Node& a, const Node& b) {\n                int cmp = rowCompare(a.row, b.row);\n                if (cmp != 0) return cmp < 0;\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.bcnt != b.bcnt) return a.bcnt > b.bcnt;\n                return a.parent < b.parent;\n            });\n\n            vector<Node> uniq;\n            uniq.reserve(cand.size());\n            for (auto& nd : cand) {\n                if (uniq.empty() || rowCompare(uniq.back().row, nd.row) != 0) {\n                    uniq.push_back(nd);\n                } else {\n                    Node& cur = uniq.back();\n                    if (nd.cost < cur.cost || (nd.cost == cur.cost && nd.bcnt > cur.bcnt)) {\n                        cur = nd;\n                    }\n                }\n            }\n\n            sort(uniq.begin(), uniq.end(), [](const Node& a, const Node& b) {\n                if (a.cost != b.cost) return a.cost < b.cost;\n                return a.bcnt > b.bcnt;\n            });\n\n            if ((int)uniq.size() > PRE) uniq.resize(PRE);\n\n            // Heuristic pruning\n            if ((int)uniq.size() > W) {\n                int from1 = pid[k+1];\n                int to1 = (k + 2 < M ? pid[k+2] : -1);\n                int from2 = (k + 2 < M ? pid[k+2] : -1);\n                int to2 = (k + 3 < M ? pid[k+3] : -1);\n\n                for (auto& nd : uniq) {\n                    int h1 = 0, h2 = 0;\n                    if (to1 != -1) {\n                        h1 = bfsDistLimit(nd.row, nd.col, from1, to1, cfg.evalDistLimit);\n                        if (h1 >= INF) h1 = cfg.evalDistLimit + 20;\n                    }\n                    if (to2 != -1) {\n                        h2 = bfsDistLimit(nd.row, nd.col, from2, to2, cfg.evalDistLimit);\n                        if (h2 >= INF) h2 = cfg.evalDistLimit + 20;\n                    }\n                    int fblk = (cfg.wFutureBlocked > 0) ? countBlockedFutureTargets(nd.row, k + 2) : 0;\n                    nd.eval = nd.cost * cfg.wCost\n                              + h1 * cfg.wH1\n                              + h2 * cfg.wH2\n                              + fblk * cfg.wFutureBlocked\n                              - min<int>(nd.bcnt, 40) * cfg.wBlockBonus;\n                }\n\n                vector<int> ord(uniq.size());\n                iota(ord.begin(), ord.end(), 0);\n                sort(ord.begin(), ord.end(), [&](int i, int j) {\n                    const Node& a = uniq[i];\n                    const Node& b = uniq[j];\n                    if (a.eval != b.eval) return a.eval < b.eval;\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                vector<Node> chosen;\n                chosen.reserve(W);\n                vector<char> used(uniq.size(), 0);\n\n                int elite = max(1, W * cfg.elitePct / 100);\n                elite = min(elite, (int)uniq.size());\n\n                for (int i = 0; i < elite; i++) {\n                    chosen.push_back(uniq[i]);\n                    used[i] = 1;\n                }\n                for (int id : ord) {\n                    if ((int)chosen.size() >= W) break;\n                    if (used[id]) continue;\n                    chosen.push_back(uniq[id]);\n                    used[id] = 1;\n                }\n\n                // keep empty-board state if available\n                bool hasEmpty = false;\n                for (const auto& nd : chosen) {\n                    if (isEmptyBoard(nd.row)) { hasEmpty = true; break; }\n                }\n                if (!hasEmpty) {\n                    for (const auto& nd : uniq) {\n                        if (isEmptyBoard(nd.row)) {\n                            if (!chosen.empty()) chosen.back() = nd;\n                            else chosen.push_back(nd);\n                            break;\n                        }\n                    }\n                }\n\n                sort(chosen.begin(), chosen.end(), [](const Node& a, const Node& b) {\n                    if (a.cost != b.cost) return a.cost < b.cost;\n                    return a.bcnt > b.bcnt;\n                });\n\n                uniq.swap(chosen);\n            }\n\n            if (uniq.empty()) return {};\n            layers[k+1].swap(uniq);\n        }\n\n        if (layers[M-1].empty()) return {};\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)layers[M-1].size(); i++) {\n            if (layers[M-1][i].cost < layers[M-1][bestIdx].cost) bestIdx = i;\n        }\n\n        struct Dec { uint8_t op, d1, d2; };\n        vector<Dec> dec(max(0, M - 1));\n\n        int idx = bestIdx;\n        for (int k = M - 2; k >= 0; k--) {\n            const Node& nd = layers[k+1][idx];\n            dec[k] = Dec{nd.op, nd.d1, nd.d2};\n            idx = nd.parent;\n            if (idx < 0 && k > 0) return {};\n        }\n        if (M >= 2 && idx < 0) return {};\n\n        // Reconstruct concrete actions\n        array<uint32_t,MAXN> row{}, col{};\n        row.fill(0u);\n        col.fill(0u);\n\n        int cur = pid[0];\n        vector<Action> ans;\n        ans.reserve(layers[M-1][bestIdx].cost + 16);\n\n        for (int k = 0; k < M - 1; k++) {\n            int s = pid[k], g = pid[k+1];\n            if (cur != s) return {};\n\n            auto [op, d1, d2] = dec[k];\n\n            if (op == 1) { // A\n                int t = to[cur][d1];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d1]});\n                toggleCell(row, col, t);\n\n            } else if (op == 2) { // M + A\n                int ncell = to[cur][d1];\n                if (ncell == -1 || isBlocked(row, ncell)) return {};\n                ans.push_back({'M', DCH[d1]});\n                cur = ncell;\n\n                int t = to[cur][d2];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t);\n\n            } else if (op == 3) { // S + A\n                int ncell = slideDest(row, col, cur, d1);\n                if (ncell == cur) return {};\n                ans.push_back({'S', DCH[d1]});\n                cur = ncell;\n\n                int t = to[cur][d2];\n                if (t == -1) return {};\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t);\n\n            } else if (op == 4) { // A + A\n                int t1 = to[cur][d1];\n                int t2 = to[cur][d2];\n                if (t1 == -1 || t2 == -1 || d1 == d2) return {};\n                ans.push_back({'A', DCH[d1]});\n                toggleCell(row, col, t1);\n                ans.push_back({'A', DCH[d2]});\n                toggleCell(row, col, t2);\n            }\n\n            vector<Action> path;\n            if (!bfsPath(row, col, cur, g, path)) return {};\n            ans.insert(ans.end(), path.begin(), path.end());\n            cur = g;\n        }\n\n        return ans;\n    }\n\n    void init() {\n        n2 = N * N;\n        LIMIT = 2 * N * M;\n\n        pid.resize(M);\n        for (int i = 0; i < M; i++) pid[i] = pts[i].r * N + pts[i].c;\n\n        cellR.resize(n2);\n        cellC.resize(n2);\n        to.assign(n2, array<int,4>{-1,-1,-1,-1});\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                cellR[id] = r;\n                cellC[id] = c;\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + DR[d], nc = c + DC[d];\n                    if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                        to[id][d] = nr * N + nc;\n                    }\n                }\n            }\n        }\n\n        for (int i = 0; i < MAXN; i++) {\n            lowMask[i] = (i == 0 ? 0u : ((1u << i) - 1u));\n            highMask[i] = ~((1u << (i + 1)) - 1u);\n        }\n\n        targetIdxAtCell.assign(n2, -1);\n        for (int i = 0; i < M; i++) {\n            targetIdxAtCell[pid[i]] = i;\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        pts.resize(M);\n        for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n        init();\n\n        vector<Action> best = fallbackNoBlock();\n        if (best.empty() || (int)best.size() > LIMIT || !validate(best)) {\n            best = fallbackManhattan();\n        }\n\n        auto start = Clock::now();\n        auto globalDL = start + chrono::milliseconds(1950);\n\n        Config c1;\n        c1.allowFutureToggle = false;\n        c1.enableDoubleAlter = false;\n        c1.wEarly = 190; c1.wMid = 150; c1.wLate = 115;\n        c1.preMul = 6; c1.elitePct = 50;\n        c1.wCost = 10; c1.wH1 = 4; c1.wH2 = 2;\n        c1.wFutureBlocked = 0; c1.wBlockBonus = 1;\n        c1.evalDistLimit = 55;\n\n        Config c2;\n        c2.allowFutureToggle = true;\n        c2.enableDoubleAlter = false;\n        c2.wEarly = 175; c2.wMid = 140; c2.wLate = 105;\n        c2.preMul = 6; c2.elitePct = 45;\n        c2.wCost = 10; c2.wH1 = 5; c2.wH2 = 2;\n        c2.wFutureBlocked = 4; c2.wBlockBonus = 1;\n        c2.evalDistLimit = 55;\n\n        Config c3;\n        c3.allowFutureToggle = true;\n        c3.enableDoubleAlter = true;\n        c3.wEarly = 145; c3.wMid = 115; c3.wLate = 90;\n        c3.preMul = 5; c3.elitePct = 40;\n        c3.wCost = 10; c3.wH1 = 5; c3.wH2 = 3;\n        c3.wFutureBlocked = 4; c3.wBlockBonus = 1;\n        c3.evalDistLimit = 55;\n\n        Config c4 = c3;\n        c4.wEarly = 130; c4.wMid = 105; c4.wLate = 82;\n        c4.elitePct = 35;\n        c4.wH1 = 6;\n        c4.wFutureBlocked = 5;\n        c4.evalDistLimit = 50;\n\n        vector<pair<Config, int>> plan = {\n            {c1, 1100},\n            {c2, 1650},\n            {c3, 1930},\n            {c4, 1950},\n        };\n\n        for (auto &p : plan) {\n            auto dl = min(globalDL, start + chrono::milliseconds(p.second));\n            if (Clock::now() >= dl) continue;\n\n            vector<Action> cand = runBeam((int)best.size(), p.first, dl);\n            if (cand.empty()) continue;\n            if ((int)cand.size() <= LIMIT && cand.size() < best.size() && validate(cand)) {\n                best.swap(cand);\n            }\n        }\n\n        if ((int)best.size() > LIMIT || !validate(best)) {\n            best = fallbackManhattan();\n        }\n\n        for (const auto& ac : best) {\n            cout << ac.a << ' ' << ac.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}"}}}